! @excsafety{Strong} */
| 488 | |
| 489 | /*! @excsafety{Strong} */ |
| 490 | void Sequence::Paste(sampleCount s, const Sequence *src) |
| 491 | { |
| 492 | if ((s < 0) || (s > mNumSamples)) |
| 493 | { |
| 494 | wxLogError( |
| 495 | wxT("Sequence::Paste: sampleCount s %s is < 0 or > mNumSamples %s)."), |
| 496 | // PRL: Why bother with Internat when the above is just wxT? |
| 497 | Internat::ToString(s.as_double(), 0), |
| 498 | Internat::ToString(mNumSamples.as_double(), 0)); |
| 499 | THROW_INCONSISTENCY_EXCEPTION; |
| 500 | } |
| 501 | |
| 502 | // Quick check to make sure that it doesn't overflow |
| 503 | if (Overflows((mNumSamples.as_double()) + (src->mNumSamples.as_double()))) |
| 504 | { |
| 505 | wxLogError( |
| 506 | wxT("Sequence::Paste: mNumSamples %s + src->mNumSamples %s would overflow."), |
| 507 | // PRL: Why bother with Internat when the above is just wxT? |
| 508 | Internat::ToString(mNumSamples.as_double(), 0), |
| 509 | Internat::ToString(src->mNumSamples.as_double(), 0)); |
| 510 | THROW_INCONSISTENCY_EXCEPTION; |
| 511 | } |
| 512 | |
| 513 | const auto format = mSampleFormats.Stored(); |
| 514 | if (src->mSampleFormats.Stored() != format) |
| 515 | { |
| 516 | wxLogError( |
| 517 | wxT("Sequence::Paste: Sample format to be pasted, %s, does not match destination format, %s."), |
| 518 | GetSampleFormatStr(src->mSampleFormats.Stored()).Debug(), |
| 519 | GetSampleFormatStr(format).Debug()); |
| 520 | THROW_INCONSISTENCY_EXCEPTION; |
| 521 | } |
| 522 | |
| 523 | const BlockArray &srcBlock = src->mBlock; |
| 524 | auto addedLen = src->mNumSamples; |
| 525 | const size_t srcNumBlocks = src->mBlockCount.load(std::memory_order_relaxed); |
| 526 | auto sampleSize = SAMPLE_SIZE(format); |
| 527 | |
| 528 | if (addedLen == 0 || srcNumBlocks == 0) |
| 529 | return; |
| 530 | |
| 531 | const size_t numBlocks = mBlockCount.load(std::memory_order_relaxed); |
| 532 | |
| 533 | // Decide whether to share sample blocks or make new copies, when whole block |
| 534 | // contents are used -- must copy if factories are different: |
| 535 | auto pUseFactory = |
| 536 | (src->mpFactory == mpFactory) ? nullptr : mpFactory.get(); |
| 537 | |
| 538 | if (numBlocks == 0 || |
| 539 | (s == mNumSamples && mBlock.back().sb->GetSampleCount() >= mMinSamples)) { |
| 540 | // Special case: this track is currently empty, or it's safe to append |
| 541 | // onto the end because the current last block is longer than the |
| 542 | // minimum size |
| 543 | |
| 544 | // Build and swap a copy so there is a strong exception safety guarantee |
| 545 | BlockArray newBlock{ mBlock }; |
| 546 | sampleCount samples = mNumSamples; |
| 547 | for (unsigned int i = 0; i < srcNumBlocks; i++) |
nothing calls this directly
no test coverage detected