Add Slice method to CopyOnWriteBuffer and use it in FEC code.

This avoids unnecessary memcpy calls.

Bug: webrtc:10750
Change-Id: I73fe8f1c9659f2c5e59d7fb97b80349a3504a34a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/145320
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29315}
This commit is contained in:
Ilya Nikolaevskiy
2019-09-25 14:37:10 +02:00
committed by Commit Bot
parent 85d5c197a8
commit 741bab0f6c
5 changed files with 147 additions and 43 deletions

View File

@ -56,6 +56,8 @@ class CopyOnWriteBuffer {
: CopyOnWriteBuffer(size, capacity) {
if (buffer_) {
std::memcpy(buffer_->data(), data, size);
offset_ = 0;
size_ = size;
}
}
@ -88,8 +90,8 @@ class CopyOnWriteBuffer {
if (!buffer_) {
return nullptr;
}
CloneDataIfReferenced(buffer_->capacity());
return buffer_->data<T>();
UnshareAndEnsureCapacity(capacity());
return buffer_->data<T>() + offset_;
}
// Get const pointer to the data. This will not create a copy of the
@ -102,17 +104,17 @@ class CopyOnWriteBuffer {
if (!buffer_) {
return nullptr;
}
return buffer_->data<T>();
return buffer_->data<T>() + offset_;
}
size_t size() const {
RTC_DCHECK(IsConsistent());
return buffer_ ? buffer_->size() : 0;
return size_;
}
size_t capacity() const {
RTC_DCHECK(IsConsistent());
return buffer_ ? buffer_->capacity() : 0;
return buffer_ ? buffer_->capacity() - offset_ : 0;
}
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
@ -120,6 +122,8 @@ class CopyOnWriteBuffer {
RTC_DCHECK(buf.IsConsistent());
if (&buf != this) {
buffer_ = buf.buffer_;
offset_ = buf.offset_;
size_ = buf.size_;
}
return *this;
}
@ -128,6 +132,10 @@ class CopyOnWriteBuffer {
RTC_DCHECK(IsConsistent());
RTC_DCHECK(buf.IsConsistent());
buffer_ = std::move(buf.buffer_);
offset_ = buf.offset_;
size_ = buf.size_;
buf.offset_ = 0;
buf.size_ = 0;
return *this;
}
@ -157,10 +165,13 @@ class CopyOnWriteBuffer {
if (!buffer_) {
buffer_ = size > 0 ? new RefCountedObject<Buffer>(data, size) : nullptr;
} else if (!buffer_->HasOneRef()) {
buffer_ = new RefCountedObject<Buffer>(data, size, buffer_->capacity());
buffer_ = new RefCountedObject<Buffer>(data, size, capacity());
} else {
buffer_->SetData(data, size);
}
offset_ = 0;
size_ = size;
RTC_DCHECK(IsConsistent());
}
@ -177,6 +188,8 @@ class CopyOnWriteBuffer {
RTC_DCHECK(buf.IsConsistent());
if (&buf != this) {
buffer_ = buf.buffer_;
offset_ = buf.offset_;
size_ = buf.size_;
}
}
@ -188,13 +201,19 @@ class CopyOnWriteBuffer {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
buffer_ = new RefCountedObject<Buffer>(data, size);
offset_ = 0;
size_ = size;
RTC_DCHECK(IsConsistent());
return;
}
CloneDataIfReferenced(
std::max(buffer_->capacity(), buffer_->size() + size));
UnshareAndEnsureCapacity(std::max(capacity(), size_ + size));
buffer_->SetSize(offset_ +
size_); // Remove data to the right of the slice.
buffer_->AppendData(data, size);
size_ += size;
RTC_DCHECK(IsConsistent());
}
@ -228,18 +247,41 @@ class CopyOnWriteBuffer {
// Swaps two buffers.
friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
std::swap(a.buffer_, b.buffer_);
std::swap(a.offset_, b.offset_);
std::swap(a.size_, b.size_);
}
CopyOnWriteBuffer Slice(size_t offset, size_t length) const {
CopyOnWriteBuffer slice(*this);
RTC_DCHECK_LE(offset, size_);
RTC_DCHECK_LE(length + offset, size_);
slice.offset_ += offset;
slice.size_ = length;
return slice;
}
private:
// Create a copy of the underlying data if it is referenced from other Buffer
// objects.
void CloneDataIfReferenced(size_t new_capacity);
// objects or there is not enough capacity.
void UnshareAndEnsureCapacity(size_t new_capacity);
// Pre- and postcondition of all methods.
bool IsConsistent() const { return (!buffer_ || buffer_->capacity() > 0); }
bool IsConsistent() const {
if (buffer_) {
return buffer_->capacity() > 0 && offset_ <= buffer_->size() &&
offset_ + size_ <= buffer_->size();
} else {
return size_ == 0 && offset_ == 0;
}
}
// buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
scoped_refptr<RefCountedObject<Buffer>> buffer_;
// This buffer may represent a slice of a original data.
size_t offset_; // Offset of a current slice in the original data in buffer_.
// Should be 0 if the buffer_ is empty.
size_t size_; // Size of a current slice in the original data in buffer_.
// Should be 0 if the buffer_ is empty.
};
} // namespace rtc