Ejemplo n.º 1
0
nsresult
SourceBuffer::Compact()
{
  mMutex.AssertCurrentThreadOwns();

  MOZ_ASSERT(mConsumerCount == 0, "Should have no consumers here");
  MOZ_ASSERT(mWaitingConsumers.Length() == 0, "Shouldn't have waiters");
  MOZ_ASSERT(mStatus, "Should be complete here");

  // Compact our waiting consumers list, since we're complete and no future
  // consumer will ever have to wait.
  mWaitingConsumers.Compact();

  // If we have no chunks, then there's nothing to compact.
  if (mChunks.Length() < 1) {
    return NS_OK;
  }

  // If we have one chunk, then we can compact if it has excess capacity.
  if (mChunks.Length() == 1 && mChunks[0].Length() == mChunks[0].Capacity()) {
    return NS_OK;
  }

  // We can compact our buffer. Determine the total length.
  size_t length = 0;
  for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
    length += mChunks[i].Length();
  }

  Maybe<Chunk> newChunk = CreateChunk(length, /* aRoundUp = */ false);
  if (MOZ_UNLIKELY(!newChunk || newChunk->AllocationFailed())) {
    NS_WARNING("Failed to allocate chunk for SourceBuffer compacting - OOM?");
    return NS_OK;
  }

  // Copy our old chunks into the new chunk.
  for (uint32_t i = 0 ; i < mChunks.Length() ; ++i) {
    size_t offset = newChunk->Length();
    MOZ_ASSERT(offset < newChunk->Capacity());
    MOZ_ASSERT(offset + mChunks[i].Length() <= newChunk->Capacity());

    memcpy(newChunk->Data() + offset, mChunks[i].Data(), mChunks[i].Length());
    newChunk->AddLength(mChunks[i].Length());
  }

  MOZ_ASSERT(newChunk->Length() == newChunk->Capacity(),
             "Compacted chunk has slack space");

  // Replace the old chunks with the new, compact chunk.
  mChunks.Clear();
  if (MOZ_UNLIKELY(NS_FAILED(AppendChunk(Move(newChunk))))) {
    return HandleError(NS_ERROR_OUT_OF_MEMORY);
  }
  mChunks.Compact();

  return NS_OK;
}