blob: e9c47ee84e02168b6df52bb5c071613c1c9a9067 [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>
ossub01c7812016-02-24 01:05:56 -080016#include <utility>
kwiberg36220ae2016-01-12 07:24:19 -080017
ossub01c7812016-02-24 01:05:56 -080018#include "webrtc/base/array_view.h"
19#include "webrtc/base/checks.h"
kwiberg8fb35572016-02-11 13:36:43 -080020#include "webrtc/base/constructormagic.h"
kwiberg36220ae2016-01-12 07:24:19 -080021#include "webrtc/base/deprecation.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022
23namespace rtc {
24
Karl Wiberg94784372015-04-20 14:03:07 +020025namespace internal {
26
27// (Internal; please don't use outside this file.) ByteType<T>::t is int if T
28// is uint8_t, int8_t, or char; otherwise, it's a compilation error. Use like
29// this:
30//
31// template <typename T, typename ByteType<T>::t = 0>
32// void foo(T* x);
33//
34// to let foo<T> be defined only for byte-sized integers.
35template <typename T>
36struct ByteType {
37 private:
38 static int F(uint8_t*);
39 static int F(int8_t*);
40 static int F(char*);
41
42 public:
43 using t = decltype(F(static_cast<T*>(nullptr)));
44};
45
46} // namespace internal
47
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000048// Basic buffer class, can be grown and shrunk dynamically.
49// Unlike std::string/vector, does not initialize data when expanding capacity.
noahric27dfe202015-10-23 06:01:10 -070050class Buffer {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000051 public:
Karl Wiberg94784372015-04-20 14:03:07 +020052 Buffer(); // An empty buffer.
53 Buffer(const Buffer& buf); // Copy size and contents of an existing buffer.
54 Buffer(Buffer&& buf); // Move contents from an existing buffer.
55
56 // Construct a buffer with the specified number of uninitialized bytes.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +000057 explicit Buffer(size_t size);
Karl Wiberg94784372015-04-20 14:03:07 +020058 Buffer(size_t size, size_t capacity);
59
60 // Construct a buffer and copy the specified number of bytes into it. The
61 // source array may be (const) uint8_t*, int8_t*, or char*.
Karl Wibergc56ac1e2015-05-04 14:54:55 +020062 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020063 Buffer(const T* data, size_t size)
64 : Buffer(data, size, size) {}
ossub01c7812016-02-24 01:05:56 -080065
Karl Wibergc56ac1e2015-05-04 14:54:55 +020066 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020067 Buffer(const T* data, size_t size, size_t capacity)
68 : Buffer(size, capacity) {
69 std::memcpy(data_.get(), data, size);
70 }
71
72 // Construct a buffer from the contents of an array.
73 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
74 Buffer(const T(&array)[N])
75 : Buffer(array, N) {}
76
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000077 ~Buffer();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078
Karl Wibergc56ac1e2015-05-04 14:54:55 +020079 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
80 // but you may also use .data<int8_t>() and .data<char>().
81 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020082 const T* data() const {
kwiberge3d99222016-03-01 01:57:38 -080083 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +020084 return reinterpret_cast<T*>(data_.get());
85 }
ossub01c7812016-02-24 01:05:56 -080086
Karl Wibergc56ac1e2015-05-04 14:54:55 +020087 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020088 T* data() {
kwiberge3d99222016-03-01 01:57:38 -080089 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +020090 return reinterpret_cast<T*>(data_.get());
91 }
92
93 size_t size() const {
kwiberge3d99222016-03-01 01:57:38 -080094 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +020095 return size_;
96 }
ossub01c7812016-02-24 01:05:56 -080097
Karl Wiberg94784372015-04-20 14:03:07 +020098 size_t capacity() const {
kwiberge3d99222016-03-01 01:57:38 -080099 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200100 return capacity_;
101 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102
103 Buffer& operator=(const Buffer& buf) {
Karl Wiberg94784372015-04-20 14:03:07 +0200104 if (&buf != this)
105 SetData(buf.data(), buf.size());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000106 return *this;
107 }
ossub01c7812016-02-24 01:05:56 -0800108
Karl Wiberg94784372015-04-20 14:03:07 +0200109 Buffer& operator=(Buffer&& buf) {
kwiberge3d99222016-03-01 01:57:38 -0800110 RTC_DCHECK(IsConsistent());
111 RTC_DCHECK(buf.IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200112 size_ = buf.size_;
113 capacity_ = buf.capacity_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800114 data_ = std::move(buf.data_);
Karl Wiberg94784372015-04-20 14:03:07 +0200115 buf.OnMovedFrom();
116 return *this;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 }
118
Karl Wiberg94784372015-04-20 14:03:07 +0200119 bool operator==(const Buffer& buf) const {
kwiberge3d99222016-03-01 01:57:38 -0800120 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200121 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 }
Karl Wiberg94784372015-04-20 14:03:07 +0200123
124 bool operator!=(const Buffer& buf) const { return !(*this == buf); }
125
ossub9338ac2016-02-29 09:36:37 -0800126 uint8_t& operator[](size_t index) {
127 RTC_DCHECK_LT(index, size_);
128 return data()[index];
129 }
130
131 uint8_t operator[](size_t index) const {
132 RTC_DCHECK_LT(index, size_);
133 return data()[index];
134 }
135
ossub01c7812016-02-24 01:05:56 -0800136 // The SetData functions replace the contents of the buffer. They accept the
137 // same input types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200138 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200139 void SetData(const T* data, size_t size) {
kwiberge3d99222016-03-01 01:57:38 -0800140 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200141 size_ = 0;
142 AppendData(data, size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143 }
ossub01c7812016-02-24 01:05:56 -0800144
Karl Wiberg94784372015-04-20 14:03:07 +0200145 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
146 void SetData(const T(&array)[N]) {
147 SetData(array, N);
148 }
ossub01c7812016-02-24 01:05:56 -0800149
Karl Wiberg94784372015-04-20 14:03:07 +0200150 void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); }
151
ossub01c7812016-02-24 01:05:56 -0800152 // Replace the data in the buffer with at most |max_bytes| of data, using the
153 // function |setter|, which should have the following signature:
154 // size_t setter(ArrayView<T> view)
155 // |setter| is given an appropriately typed ArrayView of the area in which to
156 // write the data (i.e. starting at the beginning of the buffer) and should
157 // return the number of bytes actually written. This number must be <=
158 // |max_bytes|.
159 template <typename T = uint8_t, typename F,
160 typename internal::ByteType<T>::t = 0>
161 size_t SetData(size_t max_bytes, F&& setter) {
162 RTC_DCHECK(IsConsistent());
163 size_ = 0;
164 return AppendData<T>(max_bytes, std::forward<F>(setter));
165 }
166
167 // The AppendData functions adds data to the end of the buffer. They accept
168 // the same input types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200169 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200170 void AppendData(const T* data, size_t size) {
kwiberge3d99222016-03-01 01:57:38 -0800171 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200172 const size_t new_size = size_ + size;
173 EnsureCapacity(new_size);
174 std::memcpy(data_.get() + size_, data, size);
175 size_ = new_size;
kwiberge3d99222016-03-01 01:57:38 -0800176 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200177 }
ossub01c7812016-02-24 01:05:56 -0800178
Karl Wiberg94784372015-04-20 14:03:07 +0200179 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
180 void AppendData(const T(&array)[N]) {
181 AppendData(array, N);
182 }
ossub01c7812016-02-24 01:05:56 -0800183
Karl Wiberg94784372015-04-20 14:03:07 +0200184 void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); }
185
ossub01c7812016-02-24 01:05:56 -0800186 // Append at most |max_bytes| of data to the end of the buffer, using the
187 // function |setter|, which should have the following signature:
188 // size_t setter(ArrayView<T> view)
189 // |setter| is given an appropriately typed ArrayView of the area in which to
190 // write the data (i.e. starting at the former end of the buffer) and should
191 // return the number of bytes actually written. This number must be <=
192 // |max_bytes|.
193 template <typename T = uint8_t, typename F,
194 typename internal::ByteType<T>::t = 0>
195 size_t AppendData(size_t max_bytes, F&& setter) {
196 RTC_DCHECK(IsConsistent());
197 const size_t old_size = size_;
198 SetSize(old_size + max_bytes);
199 T *base_ptr = data<T>() + old_size;
200 size_t written_bytes =
201 setter(rtc::ArrayView<T>(base_ptr, max_bytes));
202
203 RTC_CHECK_LE(written_bytes, max_bytes);
204 size_ = old_size + written_bytes;
205 RTC_DCHECK(IsConsistent());
206 return written_bytes;
207 }
208
Karl Wiberg94784372015-04-20 14:03:07 +0200209 // Sets the size of the buffer. If the new size is smaller than the old, the
210 // buffer contents will be kept but truncated; if the new size is greater,
211 // the existing contents will be kept and the new space will be
212 // uninitialized.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000213 void SetSize(size_t size) {
Karl Wiberg94784372015-04-20 14:03:07 +0200214 EnsureCapacity(size);
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000215 size_ = size;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000216 }
Karl Wiberg94784372015-04-20 14:03:07 +0200217
218 // Ensure that the buffer size can be increased to at least capacity without
219 // further reallocation. (Of course, this operation might need to reallocate
220 // the buffer.)
221 void EnsureCapacity(size_t capacity) {
kwiberge3d99222016-03-01 01:57:38 -0800222 RTC_DCHECK(IsConsistent());
Karl Wiberg94784372015-04-20 14:03:07 +0200223 if (capacity <= capacity_)
224 return;
kwiberg8fb35572016-02-11 13:36:43 -0800225 std::unique_ptr<uint8_t[]> new_data(new uint8_t[capacity]);
Karl Wiberg94784372015-04-20 14:03:07 +0200226 std::memcpy(new_data.get(), data_.get(), size_);
kwiberg0eb15ed2015-12-17 03:04:15 -0800227 data_ = std::move(new_data);
Karl Wiberg94784372015-04-20 14:03:07 +0200228 capacity_ = capacity;
kwiberge3d99222016-03-01 01:57:38 -0800229 RTC_DCHECK(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000230 }
231
kwiberg0eb15ed2015-12-17 03:04:15 -0800232 // b.Pass() does the same thing as std::move(b).
kwiberg36220ae2016-01-12 07:24:19 -0800233 // Deprecated; remove in March 2016 (bug 5373).
234 RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); }
ossub01c7812016-02-24 01:05:56 -0800235
kwiberg36220ae2016-01-12 07:24:19 -0800236 Buffer&& DEPRECATED_Pass() {
kwiberge3d99222016-03-01 01:57:38 -0800237 RTC_DCHECK(IsConsistent());
kwibergcea7c2f2016-01-07 05:52:04 -0800238 return std::move(*this);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 }
240
ossu728012e2016-02-19 02:38:32 -0800241 // Resets the buffer to zero size without altering capacity. Works even if the
242 // buffer has been moved from.
Karl Wiberg94784372015-04-20 14:03:07 +0200243 void Clear() {
Karl Wiberg94784372015-04-20 14:03:07 +0200244 size_ = 0;
kwiberge3d99222016-03-01 01:57:38 -0800245 RTC_DCHECK(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000246 }
247
Karl Wiberg94784372015-04-20 14:03:07 +0200248 // Swaps two buffers. Also works for buffers that have been moved from.
249 friend void swap(Buffer& a, Buffer& b) {
250 using std::swap;
251 swap(a.size_, b.size_);
252 swap(a.capacity_, b.capacity_);
253 swap(a.data_, b.data_);
254 }
255
256 private:
257 // Precondition for all methods except Clear and the destructor.
258 // Postcondition for all methods except move construction and move
259 // assignment, which leave the moved-from object in a possibly inconsistent
260 // state.
261 bool IsConsistent() const {
262 return (data_ || capacity_ == 0) && capacity_ >= size_;
263 }
264
265 // Called when *this has been moved from. Conceptually it's a no-op, but we
266 // can mutate the state slightly to help subsequent sanity checks catch bugs.
267 void OnMovedFrom() {
268#ifdef NDEBUG
269 // Make *this consistent and empty. Shouldn't be necessary, but better safe
270 // than sorry.
271 size_ = 0;
272 capacity_ = 0;
273#else
274 // Ensure that *this is always inconsistent, to provoke bugs.
275 size_ = 1;
276 capacity_ = 0;
277#endif
278 }
279
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000280 size_t size_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000281 size_t capacity_;
kwiberg8fb35572016-02-11 13:36:43 -0800282 std::unique_ptr<uint8_t[]> data_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283};
284
285} // namespace rtc
286
287#endif // WEBRTC_BASE_BUFFER_H_