Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Side by Side Diff: webrtc/base/copyonwritebuffer.h

Issue 1697743003: Add CopyOnWriteBuffer class (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added CopyOnWriteBuffer class Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef WEBRTC_BASE_COPYONWRITEBUFFER_H_
12 #define WEBRTC_BASE_COPYONWRITEBUFFER_H_
13
14 #include <algorithm> // std::swap (pre-C++11)
15 #include <utility> // std::swap (C++11 and later)
kwiberg-webrtc 2016/02/19 12:36:20 We're guaranteed to be C++11 or later nowadays.
joachim 2016/02/19 20:37:42 Actually still need both. "algorithm" provides "st
kwiberg-webrtc 2016/02/20 06:43:32 Acknowledged.
16
17 #include "webrtc/base/buffer.h"
18 #include "webrtc/base/refcount.h"
19 #include "webrtc/base/scoped_ref_ptr.h"
20
21 namespace rtc {
22
23 class CopyOnWriteBuffer {
24 public:
25 // An empty buffer.
26 CopyOnWriteBuffer();
27 // Copy size and contents of an existing buffer.
28 CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
29 // Move contents from an existing buffer.
30 CopyOnWriteBuffer(CopyOnWriteBuffer&& buf);
31
32 // Construct a buffer with the specified number of uninitialized bytes.
33 explicit CopyOnWriteBuffer(size_t size);
34 CopyOnWriteBuffer(size_t size, size_t capacity);
35
36 // Construct a buffer and copy the specified number of bytes into it. The
37 // source array may be (const) uint8_t*, int8_t*, or char*.
38 template <typename T, typename internal::ByteType<T>::t = 0>
39 CopyOnWriteBuffer(const T* data, size_t size)
40 : CopyOnWriteBuffer(data, size, size) {}
41 template <typename T, typename internal::ByteType<T>::t = 0>
42 CopyOnWriteBuffer(const T* data, size_t size, size_t capacity)
43 : CopyOnWriteBuffer(size, capacity) {
44 std::memcpy(buffer_->data(), data, size);
45 }
46
47 // Construct a buffer from the contents of an array.
48 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
49 CopyOnWriteBuffer(const T(&array)[N]) // NOLINT: runtime/explicit
50 : CopyOnWriteBuffer(array, N) {}
51
52 ~CopyOnWriteBuffer();
53
54 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
55 // but you may also use .data<int8_t>() and .data<char>().
56 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
57 const T* data() const {
58 if (!buffer_) {
59 return nullptr;
60 }
61 return reinterpret_cast<T*>(buffer_->data());
kwiberg-webrtc 2016/02/19 12:36:20 I think you can write return buffer_->data<T>()
joachim 2016/02/19 20:37:42 Done.
62 }
63
64 // Get writable pointer to the data. This will create a copy of the underlying
65 // data if it is shared with other buffers.
66 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
67 T* data() {
68 if (!buffer_) {
69 return nullptr;
70 }
71 CloneDataIfReferenced(buffer_->capacity());
72 return reinterpret_cast<T*>(buffer_->data());
kwiberg-webrtc 2016/02/19 12:36:20 data<T>()
joachim 2016/02/19 20:37:42 Done.
73 }
74
75 size_t size() const {
76 return buffer_ ? buffer_->size() : 0;
77 }
78
79 size_t capacity() const {
80 return buffer_ ? buffer_->capacity() : 0;
81 }
82
83 CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
84 if (&buf != this) {
85 buffer_ = buf.buffer_;
86 }
87 return *this;
88 }
89
90 CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
91 buffer_ = std::move(buf.buffer_);
kwiberg-webrtc 2016/02/19 12:36:20 IIRC, we concluded earlier that scoped_refptr does
joachim 2016/02/19 20:37:42 Done + bonus points ;-)
92 return *this;
93 }
94
95 bool operator==(const CopyOnWriteBuffer& buf) const {
96 // Must either use the same buffer internally or have the same contents.
97 return buffer_.get() == buf.buffer_.get() ||
98 (buffer_.get() && buf.buffer_.get() &&
99 *buffer_.get() == *buf.buffer_.get());
100 }
101
102 bool operator!=(const CopyOnWriteBuffer& buf) const {
103 return !(*this == buf);
104 }
105
106 // Replace the contents of the buffer. Accepts the same types as the
107 // constructors.
108 template <typename T, typename internal::ByteType<T>::t = 0>
109 void SetData(const T* data, size_t size) {
110 if (!buffer_ || !buffer_->HasOneRef()) {
111 buffer_ = new RefCountedObject<Buffer>(data, size, size);
112 } else {
113 buffer_->SetData(data, size);
114 }
115 }
116
117 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
118 void SetData(const T(&array)[N]) {
119 SetData(array, N);
120 }
121
122 void SetData(const CopyOnWriteBuffer& buf) {
123 if (&buf != this) {
124 buffer_ = buf.buffer_;
125 }
126 }
127
128 // Append data to the buffer. Accepts the same types as the constructors.
129 template <typename T, typename internal::ByteType<T>::t = 0>
130 void AppendData(const T* data, size_t size) {
131 if (!buffer_) {
132 buffer_ = new RefCountedObject<Buffer>(data, size);
133 return;
134 }
135
136 CloneDataIfReferenced(std::max(buffer_->capacity(),
137 buffer_->size() + size));
138 buffer_->AppendData(data, size);
139 }
140
141 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
142 void AppendData(const T(&array)[N]) {
143 AppendData(array, N);
144 }
145
146 void AppendData(const CopyOnWriteBuffer& buf) {
147 AppendData(buf.data(), buf.size());
148 }
149
150 // Sets the size of the buffer. If the new size is smaller than the old, the
151 // buffer contents will be kept but truncated; if the new size is greater,
152 // the existing contents will be kept and the new space will be
153 // uninitialized.
154 void SetSize(size_t size) {
155 if (!buffer_) {
kwiberg-webrtc 2016/02/19 12:36:20 !buffer_ && size > 0 Otherwise, you violate the "
joachim 2016/02/19 20:37:42 Done.
156 buffer_ = new RefCountedObject<Buffer>(size);
157 return;
158 }
159
160 CloneDataIfReferenced(std::max(buffer_->capacity(), size));
161 buffer_->SetSize(size);
162 }
163
164 // Ensure that the buffer size can be increased to at least capacity without
165 // further reallocation. (Of course, this operation might need to reallocate
166 // the buffer.)
167 void EnsureCapacity(size_t capacity) {
168 if (!buffer_) {
kwiberg-webrtc 2016/02/19 12:36:20 !buffer_ && capacity > 0 for the same reason as a
joachim 2016/02/19 20:37:42 Done.
169 buffer_ = new RefCountedObject<Buffer>(0, capacity);
170 return;
171 } else if (capacity <= buffer_->capacity()) {
172 return;
173 }
174
175 CloneDataIfReferenced(std::max(buffer_->capacity(), capacity));
176 buffer_->EnsureCapacity(capacity);
177 }
178
179 // Resets the buffer to zero size and capacity.
180 void Clear() {
181 if (!buffer_ || !buffer_->HasOneRef()) {
182 buffer_ = nullptr;
183 } else {
184 buffer_->Clear();
185 }
186 }
187
188 // Swaps two buffers.
189 friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
190 std::swap(a.buffer_, b.buffer_);
191 }
192
193 private:
194 // Create a copy of the underlying data if it is referenced from other Buffer
195 // objects.
196 void CloneDataIfReferenced(size_t new_capacity) {
197 if (buffer_->HasOneRef()) {
198 return;
199 }
200
201 buffer_ = new RefCountedObject<Buffer>(buffer_->data(), buffer_->size(),
202 new_capacity);
203 }
204
205 scoped_refptr< RefCountedObject<Buffer> > buffer_;
kwiberg-webrtc 2016/02/19 12:36:20 All those extra spaces aren't necessary, because C
joachim 2016/02/19 20:37:42 Done.
206 };
207
208 } // namespace rtc
209
210 #endif // WEBRTC_BASE_COPYONWRITEBUFFER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698