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

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

Issue 1929903002: Define rtc::BufferT, like rtc::Buffer but for any trivial type (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 7 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.gyp ('k') | webrtc/base/buffer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #ifndef WEBRTC_BASE_BUFFER_H_ 11 #ifndef WEBRTC_BASE_BUFFER_H_
12 #define WEBRTC_BASE_BUFFER_H_ 12 #define WEBRTC_BASE_BUFFER_H_
13 13
14 #include <cstring> 14 #include <cstring>
15 #include <memory> 15 #include <memory>
16 #include <type_traits>
16 #include <utility> 17 #include <utility>
17 18
18 #include "webrtc/base/array_view.h" 19 #include "webrtc/base/array_view.h"
19 #include "webrtc/base/checks.h" 20 #include "webrtc/base/checks.h"
20 #include "webrtc/base/constructormagic.h"
21 21
22 namespace rtc { 22 namespace rtc {
23 23
24 namespace internal { 24 namespace internal {
25 25
26 // (Internal; please don't use outside this file.) ByteType<T>::t is int if T 26 // (Internal; please don't use outside this file.) Determines if elements of
27 // is uint8_t, int8_t, or char; otherwise, it's a compilation error. Use like 27 // type U are compatible with a BufferT<T>. For most types, we just ignore CV
28 // this: 28 // qualifiers, but all byte-sized integers (notably char, int8_t, and uint8_t)
29 // 29 // are compatible with each other.
30 // template <typename T, typename ByteType<T>::t = 0> 30 template <typename T, typename U>
31 // void foo(T* x); 31 struct BufferCompat {
ossu 2016/04/28 13:36:53 So it is "buffer compatible" if both types are of
kwiberg-webrtc 2016/04/28 21:19:00 For historical reasons, callers use Buffer with mo
32 // 32 static constexpr bool value =
33 // to let foo<T> be defined only for byte-sized integers. 33 std::is_integral<T>::value && sizeof(T) == 1
ossu 2016/04/28 13:36:53 I find ternaries with other logic operators quite
kwiberg-webrtc 2016/04/28 21:19:01 Will do. As expected, ?: has a VERY low precedence
34 template <typename T> 34 ? std::is_integral<U>::value && sizeof(U) == 1
35 struct ByteType { 35 : std::is_same<T, typename std::remove_cv<U>::type>::value;
36 private:
37 static int F(uint8_t*);
38 static int F(int8_t*);
39 static int F(char*);
40
41 public:
42 using t = decltype(F(static_cast<T*>(nullptr)));
43 }; 36 };
44 37
45 } // namespace internal 38 } // namespace internal
46 39
47 // Basic buffer class, can be grown and shrunk dynamically. 40 // Basic buffer class, can be grown and shrunk dynamically.
48 // Unlike std::string/vector, does not initialize data when expanding capacity. 41 // Unlike std::string/vector, does not initialize data when expanding capacity.
ossu 2016/04/28 13:36:53 This isn't really part of this CL, but std::vector
kwiberg-webrtc 2016/04/28 21:19:01 That's right. Will fix.
49 class Buffer { 42 template <typename T>
43 class BufferT {
44 static_assert(std::is_pod<T>::value, "T must be a POD type");
45 static_assert(!std::is_const<T>::value, "T may not be const");
46 static_assert(!std::is_volatile<T>::value, "T may not be volatile");
ossu 2016/04/28 13:36:53 Why not? I mean, I don't see any reason to actuall
kwiberg-webrtc 2016/04/28 21:19:01 Actually, POD = trivial + standard layout, and we
47
50 public: 48 public:
51 Buffer(); // An empty buffer. 49 // An empty BufferT.
52 Buffer(Buffer&& buf); // Move contents from an existing buffer. 50 BufferT() : size_(0), capacity_(0), data_(nullptr) {
51 RTC_DCHECK(IsConsistent());
52 }
53 53
54 // Construct a buffer with the specified number of uninitialized bytes. 54 // Disable copy construction and copy assignment, since copying a buffer is
55 explicit Buffer(size_t size); 55 // expensive enough that we want to force the user to be explicit about it.
56 Buffer(size_t size, size_t capacity); 56 BufferT(const BufferT&) = delete;
57 BufferT& operator=(const BufferT&) = delete;
57 58
58 // Construct a buffer and copy the specified number of bytes into it. The 59 BufferT(BufferT&& buf)
59 // source array may be (const) uint8_t*, int8_t*, or char*. 60 : size_(buf.size()),
60 template <typename T, typename internal::ByteType<T>::t = 0> 61 capacity_(buf.capacity()),
61 Buffer(const T* data, size_t size) 62 data_(std::move(buf.data_)) {
62 : Buffer(data, size, size) {} 63 RTC_DCHECK(IsConsistent());
64 buf.OnMovedFrom();
65 }
63 66
64 template <typename T, typename internal::ByteType<T>::t = 0> 67 // Construct a buffer with the specified number of uninitialized elements.
65 Buffer(const T* data, size_t size, size_t capacity) 68 explicit BufferT(size_t size) : BufferT(size, size) {}
66 : Buffer(size, capacity) { 69
67 std::memcpy(data_.get(), data, size); 70 BufferT(size_t size, size_t capacity)
71 : size_(size),
72 capacity_(std::max(size, capacity)),
73 data_(new T[capacity_]) {
74 RTC_DCHECK(IsConsistent());
75 }
76
77 // Construct a buffer and copy the specified number of elements into it.
78 template <typename U,
79 typename std::enable_if<
80 internal::BufferCompat<T, U>::value>::type* = nullptr>
81 BufferT(const U* data, size_t size) : BufferT(data, size, size) {}
82
83 template <typename U,
84 typename std::enable_if<
85 internal::BufferCompat<T, U>::value>::type* = nullptr>
86 BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) {
87 static_assert(sizeof(T) == sizeof(U), "");
88 std::memcpy(data_.get(), data, size * sizeof(U));
68 } 89 }
69 90
70 // Construct a buffer from the contents of an array. 91 // Construct a buffer from the contents of an array.
71 template <typename T, size_t N, typename internal::ByteType<T>::t = 0> 92 template <typename U,
72 Buffer(const T(&array)[N]) 93 size_t N,
73 : Buffer(array, N) {} 94 typename std::enable_if<
95 internal::BufferCompat<T, U>::value>::type* = nullptr>
96 BufferT(U (&array)[N]) : BufferT(array, N) {}
74 97
75 ~Buffer(); 98 // Get a pointer to the data. Just .data() will give you a (const) T*, but if
76 99 // T is a byte-sized integer, you may also use .data<U>() for any other
77 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*, 100 // byte-sized integer U.
78 // but you may also use .data<int8_t>() and .data<char>(). 101 template <typename U = T,
79 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0> 102 typename std::enable_if<
80 const T* data() const { 103 internal::BufferCompat<T, U>::value>::type* = nullptr>
104 const U* data() const {
81 RTC_DCHECK(IsConsistent()); 105 RTC_DCHECK(IsConsistent());
82 return reinterpret_cast<T*>(data_.get()); 106 return reinterpret_cast<U*>(data_.get());
83 } 107 }
84 108
85 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0> 109 template <typename U = T,
86 T* data() { 110 typename std::enable_if<
111 internal::BufferCompat<T, U>::value>::type* = nullptr>
112 U* data() {
87 RTC_DCHECK(IsConsistent()); 113 RTC_DCHECK(IsConsistent());
88 return reinterpret_cast<T*>(data_.get()); 114 return reinterpret_cast<U*>(data_.get());
89 } 115 }
90 116
91 size_t size() const { 117 size_t size() const {
92 RTC_DCHECK(IsConsistent()); 118 RTC_DCHECK(IsConsistent());
93 return size_; 119 return size_;
94 } 120 }
95 121
96 size_t capacity() const { 122 size_t capacity() const {
97 RTC_DCHECK(IsConsistent()); 123 RTC_DCHECK(IsConsistent());
98 return capacity_; 124 return capacity_;
99 } 125 }
100 126
101 Buffer& operator=(Buffer&& buf) { 127 BufferT& operator=(BufferT&& buf) {
102 RTC_DCHECK(IsConsistent()); 128 RTC_DCHECK(IsConsistent());
103 RTC_DCHECK(buf.IsConsistent()); 129 RTC_DCHECK(buf.IsConsistent());
104 size_ = buf.size_; 130 size_ = buf.size_;
105 capacity_ = buf.capacity_; 131 capacity_ = buf.capacity_;
106 data_ = std::move(buf.data_); 132 data_ = std::move(buf.data_);
107 buf.OnMovedFrom(); 133 buf.OnMovedFrom();
108 return *this; 134 return *this;
109 } 135 }
110 136
111 bool operator==(const Buffer& buf) const { 137 bool operator==(const BufferT& buf) const {
138 static_assert(std::is_integral<T>::value, "T must be an integral type");
112 RTC_DCHECK(IsConsistent()); 139 RTC_DCHECK(IsConsistent());
113 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0; 140 return size_ == buf.size() &&
141 std::memcmp(data_.get(), buf.data(), size_ * sizeof(T)) == 0;
114 } 142 }
115 143
116 bool operator!=(const Buffer& buf) const { return !(*this == buf); } 144 bool operator!=(const BufferT& buf) const { return !(*this == buf); }
117 145
118 uint8_t& operator[](size_t index) { 146 T& operator[](size_t index) {
119 RTC_DCHECK_LT(index, size_); 147 RTC_DCHECK_LT(index, size_);
120 return data()[index]; 148 return data()[index];
121 } 149 }
122 150
123 uint8_t operator[](size_t index) const { 151 T operator[](size_t index) const {
124 RTC_DCHECK_LT(index, size_); 152 RTC_DCHECK_LT(index, size_);
125 return data()[index]; 153 return data()[index];
126 } 154 }
127 155
128 // The SetData functions replace the contents of the buffer. They accept the 156 // The SetData functions replace the contents of the buffer. They accept the
129 // same input types as the constructors. 157 // same input types as the constructors.
130 template <typename T, typename internal::ByteType<T>::t = 0> 158 template <typename U,
131 void SetData(const T* data, size_t size) { 159 typename std::enable_if<
160 internal::BufferCompat<T, U>::value>::type* = nullptr>
161 void SetData(const U* data, size_t size) {
132 RTC_DCHECK(IsConsistent()); 162 RTC_DCHECK(IsConsistent());
133 size_ = 0; 163 size_ = 0;
134 AppendData(data, size); 164 AppendData(data, size);
135 } 165 }
136 166
137 template <typename T, size_t N, typename internal::ByteType<T>::t = 0> 167 template <typename U,
138 void SetData(const T(&array)[N]) { 168 size_t N,
169 typename std::enable_if<
170 internal::BufferCompat<T, U>::value>::type* = nullptr>
171 void SetData(const U (&array)[N]) {
139 SetData(array, N); 172 SetData(array, N);
140 } 173 }
141 174
142 void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); } 175 void SetData(const BufferT& buf) { SetData(buf.data(), buf.size()); }
143 176
144 // Replace the data in the buffer with at most |max_bytes| of data, using the 177 // Replace the data in the buffer with at most |max_elements| of data, using
145 // function |setter|, which should have the following signature: 178 // the function |setter|, which should have the following signature:
146 // size_t setter(ArrayView<T> view) 179 // size_t setter(ArrayView<U> view)
147 // |setter| is given an appropriately typed ArrayView of the area in which to 180 // |setter| is given an appropriately typed ArrayView of the area in which to
148 // write the data (i.e. starting at the beginning of the buffer) and should 181 // write the data (i.e. starting at the beginning of the buffer) and should
149 // return the number of bytes actually written. This number must be <= 182 // return the number of elements actually written. This number must be <=
150 // |max_bytes|. 183 // |max_elements|.
151 template <typename T = uint8_t, typename F, 184 template <typename U = T,
152 typename internal::ByteType<T>::t = 0> 185 typename F,
153 size_t SetData(size_t max_bytes, F&& setter) { 186 typename std::enable_if<
187 internal::BufferCompat<T, U>::value>::type* = nullptr>
188 size_t SetData(size_t max_elements, F&& setter) {
154 RTC_DCHECK(IsConsistent()); 189 RTC_DCHECK(IsConsistent());
155 size_ = 0; 190 size_ = 0;
156 return AppendData<T>(max_bytes, std::forward<F>(setter)); 191 return AppendData<U>(max_elements, std::forward<F>(setter));
157 } 192 }
158 193
159 // The AppendData functions adds data to the end of the buffer. They accept 194 // The AppendData functions adds data to the end of the buffer. They accept
ossu 2016/04/28 13:36:53 Not your fault, but it should be "functions add" r
kwiberg-webrtc 2016/04/28 21:19:01 Done.
160 // the same input types as the constructors. 195 // the same input types as the constructors.
161 template <typename T, typename internal::ByteType<T>::t = 0> 196 template <typename U,
162 void AppendData(const T* data, size_t size) { 197 typename std::enable_if<
198 internal::BufferCompat<T, U>::value>::type* = nullptr>
199 void AppendData(const U* data, size_t size) {
163 RTC_DCHECK(IsConsistent()); 200 RTC_DCHECK(IsConsistent());
164 const size_t new_size = size_ + size; 201 const size_t new_size = size_ + size;
165 EnsureCapacity(new_size); 202 EnsureCapacity(new_size);
166 std::memcpy(data_.get() + size_, data, size); 203 static_assert(sizeof(T) == sizeof(U), "");
204 std::memcpy(data_.get() + size_, data, size * sizeof(U));
167 size_ = new_size; 205 size_ = new_size;
168 RTC_DCHECK(IsConsistent()); 206 RTC_DCHECK(IsConsistent());
169 } 207 }
170 208
171 template <typename T, size_t N, typename internal::ByteType<T>::t = 0> 209 template <typename U,
172 void AppendData(const T(&array)[N]) { 210 size_t N,
211 typename std::enable_if<
212 internal::BufferCompat<T, U>::value>::type* = nullptr>
213 void AppendData(const U (&array)[N]) {
173 AppendData(array, N); 214 AppendData(array, N);
174 } 215 }
175 216
176 void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); } 217 void AppendData(const BufferT& buf) { AppendData(buf.data(), buf.size()); }
177 218
178 // Append at most |max_bytes| of data to the end of the buffer, using the 219 // Append at most |max_elements| to the end of the buffer, using the function
179 // function |setter|, which should have the following signature: 220 // |setter|, which should have the following signature:
180 // size_t setter(ArrayView<T> view) 221 // size_t setter(ArrayView<U> view)
181 // |setter| is given an appropriately typed ArrayView of the area in which to 222 // |setter| is given an appropriately typed ArrayView of the area in which to
182 // write the data (i.e. starting at the former end of the buffer) and should 223 // write the data (i.e. starting at the former end of the buffer) and should
183 // return the number of bytes actually written. This number must be <= 224 // return the number of elements actually written. This number must be <=
184 // |max_bytes|. 225 // |max_elements|.
185 template <typename T = uint8_t, typename F, 226 template <typename U = T,
186 typename internal::ByteType<T>::t = 0> 227 typename F,
187 size_t AppendData(size_t max_bytes, F&& setter) { 228 typename std::enable_if<
229 internal::BufferCompat<T, U>::value>::type* = nullptr>
230 size_t AppendData(size_t max_elements, F&& setter) {
188 RTC_DCHECK(IsConsistent()); 231 RTC_DCHECK(IsConsistent());
189 const size_t old_size = size_; 232 const size_t old_size = size_;
190 SetSize(old_size + max_bytes); 233 SetSize(old_size + max_elements);
191 T *base_ptr = data<T>() + old_size; 234 U* base_ptr = data<U>() + old_size;
192 size_t written_bytes = 235 size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements));
193 setter(rtc::ArrayView<T>(base_ptr, max_bytes));
194 236
195 RTC_CHECK_LE(written_bytes, max_bytes); 237 RTC_CHECK_LE(written_elements, max_elements);
196 size_ = old_size + written_bytes; 238 size_ = old_size + written_elements;
197 RTC_DCHECK(IsConsistent()); 239 RTC_DCHECK(IsConsistent());
198 return written_bytes; 240 return written_elements;
199 } 241 }
200 242
201 // Sets the size of the buffer. If the new size is smaller than the old, the 243 // Sets the size of the buffer. If the new size is smaller than the old, the
202 // buffer contents will be kept but truncated; if the new size is greater, 244 // buffer contents will be kept but truncated; if the new size is greater,
203 // the existing contents will be kept and the new space will be 245 // the existing contents will be kept and the new space will be
204 // uninitialized. 246 // uninitialized.
205 void SetSize(size_t size) { 247 void SetSize(size_t size) {
206 EnsureCapacity(size); 248 EnsureCapacity(size);
207 size_ = size; 249 size_ = size;
208 } 250 }
209 251
210 // Ensure that the buffer size can be increased to at least capacity without 252 // Ensure that the buffer size can be increased to at least capacity without
211 // further reallocation. (Of course, this operation might need to reallocate 253 // further reallocation. (Of course, this operation might need to reallocate
212 // the buffer.) 254 // the buffer.)
213 void EnsureCapacity(size_t capacity) { 255 void EnsureCapacity(size_t capacity) {
214 RTC_DCHECK(IsConsistent()); 256 RTC_DCHECK(IsConsistent());
215 if (capacity <= capacity_) 257 if (capacity <= capacity_)
216 return; 258 return;
217 std::unique_ptr<uint8_t[]> new_data(new uint8_t[capacity]); 259 std::unique_ptr<T[]> new_data(new T[capacity]);
218 std::memcpy(new_data.get(), data_.get(), size_); 260 std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T));
219 data_ = std::move(new_data); 261 data_ = std::move(new_data);
220 capacity_ = capacity; 262 capacity_ = capacity;
221 RTC_DCHECK(IsConsistent()); 263 RTC_DCHECK(IsConsistent());
222 } 264 }
223 265
224 // Resets the buffer to zero size without altering capacity. Works even if the 266 // Resets the buffer to zero size without altering capacity. Works even if the
225 // buffer has been moved from. 267 // buffer has been moved from.
226 void Clear() { 268 void Clear() {
227 size_ = 0; 269 size_ = 0;
228 RTC_DCHECK(IsConsistent()); 270 RTC_DCHECK(IsConsistent());
229 } 271 }
230 272
231 // Swaps two buffers. Also works for buffers that have been moved from. 273 // Swaps two buffers. Also works for buffers that have been moved from.
232 friend void swap(Buffer& a, Buffer& b) { 274 friend void swap(BufferT& a, BufferT& b) {
233 using std::swap; 275 using std::swap;
234 swap(a.size_, b.size_); 276 swap(a.size_, b.size_);
235 swap(a.capacity_, b.capacity_); 277 swap(a.capacity_, b.capacity_);
236 swap(a.data_, b.data_); 278 swap(a.data_, b.data_);
237 } 279 }
238 280
239 private: 281 private:
240 // Precondition for all methods except Clear and the destructor. 282 // Precondition for all methods except Clear and the destructor.
241 // Postcondition for all methods except move construction and move 283 // Postcondition for all methods except move construction and move
242 // assignment, which leave the moved-from object in a possibly inconsistent 284 // assignment, which leave the moved-from object in a possibly inconsistent
(...skipping 12 matching lines...) Expand all
255 capacity_ = 0; 297 capacity_ = 0;
256 #else 298 #else
257 // Ensure that *this is always inconsistent, to provoke bugs. 299 // Ensure that *this is always inconsistent, to provoke bugs.
258 size_ = 1; 300 size_ = 1;
259 capacity_ = 0; 301 capacity_ = 0;
260 #endif 302 #endif
261 } 303 }
262 304
263 size_t size_; 305 size_t size_;
264 size_t capacity_; 306 size_t capacity_;
265 std::unique_ptr<uint8_t[]> data_; 307 std::unique_ptr<T[]> data_;
308 };
266 309
267 RTC_DISALLOW_COPY_AND_ASSIGN(Buffer); 310 // By far the most common sort of buffer.
268 }; 311 using Buffer = BufferT<uint8_t>;
269 312
270 } // namespace rtc 313 } // namespace rtc
271 314
272 #endif // WEBRTC_BASE_BUFFER_H_ 315 #endif // WEBRTC_BASE_BUFFER_H_
OLDNEW
« no previous file with comments | « webrtc/base/base.gyp ('k') | webrtc/base/buffer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698