1
0
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:
Paul Licameli
2016-11-27 11:00:23 -05:00
parent 2ba6065961
commit 160d846643
3 changed files with 45 additions and 45 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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)