blob: 0ef1e3b5c8a70a99068cbcf2ce32ac5e5da8d06f [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 <cassert>
15#include <cstring>
kwiberg8fb35572016-02-11 13:36:43 -080016#include <memory>
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"
kwiberg8fb35572016-02-11 13:36:43 -080021#include "webrtc/base/constructormagic.h"
kwiberg36220ae2016-01-12 07:24:19 -080022#include "webrtc/base/deprecation.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000023
24namespace rtc {
25
Karl Wiberg94784372015-04-20 14:03:07 +020026namespace internal {
27
28// (Internal; please don't use outside this file.) ByteType<T>::t is int if T
29// is uint8_t, int8_t, or char; otherwise, it's a compilation error. Use like
30// this:
31//
32// template <typename T, typename ByteType<T>::t = 0>
33// void foo(T* x);
34//
35// to let foo<T> be defined only for byte-sized integers.
36template <typename T>
37struct ByteType {
38 private:
39 static int F(uint8_t*);
40 static int F(int8_t*);
41 static int F(char*);
42
43 public:
44 using t = decltype(F(static_cast<T*>(nullptr)));
45};
46
47} // namespace internal
48
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049// Basic buffer class, can be grown and shrunk dynamically.
50// Unlike std::string/vector, does not initialize data when expanding capacity.
noahric27dfe202015-10-23 06:01:10 -070051class Buffer {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052 public:
Karl Wiberg94784372015-04-20 14:03:07 +020053 Buffer(); // An empty buffer.
54 Buffer(const Buffer& buf); // Copy size and contents of an existing buffer.
55 Buffer(Buffer&& buf); // Move contents from an existing buffer.
56
57 // Construct a buffer with the specified number of uninitialized bytes.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +000058 explicit Buffer(size_t size);
Karl Wiberg94784372015-04-20 14:03:07 +020059 Buffer(size_t size, size_t capacity);
60
61 // Construct a buffer and copy the specified number of bytes into it. The
62 // source array may be (const) uint8_t*, int8_t*, or char*.
Karl Wibergc56ac1e2015-05-04 14:54:55 +020063 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020064 Buffer(const T* data, size_t size)
65 : Buffer(data, size, size) {}
ossub01c7812016-02-24 01:05:56 -080066
Karl Wibergc56ac1e2015-05-04 14:54:55 +020067 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020068 Buffer(const T* data, size_t size, size_t capacity)
69 : Buffer(size, capacity) {
70 std::memcpy(data_.get(), data, size);
71 }
72
73 // Construct a buffer from the contents of an array.
74 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
75 Buffer(const T(&array)[N])
76 : Buffer(array, N) {}
77
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000078 ~Buffer();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000079
Karl Wibergc56ac1e2015-05-04 14:54:55 +020080 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
81 // but you may also use .data<int8_t>() and .data<char>().
82 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020083 const T* data() const {
84 assert(IsConsistent());
85 return reinterpret_cast<T*>(data_.get());
86 }
ossub01c7812016-02-24 01:05:56 -080087
Karl Wibergc56ac1e2015-05-04 14:54:55 +020088 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020089 T* data() {
90 assert(IsConsistent());
91 return reinterpret_cast<T*>(data_.get());
92 }
93
94 size_t size() const {
95 assert(IsConsistent());
96 return size_;
97 }
ossub01c7812016-02-24 01:05:56 -080098
Karl Wiberg94784372015-04-20 14:03:07 +020099 size_t capacity() const {
100 assert(IsConsistent());
101 return capacity_;
102 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000103
104 Buffer& operator=(const Buffer& buf) {
Karl Wiberg94784372015-04-20 14:03:07 +0200105 if (&buf != this)
106 SetData(buf.data(), buf.size());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107 return *this;
108 }
ossub01c7812016-02-24 01:05:56 -0800109
Karl Wiberg94784372015-04-20 14:03:07 +0200110 Buffer& operator=(Buffer&& buf) {
111 assert(IsConsistent());
112 assert(buf.IsConsistent());
113 size_ = buf.size_;
114 capacity_ = buf.capacity_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800115 data_ = std::move(buf.data_);
Karl Wiberg94784372015-04-20 14:03:07 +0200116 buf.OnMovedFrom();
117 return *this;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118 }
119
Karl Wiberg94784372015-04-20 14:03:07 +0200120 bool operator==(const Buffer& buf) const {
121 assert(IsConsistent());
122 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123 }
Karl Wiberg94784372015-04-20 14:03:07 +0200124
125 bool operator!=(const Buffer& buf) const { return !(*this == buf); }
126
ossub01c7812016-02-24 01:05:56 -0800127 // The SetData functions replace the contents of the buffer. They accept the
128 // same input types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200129 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200130 void SetData(const T* data, size_t size) {
131 assert(IsConsistent());
132 size_ = 0;
133 AppendData(data, size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134 }
ossub01c7812016-02-24 01:05:56 -0800135
Karl Wiberg94784372015-04-20 14:03:07 +0200136 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
137 void SetData(const T(&array)[N]) {
138 SetData(array, N);
139 }
ossub01c7812016-02-24 01:05:56 -0800140
Karl Wiberg94784372015-04-20 14:03:07 +0200141 void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); }
142
ossub01c7812016-02-24 01:05:56 -0800143 // Replace the data in the buffer with at most |max_bytes| of data, using the
144 // function |setter|, which should have the following signature:
145 // size_t setter(ArrayView<T> view)
146 // |setter| is given an appropriately typed ArrayView of the area in which to
147 // write the data (i.e. starting at the beginning of the buffer) and should
148 // return the number of bytes actually written. This number must be <=
149 // |max_bytes|.
150 template <typename T = uint8_t, typename F,
151 typename internal::ByteType<T>::t = 0>
152 size_t SetData(size_t max_bytes, F&& setter) {
153 RTC_DCHECK(IsConsistent());
154 size_ = 0;
155 return AppendData<T>(max_bytes, std::forward<F>(setter));
156 }
157
158 // The AppendData functions adds data to the end of the buffer. They accept
159 // the same input types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200160 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200161 void AppendData(const T* data, size_t size) {
162 assert(IsConsistent());
163 const size_t new_size = size_ + size;
164 EnsureCapacity(new_size);
165 std::memcpy(data_.get() + size_, data, size);
166 size_ = new_size;
167 assert(IsConsistent());
168 }
ossub01c7812016-02-24 01:05:56 -0800169
Karl Wiberg94784372015-04-20 14:03:07 +0200170 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
171 void AppendData(const T(&array)[N]) {
172 AppendData(array, N);
173 }
ossub01c7812016-02-24 01:05:56 -0800174
Karl Wiberg94784372015-04-20 14:03:07 +0200175 void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); }
176
ossub01c7812016-02-24 01:05:56 -0800177 // Append at most |max_bytes| of data to the end of the buffer, using the
178 // function |setter|, which should have the following signature:
179 // size_t setter(ArrayView<T> view)
180 // |setter| is given an appropriately typed ArrayView of the area in which to
181 // write the data (i.e. starting at the former end of the buffer) and should
182 // return the number of bytes actually written. This number must be <=
183 // |max_bytes|.
184 template <typename T = uint8_t, typename F,
185 typename internal::ByteType<T>::t = 0>
186 size_t AppendData(size_t max_bytes, F&& setter) {
187 RTC_DCHECK(IsConsistent());
188 const size_t old_size = size_;
189 SetSize(old_size + max_bytes);
190 T *base_ptr = data<T>() + old_size;
191 size_t written_bytes =
192 setter(rtc::ArrayView<T>(base_ptr, max_bytes));
193
194 RTC_CHECK_LE(written_bytes, max_bytes);
195 size_ = old_size + written_bytes;
196 RTC_DCHECK(IsConsistent());
197 return written_bytes;
198 }
199
Karl Wiberg94784372015-04-20 14:03:07 +0200200 // Sets the size of the buffer. If the new size is smaller than the old, the
201 // buffer contents will be kept but truncated; if the new size is greater,
202 // the existing contents will be kept and the new space will be
203 // uninitialized.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000204 void SetSize(size_t size) {
Karl Wiberg94784372015-04-20 14:03:07 +0200205 EnsureCapacity(size);
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000206 size_ = size;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 }
Karl Wiberg94784372015-04-20 14:03:07 +0200208
209 // Ensure that the buffer size can be increased to at least capacity without
210 // further reallocation. (Of course, this operation might need to reallocate
211 // the buffer.)
212 void EnsureCapacity(size_t capacity) {
213 assert(IsConsistent());
214 if (capacity <= capacity_)
215 return;
kwiberg8fb35572016-02-11 13:36:43 -0800216 std::unique_ptr<uint8_t[]> new_data(new uint8_t[capacity]);
Karl Wiberg94784372015-04-20 14:03:07 +0200217 std::memcpy(new_data.get(), data_.get(), size_);
kwiberg0eb15ed2015-12-17 03:04:15 -0800218 data_ = std::move(new_data);
Karl Wiberg94784372015-04-20 14:03:07 +0200219 capacity_ = capacity;
220 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221 }
222
kwiberg0eb15ed2015-12-17 03:04:15 -0800223 // b.Pass() does the same thing as std::move(b).
kwiberg36220ae2016-01-12 07:24:19 -0800224 // Deprecated; remove in March 2016 (bug 5373).
225 RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); }
ossub01c7812016-02-24 01:05:56 -0800226
kwiberg36220ae2016-01-12 07:24:19 -0800227 Buffer&& DEPRECATED_Pass() {
Karl Wiberg94784372015-04-20 14:03:07 +0200228 assert(IsConsistent());
kwibergcea7c2f2016-01-07 05:52:04 -0800229 return std::move(*this);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000230 }
231
ossu728012e2016-02-19 02:38:32 -0800232 // Resets the buffer to zero size without altering capacity. Works even if the
233 // buffer has been moved from.
Karl Wiberg94784372015-04-20 14:03:07 +0200234 void Clear() {
Karl Wiberg94784372015-04-20 14:03:07 +0200235 size_ = 0;
Karl Wiberg94784372015-04-20 14:03:07 +0200236 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 }
238
Karl Wiberg94784372015-04-20 14:03:07 +0200239 // Swaps two buffers. Also works for buffers that have been moved from.
240 friend void swap(Buffer& a, Buffer& b) {
241 using std::swap;
242 swap(a.size_, b.size_);
243 swap(a.capacity_, b.capacity_);
244 swap(a.data_, b.data_);
245 }
246
247 private:
248 // Precondition for all methods except Clear and the destructor.
249 // Postcondition for all methods except move construction and move
250 // assignment, which leave the moved-from object in a possibly inconsistent
251 // state.
252 bool IsConsistent() const {
253 return (data_ || capacity_ == 0) && capacity_ >= size_;
254 }
255
256 // Called when *this has been moved from. Conceptually it's a no-op, but we
257 // can mutate the state slightly to help subsequent sanity checks catch bugs.
258 void OnMovedFrom() {
259#ifdef NDEBUG
260 // Make *this consistent and empty. Shouldn't be necessary, but better safe
261 // than sorry.
262 size_ = 0;
263 capacity_ = 0;
264#else
265 // Ensure that *this is always inconsistent, to provoke bugs.
266 size_ = 1;
267 capacity_ = 0;
268#endif
269 }
270
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000271 size_t size_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000272 size_t capacity_;
kwiberg8fb35572016-02-11 13:36:43 -0800273 std::unique_ptr<uint8_t[]> data_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274};
275
276} // namespace rtc
277
278#endif // WEBRTC_BASE_BUFFER_H_