mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-26 07:13:49 +01:00
Sequence::Paste gives strong guarantee
This commit is contained in:
@@ -72,9 +72,7 @@ Sequence::Sequence(const Sequence &orig, const std::shared_ptr<DirManager> &proj
|
|||||||
, mMinSamples(orig.mMinSamples)
|
, mMinSamples(orig.mMinSamples)
|
||||||
, mMaxSamples(orig.mMaxSamples)
|
, mMaxSamples(orig.mMaxSamples)
|
||||||
{
|
{
|
||||||
bool bResult = Paste(0, &orig);
|
Paste(0, &orig);
|
||||||
wxASSERT(bResult); // TO DO: Actually handle this.
|
|
||||||
(void)bResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence::~Sequence()
|
Sequence::~Sequence()
|
||||||
@@ -451,7 +449,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::Paste(sampleCount s, const Sequence *src)
|
void Sequence::Paste(sampleCount s, const Sequence *src)
|
||||||
|
// STRONG-GUARANTEE
|
||||||
{
|
{
|
||||||
if ((s < 0) || (s > mNumSamples))
|
if ((s < 0) || (s > mNumSamples))
|
||||||
{
|
{
|
||||||
@@ -460,8 +459,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
// PRL: Why bother with Internat when the above is just wxT?
|
// PRL: Why bother with Internat when the above is just wxT?
|
||||||
Internat::ToString(s.as_double(), 0).c_str(),
|
Internat::ToString(s.as_double(), 0).c_str(),
|
||||||
Internat::ToString(mNumSamples.as_double(), 0).c_str());
|
Internat::ToString(mNumSamples.as_double(), 0).c_str());
|
||||||
wxASSERT(false);
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
return false;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick check to make sure that it doesn't overflow
|
// Quick check to make sure that it doesn't overflow
|
||||||
@@ -472,8 +471,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
// PRL: Why bother with Internat when the above is just wxT?
|
// PRL: Why bother with Internat when the above is just wxT?
|
||||||
Internat::ToString(mNumSamples.as_double(), 0).c_str(),
|
Internat::ToString(mNumSamples.as_double(), 0).c_str(),
|
||||||
Internat::ToString(src->mNumSamples.as_double(), 0).c_str());
|
Internat::ToString(src->mNumSamples.as_double(), 0).c_str());
|
||||||
wxASSERT(false);
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
return false;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->mSampleFormat != mSampleFormat)
|
if (src->mSampleFormat != mSampleFormat)
|
||||||
@@ -481,8 +480,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
wxLogError(
|
wxLogError(
|
||||||
wxT("Sequence::Paste: Sample format to be pasted, %s, does not match destination format, %s."),
|
wxT("Sequence::Paste: Sample format to be pasted, %s, does not match destination format, %s."),
|
||||||
GetSampleFormatStr(src->mSampleFormat), GetSampleFormatStr(src->mSampleFormat));
|
GetSampleFormatStr(src->mSampleFormat), GetSampleFormatStr(src->mSampleFormat));
|
||||||
wxASSERT(false);
|
//THROW_INCONSISTENCY_EXCEPTION
|
||||||
return false;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlockArray &srcBlock = src->mBlock;
|
const BlockArray &srcBlock = src->mBlock;
|
||||||
@@ -491,7 +490,7 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
auto sampleSize = SAMPLE_SIZE(mSampleFormat);
|
auto sampleSize = SAMPLE_SIZE(mSampleFormat);
|
||||||
|
|
||||||
if (addedLen == 0 || srcNumBlocks == 0)
|
if (addedLen == 0 || srcNumBlocks == 0)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
const size_t numBlocks = mBlock.size();
|
const size_t numBlocks = mBlock.size();
|
||||||
|
|
||||||
@@ -501,12 +500,18 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
// onto the end because the current last block is longer than the
|
// onto the end because the current last block is longer than the
|
||||||
// minimum size
|
// minimum size
|
||||||
|
|
||||||
|
// Build and swap a copy so there is a strong exception safety guarantee
|
||||||
|
BlockArray newBlock{ mBlock };
|
||||||
|
sampleCount samples = mNumSamples;
|
||||||
for (unsigned int i = 0; i < srcNumBlocks; i++)
|
for (unsigned int i = 0; i < srcNumBlocks; i++)
|
||||||
AppendBlock(*mDirManager, mBlock, mNumSamples, srcBlock[i]);
|
// AppendBlock may throw for limited disk space, if pasting from
|
||||||
|
// one project into another.
|
||||||
|
AppendBlock(*mDirManager, newBlock, samples, srcBlock[i]);
|
||||||
// Increase ref count or duplicate file
|
// Increase ref count or duplicate file
|
||||||
|
|
||||||
ConsistencyCheck(wxT("Paste branch one"));
|
CommitChangesIfConsistent
|
||||||
return true;
|
(newBlock, samples, wxT("Paste branch one"));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int b = (s == mNumSamples) ? mBlock.size() - 1 : FindBlock(s);
|
const int b = (s == mNumSamples) ? mBlock.size() - 1 : FindBlock(s);
|
||||||
@@ -541,6 +546,10 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
// largerBlockLen is not more than mMaxSamples...
|
// largerBlockLen is not more than mMaxSamples...
|
||||||
buffer.ptr(), largerBlockLen.as_size_t(), mSampleFormat);
|
buffer.ptr(), largerBlockLen.as_size_t(), mSampleFormat);
|
||||||
|
|
||||||
|
// Don't make a duplicate array. We can still give STRONG-GUARANTEE
|
||||||
|
// if we modify only one block in place.
|
||||||
|
|
||||||
|
// use NOFAIL-GUARANTEE in remaining steps
|
||||||
block.f = file;
|
block.f = file;
|
||||||
|
|
||||||
for (unsigned int i = b + 1; i < numBlocks; i++)
|
for (unsigned int i = b + 1; i < numBlocks; i++)
|
||||||
@@ -548,8 +557,10 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
|
|
||||||
mNumSamples += addedLen;
|
mNumSamples += addedLen;
|
||||||
|
|
||||||
ConsistencyCheck(wxT("Paste branch two"));
|
// This consistency check won't throw, it asserts.
|
||||||
return true;
|
// Proof that we kept consistency is not hard.
|
||||||
|
ConsistencyCheck(wxT("Paste branch two"), false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case three: if we are inserting four or fewer blocks,
|
// Case three: if we are inserting four or fewer blocks,
|
||||||
@@ -637,12 +648,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
for (i = b + 1; i < numBlocks; i++)
|
for (i = b + 1; i < numBlocks; i++)
|
||||||
newBlock.push_back(mBlock[i].Plus(addedLen));
|
newBlock.push_back(mBlock[i].Plus(addedLen));
|
||||||
|
|
||||||
mBlock.swap(newBlock);
|
CommitChangesIfConsistent
|
||||||
|
(newBlock, mNumSamples + addedLen, wxT("Paste branch three"));
|
||||||
mNumSamples += addedLen;
|
|
||||||
|
|
||||||
ConsistencyCheck(wxT("Paste branch three"));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::SetSilence(sampleCount s0, sampleCount len)
|
bool Sequence::SetSilence(sampleCount s0, sampleCount len)
|
||||||
@@ -693,11 +700,9 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len)
|
|||||||
|
|
||||||
sTrack.mNumSamples = pos;
|
sTrack.mNumSamples = pos;
|
||||||
|
|
||||||
bool bResult = Paste(s0, &sTrack);
|
Paste(s0, &sTrack);
|
||||||
wxASSERT(bResult);
|
|
||||||
|
|
||||||
ConsistencyCheck(wxT("InsertSilence"));
|
return true;
|
||||||
return bResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::AppendAlias(const wxString &fullPath,
|
bool Sequence::AppendAlias(const wxString &fullPath,
|
||||||
@@ -737,13 +742,15 @@ bool Sequence::AppendCoded(const wxString &fName, sampleCount start,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::AppendBlock
|
void Sequence::AppendBlock
|
||||||
(DirManager &mDirManager,
|
(DirManager &mDirManager,
|
||||||
BlockArray &mBlock, sampleCount &mNumSamples, const SeqBlock &b)
|
BlockArray &mBlock, sampleCount &mNumSamples, const SeqBlock &b)
|
||||||
{
|
{
|
||||||
// Quick check to make sure that it doesn't overflow
|
// Quick check to make sure that it doesn't overflow
|
||||||
if (Overflows((mNumSamples.as_double()) + ((double)b.f->GetLength())))
|
if (Overflows((mNumSamples.as_double()) + ((double)b.f->GetLength())))
|
||||||
return false;
|
// THROW_INCONSISTENCY_EXCEPTION
|
||||||
|
return
|
||||||
|
;
|
||||||
|
|
||||||
SeqBlock newBlock(
|
SeqBlock newBlock(
|
||||||
mDirManager.CopyBlockFile(b.f), // Bump ref count if not locked, else copy
|
mDirManager.CopyBlockFile(b.f), // Bump ref count if not locked, else copy
|
||||||
@@ -755,16 +762,11 @@ bool Sequence::AppendBlock
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Don't need to Ref because it was done by CopyBlockFile, above...
|
|
||||||
//mDirManager->Ref(newBlock.f);
|
|
||||||
|
|
||||||
mBlock.push_back(newBlock);
|
mBlock.push_back(newBlock);
|
||||||
mNumSamples += newBlock.f->GetLength();
|
mNumSamples += newBlock.f->GetLength();
|
||||||
|
|
||||||
// Don't do a consistency check here because this
|
// Don't do a consistency check here because this
|
||||||
// function gets called in an inner loop.
|
// function gets called in an inner loop.
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc.
|
///gets an int with OD flags so that we can determine which ODTasks should be run on this track after save/open, etc.
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
|||||||
size_t len, const sampleCount *where) const;
|
size_t len, const sampleCount *where) const;
|
||||||
|
|
||||||
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
std::unique_ptr<Sequence> Copy(sampleCount s0, sampleCount s1) const;
|
||||||
bool Paste(sampleCount s0, const Sequence *src);
|
void Paste(sampleCount s0, const Sequence *src);
|
||||||
|
|
||||||
size_t GetIdealAppendLen() const;
|
size_t GetIdealAppendLen() const;
|
||||||
bool Append(samplePtr buffer, sampleFormat format, size_t len,
|
bool Append(samplePtr buffer, sampleFormat format, size_t len,
|
||||||
@@ -245,7 +245,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
|||||||
|
|
||||||
int FindBlock(sampleCount pos) const;
|
int FindBlock(sampleCount pos) const;
|
||||||
|
|
||||||
static bool AppendBlock
|
static void AppendBlock
|
||||||
(DirManager &dirManager,
|
(DirManager &dirManager,
|
||||||
BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b);
|
BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b);
|
||||||
|
|
||||||
|
|||||||
@@ -1611,18 +1611,16 @@ void WaveClip::Paste(double t0, const WaveClip* other)
|
|||||||
TimeToSamplesClip(t0, &s0);
|
TimeToSamplesClip(t0, &s0);
|
||||||
|
|
||||||
// Assume STRONG-GUARANTEE from Sequence::Paste
|
// Assume STRONG-GUARANTEE from Sequence::Paste
|
||||||
if (mSequence->Paste(s0, pastedClip->mSequence.get()))
|
mSequence->Paste(s0, pastedClip->mSequence.get());
|
||||||
{
|
|
||||||
// Assume NOFAIL-GUARANTEE in the remaining
|
|
||||||
MarkChanged();
|
|
||||||
mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get());
|
|
||||||
mEnvelope->RemoveUnneededPoints();
|
|
||||||
OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime());
|
|
||||||
|
|
||||||
for (auto &holder : newCutlines)
|
// Assume NOFAIL-GUARANTEE in the remaining
|
||||||
mCutLines.push_back(std::move(holder));
|
MarkChanged();
|
||||||
|
mEnvelope->Paste(s0.as_double()/mRate + mOffset, pastedClip->mEnvelope.get());
|
||||||
|
mEnvelope->RemoveUnneededPoints();
|
||||||
|
OffsetCutLines(t0, pastedClip->GetEndTime() - pastedClip->GetStartTime());
|
||||||
|
|
||||||
}
|
for (auto &holder : newCutlines)
|
||||||
|
mCutLines.push_back(std::move(holder));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveClip::InsertSilence(double t, double len)
|
void WaveClip::InsertSilence(double t, double len)
|
||||||
|
|||||||
Reference in New Issue
Block a user