From 160d846643d9e9518a393fc9006ed4d092bde7a5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 27 Nov 2016 11:00:23 -0500 Subject: [PATCH] Sequence::Paste gives strong guarantee --- src/Sequence.cpp | 68 +++++++++++++++++++++++++----------------------- src/Sequence.h | 4 +-- src/WaveClip.cpp | 18 ++++++------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 91b5acc0a..bb0df2917 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -72,9 +72,7 @@ Sequence::Sequence(const Sequence &orig, const std::shared_ptr &proj , mMinSamples(orig.mMinSamples) , mMaxSamples(orig.mMaxSamples) { - bool bResult = Paste(0, &orig); - wxASSERT(bResult); // TO DO: Actually handle this. - (void)bResult; + Paste(0, &orig); } 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)) { @@ -460,8 +459,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) // PRL: Why bother with Internat when the above is just wxT? Internat::ToString(s.as_double(), 0).c_str(), Internat::ToString(mNumSamples.as_double(), 0).c_str()); - wxASSERT(false); - return false; + //THROW_INCONSISTENCY_EXCEPTION + ; } // 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? Internat::ToString(mNumSamples.as_double(), 0).c_str(), Internat::ToString(src->mNumSamples.as_double(), 0).c_str()); - wxASSERT(false); - return false; + //THROW_INCONSISTENCY_EXCEPTION + ; } if (src->mSampleFormat != mSampleFormat) @@ -481,8 +480,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) wxLogError( wxT("Sequence::Paste: Sample format to be pasted, %s, does not match destination format, %s."), GetSampleFormatStr(src->mSampleFormat), GetSampleFormatStr(src->mSampleFormat)); - wxASSERT(false); - return false; + //THROW_INCONSISTENCY_EXCEPTION + ; } const BlockArray &srcBlock = src->mBlock; @@ -491,7 +490,7 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) auto sampleSize = SAMPLE_SIZE(mSampleFormat); if (addedLen == 0 || srcNumBlocks == 0) - return true; + return; 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 // 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++) - 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 - ConsistencyCheck(wxT("Paste branch one")); - return true; + CommitChangesIfConsistent + (newBlock, samples, wxT("Paste branch one")); + return; } 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... 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; for (unsigned int i = b + 1; i < numBlocks; i++) @@ -548,8 +557,10 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) mNumSamples += addedLen; - ConsistencyCheck(wxT("Paste branch two")); - return true; + // This consistency check won't throw, it asserts. + // 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, @@ -637,12 +648,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src) for (i = b + 1; i < numBlocks; i++) newBlock.push_back(mBlock[i].Plus(addedLen)); - mBlock.swap(newBlock); - - mNumSamples += addedLen; - - ConsistencyCheck(wxT("Paste branch three")); - return true; + CommitChangesIfConsistent + (newBlock, mNumSamples + addedLen, wxT("Paste branch three")); } bool Sequence::SetSilence(sampleCount s0, sampleCount len) @@ -693,11 +700,9 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len) sTrack.mNumSamples = pos; - bool bResult = Paste(s0, &sTrack); - wxASSERT(bResult); + Paste(s0, &sTrack); - ConsistencyCheck(wxT("InsertSilence")); - return bResult; + return true; } bool Sequence::AppendAlias(const wxString &fullPath, @@ -737,13 +742,15 @@ bool Sequence::AppendCoded(const wxString &fName, sampleCount start, return true; } -bool Sequence::AppendBlock +void Sequence::AppendBlock (DirManager &mDirManager, BlockArray &mBlock, sampleCount &mNumSamples, const SeqBlock &b) { // Quick check to make sure that it doesn't overflow if (Overflows((mNumSamples.as_double()) + ((double)b.f->GetLength()))) - return false; + // THROW_INCONSISTENCY_EXCEPTION + return + ; SeqBlock newBlock( mDirManager.CopyBlockFile(b.f), // Bump ref count if not locked, else copy @@ -755,16 +762,11 @@ bool Sequence::AppendBlock return false; } - //Don't need to Ref because it was done by CopyBlockFile, above... - //mDirManager->Ref(newBlock.f); - mBlock.push_back(newBlock); mNumSamples += newBlock.f->GetLength(); // Don't do a consistency check here because this // 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. diff --git a/src/Sequence.h b/src/Sequence.h index 29b1da119..192dc4f68 100644 --- a/src/Sequence.h +++ b/src/Sequence.h @@ -104,7 +104,7 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{ size_t len, const sampleCount *where) const; std::unique_ptr Copy(sampleCount s0, sampleCount s1) const; - bool Paste(sampleCount s0, const Sequence *src); + void Paste(sampleCount s0, const Sequence *src); size_t GetIdealAppendLen() const; 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; - static bool AppendBlock + static void AppendBlock (DirManager &dirManager, BlockArray &blocks, sampleCount &numSamples, const SeqBlock &b); diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp index d4a6855ff..8d0f1f435 100644 --- a/src/WaveClip.cpp +++ b/src/WaveClip.cpp @@ -1611,18 +1611,16 @@ void WaveClip::Paste(double t0, const WaveClip* other) TimeToSamplesClip(t0, &s0); // Assume STRONG-GUARANTEE from Sequence::Paste - if (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()); + mSequence->Paste(s0, pastedClip->mSequence.get()); - for (auto &holder : newCutlines) - mCutLines.push_back(std::move(holder)); + // 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) + mCutLines.push_back(std::move(holder)); } void WaveClip::InsertSilence(double t, double len)