webrtc_m130/webrtc/base/copyonwritebuffer.h
kjellander 194e3bcc53 Revert of Use CopyOnWriteBuffer instead of Buffer to avoid unnecessary copies. (patchset #4 id:60001 of https://codereview.webrtc.org/1785713005/ )
Reason for revert:
I'm really sorry for having to revert this but it seems this hit an unexpected compile error downstream:

webrtc/media/sctp/sctpdataengine.cc: In function 'void cricket::VerboseLogPacket(const void*, size_t, int)':
webrtc/media/sctp/sctpdataengine.cc:172:37: error: invalid conversion from 'const void*' to 'void*' [-fpermissive]
              data, length, direction)) != NULL) {
                                     ^
In file included from webrtc/media/sctp/sctpdataengine.cc:20:0:
third_party/usrsctp/usrsctplib/usrsctp.h:964:1: error:   initializing argument 1 of 'char* usrsctp_dumppacket(void*, size_t, int)' [-fpermissive]
 usrsctp_dumppacket(void *, size_t, int);
 ^

I'm sure you can fix this easily and just re-land this CL, while I'm going to look into how to add this warning at the public bots (on Monday).

Original issue's description:
> Use CopyOnWriteBuffer instead of Buffer to avoid unnecessary copies.
>
> This CL removes copy and assign support from Buffer and changes various
> parameters from Buffer to CopyOnWriteBuffer so they can be passed along
> and copied without actually copying the underlying data.
>
> With this changed some parameters to be "const" and fixed an issue when
> creating a CopyOnWriteBuffer with empty data.
>
> BUG=webrtc:5155
>
> Committed: https://crrev.com/944c39006f1c52aee20919676002dac7a42b1c05
> Cr-Commit-Position: refs/heads/master@{#12058}

TBR=kwiberg@webrtc.org,tkchin@webrtc.org,tommi@webrtc.org,pthatcher@webrtc.org,jbauch@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:5155

Review URL: https://codereview.webrtc.org/1817753003

Cr-Commit-Position: refs/heads/master@{#12060}
2016-03-19 19:12:58 +00:00

257 lines
7.6 KiB
C++

/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_BASE_COPYONWRITEBUFFER_H_
#define WEBRTC_BASE_COPYONWRITEBUFFER_H_
#include <algorithm>
#include <utility>
#include "webrtc/base/buffer.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/refcount.h"
#include "webrtc/base/scoped_ref_ptr.h"
namespace rtc {
class CopyOnWriteBuffer {
public:
// An empty buffer.
CopyOnWriteBuffer();
// Copy size and contents of an existing buffer.
CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
// Move contents from an existing buffer.
CopyOnWriteBuffer(CopyOnWriteBuffer&& buf);
// Construct a buffer with the specified number of uninitialized bytes.
explicit CopyOnWriteBuffer(size_t size);
CopyOnWriteBuffer(size_t size, size_t capacity);
// Construct a buffer and copy the specified number of bytes into it. The
// source array may be (const) uint8_t*, int8_t*, or char*.
template <typename T, typename internal::ByteType<T>::t = 0>
CopyOnWriteBuffer(const T* data, size_t size)
: CopyOnWriteBuffer(data, size, size) {}
template <typename T, typename internal::ByteType<T>::t = 0>
CopyOnWriteBuffer(const T* data, size_t size, size_t capacity)
: CopyOnWriteBuffer(size, capacity) {
std::memcpy(buffer_->data(), data, size);
}
// Construct a buffer from the contents of an array.
template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
CopyOnWriteBuffer(const T(&array)[N]) // NOLINT: runtime/explicit
: CopyOnWriteBuffer(array, N) {}
~CopyOnWriteBuffer();
// Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
// but you may also use .data<int8_t>() and .data<char>().
template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
const T* data() const {
return cdata<T>();
}
// Get writable pointer to the data. This will create a copy of the underlying
// data if it is shared with other buffers.
template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
T* data() {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
return nullptr;
}
CloneDataIfReferenced(buffer_->capacity());
return buffer_->data<T>();
}
// Get const pointer to the data. This will not create a copy of the
// underlying data if it is shared with other buffers.
template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
T* cdata() const {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
return nullptr;
}
return buffer_->data<T>();
}
size_t size() const {
RTC_DCHECK(IsConsistent());
return buffer_ ? buffer_->size() : 0;
}
size_t capacity() const {
RTC_DCHECK(IsConsistent());
return buffer_ ? buffer_->capacity() : 0;
}
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
RTC_DCHECK(IsConsistent());
RTC_DCHECK(buf.IsConsistent());
if (&buf != this) {
buffer_ = buf.buffer_;
}
return *this;
}
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
RTC_DCHECK(IsConsistent());
RTC_DCHECK(buf.IsConsistent());
// TODO(jbauch): use std::move once scoped_refptr supports it (issue 5556)
buffer_.swap(buf.buffer_);
buf.buffer_ = nullptr;
return *this;
}
bool operator==(const CopyOnWriteBuffer& buf) const {
// Must either use the same buffer internally or have the same contents.
RTC_DCHECK(IsConsistent());
RTC_DCHECK(buf.IsConsistent());
return buffer_.get() == buf.buffer_.get() ||
(buffer_.get() && buf.buffer_.get() &&
*buffer_.get() == *buf.buffer_.get());
}
bool operator!=(const CopyOnWriteBuffer& buf) const {
return !(*this == buf);
}
// Replace the contents of the buffer. Accepts the same types as the
// constructors.
template <typename T, typename internal::ByteType<T>::t = 0>
void SetData(const T* data, size_t size) {
RTC_DCHECK(IsConsistent());
if (!buffer_ || !buffer_->HasOneRef()) {
buffer_ = new RefCountedObject<Buffer>(data, size, size);
} else {
buffer_->SetData(data, size);
}
RTC_DCHECK(IsConsistent());
}
template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
void SetData(const T(&array)[N]) {
SetData(array, N);
}
void SetData(const CopyOnWriteBuffer& buf) {
RTC_DCHECK(IsConsistent());
RTC_DCHECK(buf.IsConsistent());
if (&buf != this) {
buffer_ = buf.buffer_;
}
}
// Append data to the buffer. Accepts the same types as the constructors.
template <typename T, typename internal::ByteType<T>::t = 0>
void AppendData(const T* data, size_t size) {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
buffer_ = new RefCountedObject<Buffer>(data, size);
RTC_DCHECK(IsConsistent());
return;
}
CloneDataIfReferenced(std::max(buffer_->capacity(),
buffer_->size() + size));
buffer_->AppendData(data, size);
RTC_DCHECK(IsConsistent());
}
template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
void AppendData(const T(&array)[N]) {
AppendData(array, N);
}
void AppendData(const CopyOnWriteBuffer& buf) {
AppendData(buf.data(), buf.size());
}
// Sets the size of the buffer. If the new size is smaller than the old, the
// buffer contents will be kept but truncated; if the new size is greater,
// the existing contents will be kept and the new space will be
// uninitialized.
void SetSize(size_t size) {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
if (size > 0) {
buffer_ = new RefCountedObject<Buffer>(size);
}
RTC_DCHECK(IsConsistent());
return;
}
CloneDataIfReferenced(std::max(buffer_->capacity(), size));
buffer_->SetSize(size);
RTC_DCHECK(IsConsistent());
}
// Ensure that the buffer size can be increased to at least capacity without
// further reallocation. (Of course, this operation might need to reallocate
// the buffer.)
void EnsureCapacity(size_t capacity) {
RTC_DCHECK(IsConsistent());
if (!buffer_) {
if (capacity > 0) {
buffer_ = new RefCountedObject<Buffer>(0, capacity);
}
RTC_DCHECK(IsConsistent());
return;
} else if (capacity <= buffer_->capacity()) {
return;
}
CloneDataIfReferenced(std::max(buffer_->capacity(), capacity));
buffer_->EnsureCapacity(capacity);
RTC_DCHECK(IsConsistent());
}
// Resets the buffer to zero size and capacity.
void Clear() {
RTC_DCHECK(IsConsistent());
if (!buffer_ || !buffer_->HasOneRef()) {
buffer_ = nullptr;
} else {
buffer_->Clear();
}
RTC_DCHECK(IsConsistent());
}
// Swaps two buffers.
friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
std::swap(a.buffer_, b.buffer_);
}
private:
// Create a copy of the underlying data if it is referenced from other Buffer
// objects.
void CloneDataIfReferenced(size_t new_capacity) {
if (buffer_->HasOneRef()) {
return;
}
buffer_ = new RefCountedObject<Buffer>(buffer_->data(), buffer_->size(),
new_capacity);
RTC_DCHECK(IsConsistent());
}
// Pre- and postcondition of all methods.
bool IsConsistent() const {
return (!buffer_ || buffer_->capacity() > 0);
}
// buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
scoped_refptr<RefCountedObject<Buffer>> buffer_;
};
} // namespace rtc
#endif // WEBRTC_BASE_COPYONWRITEBUFFER_H_