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

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: More feedback from kwiberg 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
« no previous file with comments | « webrtc/base/base_tests.gyp ('k') | webrtc/base/copyonwritebuffer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>
15 #include <utility>
16
17 #include "webrtc/base/buffer.h"
18 #include "webrtc/base/checks.h"
19 #include "webrtc/base/refcount.h"
20 #include "webrtc/base/scoped_ref_ptr.h"
21
22 namespace rtc {
23
24 class CopyOnWriteBuffer {
25 public:
26 // An empty buffer.
27 CopyOnWriteBuffer();
28 // Copy size and contents of an existing buffer.
29 CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
30 // Move contents from an existing buffer.
31 CopyOnWriteBuffer(CopyOnWriteBuffer&& buf);
32
33 // Construct a buffer with the specified number of uninitialized bytes.
34 explicit CopyOnWriteBuffer(size_t size);
35 CopyOnWriteBuffer(size_t size, size_t capacity);
36
37 // Construct a buffer and copy the specified number of bytes into it. The
38 // source array may be (const) uint8_t*, int8_t*, or char*.
39 template <typename T, typename internal::ByteType<T>::t = 0>
40 CopyOnWriteBuffer(const T* data, size_t size)
41 : CopyOnWriteBuffer(data, size, size) {}
42 template <typename T, typename internal::ByteType<T>::t = 0>
43 CopyOnWriteBuffer(const T* data, size_t size, size_t capacity)
44 : CopyOnWriteBuffer(size, capacity) {
45 std::memcpy(buffer_->data(), data, size);
46 }
47
48 // Construct a buffer from the contents of an array.
49 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
50 CopyOnWriteBuffer(const T(&array)[N]) // NOLINT: runtime/explicit
51 : CopyOnWriteBuffer(array, N) {}
52
53 ~CopyOnWriteBuffer();
54
55 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
56 // but you may also use .data<int8_t>() and .data<char>().
57 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
58 const T* data() const {
59 return cdata<T>();
60 }
61
62 // Get writable pointer to the data. This will create a copy of the underlying
63 // data if it is shared with other buffers.
64 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
65 T* data() {
66 RTC_DCHECK(IsConsistent());
67 if (!buffer_) {
68 return nullptr;
69 }
70 CloneDataIfReferenced(buffer_->capacity());
71 return buffer_->data<T>();
72 }
73
74 // Get const pointer to the data. This will not create a copy of the
75 // underlying data if it is shared with other buffers.
76 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
77 T* cdata() const {
78 RTC_DCHECK(IsConsistent());
79 if (!buffer_) {
80 return nullptr;
81 }
82 return buffer_->data<T>();
83 }
84
85 size_t size() const {
86 RTC_DCHECK(IsConsistent());
87 return buffer_ ? buffer_->size() : 0;
88 }
89
90 size_t capacity() const {
91 RTC_DCHECK(IsConsistent());
92 return buffer_ ? buffer_->capacity() : 0;
93 }
94
95 CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
96 RTC_DCHECK(IsConsistent());
97 RTC_DCHECK(buf.IsConsistent());
98 if (&buf != this) {
99 buffer_ = buf.buffer_;
100 }
101 return *this;
102 }
103
104 CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
105 RTC_DCHECK(IsConsistent());
106 RTC_DCHECK(buf.IsConsistent());
107 // TODO(jbauch): use std::move once scoped_refptr supports it (issue 5556)
108 buffer_.swap(buf.buffer_);
109 buf.buffer_ = nullptr;
110 return *this;
111 }
112
113 bool operator==(const CopyOnWriteBuffer& buf) const {
114 // Must either use the same buffer internally or have the same contents.
115 RTC_DCHECK(IsConsistent());
116 RTC_DCHECK(buf.IsConsistent());
117 return buffer_.get() == buf.buffer_.get() ||
118 (buffer_.get() && buf.buffer_.get() &&
119 *buffer_.get() == *buf.buffer_.get());
120 }
121
122 bool operator!=(const CopyOnWriteBuffer& buf) const {
123 return !(*this == buf);
124 }
125
126 // Replace the contents of the buffer. Accepts the same types as the
127 // constructors.
128 template <typename T, typename internal::ByteType<T>::t = 0>
129 void SetData(const T* data, size_t size) {
130 RTC_DCHECK(IsConsistent());
131 if (!buffer_ || !buffer_->HasOneRef()) {
132 buffer_ = new RefCountedObject<Buffer>(data, size, size);
133 } else {
134 buffer_->SetData(data, size);
135 }
136 RTC_DCHECK(IsConsistent());
137 }
138
139 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
140 void SetData(const T(&array)[N]) {
141 SetData(array, N);
142 }
143
144 void SetData(const CopyOnWriteBuffer& buf) {
145 RTC_DCHECK(IsConsistent());
146 RTC_DCHECK(buf.IsConsistent());
147 if (&buf != this) {
148 buffer_ = buf.buffer_;
149 }
150 }
151
152 // Append data to the buffer. Accepts the same types as the constructors.
153 template <typename T, typename internal::ByteType<T>::t = 0>
154 void AppendData(const T* data, size_t size) {
155 RTC_DCHECK(IsConsistent());
156 if (!buffer_) {
157 buffer_ = new RefCountedObject<Buffer>(data, size);
158 RTC_DCHECK(IsConsistent());
159 return;
160 }
161
162 CloneDataIfReferenced(std::max(buffer_->capacity(),
163 buffer_->size() + size));
164 buffer_->AppendData(data, size);
165 RTC_DCHECK(IsConsistent());
166 }
167
168 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
169 void AppendData(const T(&array)[N]) {
170 AppendData(array, N);
171 }
172
173 void AppendData(const CopyOnWriteBuffer& buf) {
174 AppendData(buf.data(), buf.size());
175 }
176
177 // Sets the size of the buffer. If the new size is smaller than the old, the
178 // buffer contents will be kept but truncated; if the new size is greater,
179 // the existing contents will be kept and the new space will be
180 // uninitialized.
181 void SetSize(size_t size) {
182 RTC_DCHECK(IsConsistent());
183 if (!buffer_) {
184 if (size > 0) {
185 buffer_ = new RefCountedObject<Buffer>(size);
186 }
187 RTC_DCHECK(IsConsistent());
188 return;
189 }
190
191 CloneDataIfReferenced(std::max(buffer_->capacity(), size));
192 buffer_->SetSize(size);
193 RTC_DCHECK(IsConsistent());
194 }
195
196 // Ensure that the buffer size can be increased to at least capacity without
197 // further reallocation. (Of course, this operation might need to reallocate
198 // the buffer.)
199 void EnsureCapacity(size_t capacity) {
200 RTC_DCHECK(IsConsistent());
201 if (!buffer_) {
202 if (capacity > 0) {
203 buffer_ = new RefCountedObject<Buffer>(0, capacity);
204 }
205 RTC_DCHECK(IsConsistent());
206 return;
207 } else if (capacity <= buffer_->capacity()) {
208 return;
209 }
210
211 CloneDataIfReferenced(std::max(buffer_->capacity(), capacity));
212 buffer_->EnsureCapacity(capacity);
213 RTC_DCHECK(IsConsistent());
214 }
215
216 // Resets the buffer to zero size and capacity.
217 void Clear() {
218 RTC_DCHECK(IsConsistent());
219 if (!buffer_ || !buffer_->HasOneRef()) {
220 buffer_ = nullptr;
221 } else {
222 buffer_->Clear();
223 }
224 RTC_DCHECK(IsConsistent());
225 }
226
227 // Swaps two buffers.
228 friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
229 std::swap(a.buffer_, b.buffer_);
230 }
231
232 private:
233 // Create a copy of the underlying data if it is referenced from other Buffer
234 // objects.
235 void CloneDataIfReferenced(size_t new_capacity) {
236 if (buffer_->HasOneRef()) {
237 return;
238 }
239
240 buffer_ = new RefCountedObject<Buffer>(buffer_->data(), buffer_->size(),
241 new_capacity);
242 RTC_DCHECK(IsConsistent());
243 }
244
245 // Pre- and postcondition of all methods.
246 bool IsConsistent() const {
247 return (!buffer_ || buffer_->capacity() > 0);
248 }
249
250 // buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
251 scoped_refptr<RefCountedObject<Buffer>> buffer_;
252 };
253
254 } // namespace rtc
255
256 #endif // WEBRTC_BASE_COPYONWRITEBUFFER_H_
OLDNEW
« no previous file with comments | « webrtc/base/base_tests.gyp ('k') | webrtc/base/copyonwritebuffer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698