blob: b8b8fc0e1693f92e87969f57eb5ec7c84cd86f15 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 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_BUFFER_H_
12#define WEBRTC_BASE_BUFFER_H_
13
Karl Wiberg94784372015-04-20 14:03:07 +020014#include <cstring>
kwiberg8fb35572016-02-11 13:36:43 -080015#include <memory>
kwiberga4ac4782016-04-29 08:00:22 -070016#include <type_traits>
ossub01c7812016-02-24 01:05:56 -080017#include <utility>
kwiberg36220ae2016-01-12 07:24:19 -080018
ossub01c7812016-02-24 01:05:56 -080019#include "webrtc/base/array_view.h"
20#include "webrtc/base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021
22namespace rtc {
23
Karl Wiberg94784372015-04-20 14:03:07 +020024namespace internal {
25
kwiberga4ac4782016-04-29 08:00:22 -070026// (Internal; please don't use outside this file.) Determines if elements of
27// type U are compatible with a BufferT<T>. For most types, we just ignore
28// top-level const and forbid top-level volatile and require T and U to be
29// otherwise equal, but all byte-sized integers (notably char, int8_t, and
30// uint8_t) are compatible with each other. (Note: We aim to get rid of this
31// behavior, and treat all types the same.)
32template <typename T, typename U>
33struct BufferCompat {
34 static constexpr bool value =
35 !std::is_volatile<U>::value &&
36 ((std::is_integral<T>::value && sizeof(T) == 1)
37 ? (std::is_integral<U>::value && sizeof(U) == 1)
38 : (std::is_same<T, typename std::remove_const<U>::type>::value));
Karl Wiberg94784372015-04-20 14:03:07 +020039};
40
41} // namespace internal
42
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043// Basic buffer class, can be grown and shrunk dynamically.
kwiberga4ac4782016-04-29 08:00:22 -070044// Unlike std::string/vector, does not initialize data when increasing size.
45template <typename T>
46class BufferT {
47 // We want T's destructor and default constructor to be trivial, i.e. perform
48 // no action, so that we don't have to touch the memory we allocate and
49 // deallocate. And we want T to be trivially copyable, so that we can copy T
50 // instances with std::memcpy. This is precisely the definition of a trivial
51 // type.
52 static_assert(std::is_trivial<T>::value, "T must be a trivial type.");
53
54 // This class relies heavily on being able to mutate its data.
55 static_assert(!std::is_const<T>::value, "T may not be const");
56
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 public:
kwiberga4ac4782016-04-29 08:00:22 -070058 // An empty BufferT.
59 BufferT() : size_(0), capacity_(0), data_(nullptr) {
60 RTC_DCHECK(IsConsistent());
61 }
Karl Wiberg94784372015-04-20 14:03:07 +020062
kwiberga4ac4782016-04-29 08:00:22 -070063 // Disable copy construction and copy assignment, since copying a buffer is
64 // expensive enough that we want to force the user to be explicit about it.
65 BufferT(const BufferT&) = delete;
66 BufferT& operator=(const BufferT&) = delete;
Karl Wiberg94784372015-04-20 14:03:07 +020067
kwiberga4ac4782016-04-29 08:00:22 -070068 BufferT(BufferT&& buf)
69 : size_(buf.size()),
70 capacity_(buf.capacity()),
71 data_(std::move(buf.data_)) {
72 RTC_DCHECK(IsConsistent());
73 buf.OnMovedFrom();
74 }
ossub01c7812016-02-24 01:05:56 -080075
kwiberga4ac4782016-04-29 08:00:22 -070076 // Construct a buffer with the specified number of uninitialized elements.
77 explicit BufferT(size_t size) : BufferT(size, size) {}
78
79 BufferT(size_t size, size_t capacity)
80 : size_(size),
81 capacity_(std::max(size, capacity)),
82 data_(new T[capacity_]) {
83 RTC_DCHECK(IsConsistent());
84 }
85
86 // Construct a buffer and copy the specified number of elements into it.
87 template <typename U,
88 typename std::enable_if<
89 internal::BufferCompat<T, U>::value>::type* = nullptr>
90 BufferT(const U* data, size_t size) : BufferT(data, size, size) {}
91
92 template <typename U,
93 typename std::enable_if<
94 internal::BufferCompat<T, U>::value>::type* = nullptr>
95 BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) {
96 static_assert(sizeof(T) == sizeof(U), "");
97 std::memcpy(data_.get(), data, size * sizeof(U));
Karl Wiberg94784372015-04-20 14:03:07 +020098 }
99
100 // Construct a buffer from the contents of an array.
kwiberga4ac4782016-04-29 08:00:22 -0700101 template <typename U,
102 size_t N,
103 typename std::enable_if<
104 internal::BufferCompat<T, U>::value>::type* = nullptr>
105 BufferT(U (&array)[N]) : BufferT(array, N) {}
Karl Wiberg94784372015-04-20 14:03:07 +0200106
kwiberga4ac4782016-04-29 08:00:22 -0700107 // Get a pointer to the data. Just .data() will give you a (const) T*, but if
108 // T is a byte-sized integer, you may also use .data<U>() for any other
109 // byte-sized integer U.
110 template <typename U = T,
111 typename std::enable_if<
112 internal::BufferCompat<T, U>::value>::type* = nullptr>
113 const U* data() const {
kwiberge3d99222016-03-01 01:57:38 -0800114 RTC_DCHECK(IsConsistent());
kwiberga4ac4782016-04-29 08:00:22 -0700115 return reinterpret_cast<U*>(data_.get());
Karl Wiberg94784372015-04-20 14:03:07 +0200116 }
ossub01c7812016-02-24 01:05:56 -0800117
kwiberga4ac4782016-04-29 08:00:22 -0700118 template <typename U = T,
119 typename std::enable_if<
120 internal::BufferCompat<T, U>::value>::type* = nullptr>
121 U* data() {
kwiberge3d99222016-03-01 01:57:38 -0800122 RTC_DCHECK(IsConsistent());
kwiberga4ac4782016-04-29 08:00:22 -0700123 return reinterpret_cast<U*>(data_.get());
Karl Wiberg94784372015-04-20 14:03:07 +0200124 }
125
126 size_t size() const {
kwiberge3d99222016-03-01 01:57:38 -0800127 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200128 return size_;
129 }
ossub01c7812016-02-24 01:05:56 -0800130
Karl Wiberg94784372015-04-20 14:03:07 +0200131 size_t capacity() const {
kwiberge3d99222016-03-01 01:57:38 -0800132 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200133 return capacity_;
134 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135
kwiberga4ac4782016-04-29 08:00:22 -0700136 BufferT& operator=(BufferT&& buf) {
kwiberge3d99222016-03-01 01:57:38 -0800137 RTC_DCHECK(IsConsistent());
138 RTC_DCHECK(buf.IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200139 size_ = buf.size_;
140 capacity_ = buf.capacity_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800141 data_ = std::move(buf.data_);
Karl Wiberg94784372015-04-20 14:03:07 +0200142 buf.OnMovedFrom();
143 return *this;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 }
145
kwiberga4ac4782016-04-29 08:00:22 -0700146 bool operator==(const BufferT& buf) const {
kwiberge3d99222016-03-01 01:57:38 -0800147 RTC_DCHECK(IsConsistent());
kwiberga4ac4782016-04-29 08:00:22 -0700148 if (size_ != buf.size_) {
149 return false;
150 }
151 if (std::is_integral<T>::value) {
152 // Optimization.
153 return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0;
154 }
155 for (size_t i = 0; i < size_; ++i) {
156 if (data_[i] != buf.data_[i]) {
157 return false;
158 }
159 }
160 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161 }
Karl Wiberg94784372015-04-20 14:03:07 +0200162
kwiberga4ac4782016-04-29 08:00:22 -0700163 bool operator!=(const BufferT& buf) const { return !(*this == buf); }
Karl Wiberg94784372015-04-20 14:03:07 +0200164
kwiberga4ac4782016-04-29 08:00:22 -0700165 T& operator[](size_t index) {
ossub9338ac2016-02-29 09:36:37 -0800166 RTC_DCHECK_LT(index, size_);
167 return data()[index];
168 }
169
kwiberga4ac4782016-04-29 08:00:22 -0700170 T operator[](size_t index) const {
ossub9338ac2016-02-29 09:36:37 -0800171 RTC_DCHECK_LT(index, size_);
172 return data()[index];
173 }
174
ossub01c7812016-02-24 01:05:56 -0800175 // The SetData functions replace the contents of the buffer. They accept the
176 // same input types as the constructors.
kwiberga4ac4782016-04-29 08:00:22 -0700177 template <typename U,
178 typename std::enable_if<
179 internal::BufferCompat<T, U>::value>::type* = nullptr>
180 void SetData(const U* data, size_t size) {
kwiberge3d99222016-03-01 01:57:38 -0800181 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200182 size_ = 0;
183 AppendData(data, size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000184 }
ossub01c7812016-02-24 01:05:56 -0800185
kwiberga4ac4782016-04-29 08:00:22 -0700186 template <typename U,
187 size_t N,
188 typename std::enable_if<
189 internal::BufferCompat<T, U>::value>::type* = nullptr>
190 void SetData(const U (&array)[N]) {
Karl Wiberg94784372015-04-20 14:03:07 +0200191 SetData(array, N);
192 }
ossub01c7812016-02-24 01:05:56 -0800193
kwiberga4ac4782016-04-29 08:00:22 -0700194 void SetData(const BufferT& buf) { SetData(buf.data(), buf.size()); }
Karl Wiberg94784372015-04-20 14:03:07 +0200195
kwiberga4ac4782016-04-29 08:00:22 -0700196 // Replace the data in the buffer with at most |max_elements| of data, using
197 // the function |setter|, which should have the following signature:
198 // size_t setter(ArrayView<U> view)
ossub01c7812016-02-24 01:05:56 -0800199 // |setter| is given an appropriately typed ArrayView of the area in which to
200 // write the data (i.e. starting at the beginning of the buffer) and should
kwiberga4ac4782016-04-29 08:00:22 -0700201 // return the number of elements actually written. This number must be <=
202 // |max_elements|.
203 template <typename U = T,
204 typename F,
205 typename std::enable_if<
206 internal::BufferCompat<T, U>::value>::type* = nullptr>
207 size_t SetData(size_t max_elements, F&& setter) {
ossub01c7812016-02-24 01:05:56 -0800208 RTC_DCHECK(IsConsistent());
209 size_ = 0;
kwiberga4ac4782016-04-29 08:00:22 -0700210 return AppendData<U>(max_elements, std::forward<F>(setter));
ossub01c7812016-02-24 01:05:56 -0800211 }
212
kwiberga4ac4782016-04-29 08:00:22 -0700213 // The AppendData functions add data to the end of the buffer. They accept
ossub01c7812016-02-24 01:05:56 -0800214 // the same input types as the constructors.
kwiberga4ac4782016-04-29 08:00:22 -0700215 template <typename U,
216 typename std::enable_if<
217 internal::BufferCompat<T, U>::value>::type* = nullptr>
218 void AppendData(const U* data, size_t size) {
kwiberge3d99222016-03-01 01:57:38 -0800219 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200220 const size_t new_size = size_ + size;
221 EnsureCapacity(new_size);
kwiberga4ac4782016-04-29 08:00:22 -0700222 static_assert(sizeof(T) == sizeof(U), "");
223 std::memcpy(data_.get() + size_, data, size * sizeof(U));
Karl Wiberg94784372015-04-20 14:03:07 +0200224 size_ = new_size;
kwiberge3d99222016-03-01 01:57:38 -0800225 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200226 }
ossub01c7812016-02-24 01:05:56 -0800227
kwiberga4ac4782016-04-29 08:00:22 -0700228 template <typename U,
229 size_t N,
230 typename std::enable_if<
231 internal::BufferCompat<T, U>::value>::type* = nullptr>
232 void AppendData(const U (&array)[N]) {
Karl Wiberg94784372015-04-20 14:03:07 +0200233 AppendData(array, N);
234 }
ossub01c7812016-02-24 01:05:56 -0800235
kwiberga4ac4782016-04-29 08:00:22 -0700236 void AppendData(const BufferT& buf) { AppendData(buf.data(), buf.size()); }
Karl Wiberg94784372015-04-20 14:03:07 +0200237
kwiberga4ac4782016-04-29 08:00:22 -0700238 // Append at most |max_elements| to the end of the buffer, using the function
239 // |setter|, which should have the following signature:
240 // size_t setter(ArrayView<U> view)
ossub01c7812016-02-24 01:05:56 -0800241 // |setter| is given an appropriately typed ArrayView of the area in which to
242 // write the data (i.e. starting at the former end of the buffer) and should
kwiberga4ac4782016-04-29 08:00:22 -0700243 // return the number of elements actually written. This number must be <=
244 // |max_elements|.
245 template <typename U = T,
246 typename F,
247 typename std::enable_if<
248 internal::BufferCompat<T, U>::value>::type* = nullptr>
249 size_t AppendData(size_t max_elements, F&& setter) {
ossub01c7812016-02-24 01:05:56 -0800250 RTC_DCHECK(IsConsistent());
251 const size_t old_size = size_;
kwiberga4ac4782016-04-29 08:00:22 -0700252 SetSize(old_size + max_elements);
253 U* base_ptr = data<U>() + old_size;
254 size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements));
ossub01c7812016-02-24 01:05:56 -0800255
kwiberga4ac4782016-04-29 08:00:22 -0700256 RTC_CHECK_LE(written_elements, max_elements);
257 size_ = old_size + written_elements;
ossub01c7812016-02-24 01:05:56 -0800258 RTC_DCHECK(IsConsistent());
kwiberga4ac4782016-04-29 08:00:22 -0700259 return written_elements;
ossub01c7812016-02-24 01:05:56 -0800260 }
261
Karl Wiberg94784372015-04-20 14:03:07 +0200262 // Sets the size of the buffer. If the new size is smaller than the old, the
263 // buffer contents will be kept but truncated; if the new size is greater,
264 // the existing contents will be kept and the new space will be
265 // uninitialized.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000266 void SetSize(size_t size) {
Karl Wiberg94784372015-04-20 14:03:07 +0200267 EnsureCapacity(size);
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000268 size_ = size;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000269 }
Karl Wiberg94784372015-04-20 14:03:07 +0200270
271 // Ensure that the buffer size can be increased to at least capacity without
272 // further reallocation. (Of course, this operation might need to reallocate
273 // the buffer.)
274 void EnsureCapacity(size_t capacity) {
kwiberge3d99222016-03-01 01:57:38 -0800275 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200276 if (capacity <= capacity_)
277 return;
kwiberga4ac4782016-04-29 08:00:22 -0700278 std::unique_ptr<T[]> new_data(new T[capacity]);
279 std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T));
kwiberg0eb15ed2015-12-17 03:04:15 -0800280 data_ = std::move(new_data);
Karl Wiberg94784372015-04-20 14:03:07 +0200281 capacity_ = capacity;
kwiberge3d99222016-03-01 01:57:38 -0800282 RTC_DCHECK(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283 }
284
ossu728012e2016-02-19 02:38:32 -0800285 // Resets the buffer to zero size without altering capacity. Works even if the
286 // buffer has been moved from.
Karl Wiberg94784372015-04-20 14:03:07 +0200287 void Clear() {
Karl Wiberg94784372015-04-20 14:03:07 +0200288 size_ = 0;
kwiberge3d99222016-03-01 01:57:38 -0800289 RTC_DCHECK(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000290 }
291
Karl Wiberg94784372015-04-20 14:03:07 +0200292 // Swaps two buffers. Also works for buffers that have been moved from.
kwiberga4ac4782016-04-29 08:00:22 -0700293 friend void swap(BufferT& a, BufferT& b) {
Karl Wiberg94784372015-04-20 14:03:07 +0200294 using std::swap;
295 swap(a.size_, b.size_);
296 swap(a.capacity_, b.capacity_);
297 swap(a.data_, b.data_);
298 }
299
300 private:
301 // Precondition for all methods except Clear and the destructor.
302 // Postcondition for all methods except move construction and move
303 // assignment, which leave the moved-from object in a possibly inconsistent
304 // state.
305 bool IsConsistent() const {
306 return (data_ || capacity_ == 0) && capacity_ >= size_;
307 }
308
309 // Called when *this has been moved from. Conceptually it's a no-op, but we
310 // can mutate the state slightly to help subsequent sanity checks catch bugs.
311 void OnMovedFrom() {
312#ifdef NDEBUG
313 // Make *this consistent and empty. Shouldn't be necessary, but better safe
314 // than sorry.
315 size_ = 0;
316 capacity_ = 0;
317#else
318 // Ensure that *this is always inconsistent, to provoke bugs.
319 size_ = 1;
320 capacity_ = 0;
321#endif
322 }
323
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000324 size_t size_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000325 size_t capacity_;
kwiberga4ac4782016-04-29 08:00:22 -0700326 std::unique_ptr<T[]> data_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327};
328
kwiberga4ac4782016-04-29 08:00:22 -0700329// By far the most common sort of buffer.
330using Buffer = BufferT<uint8_t>;
331
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000332} // namespace rtc
333
334#endif // WEBRTC_BASE_BUFFER_H_