blob: ff9bb73d3f998ad3f7cd76fcae320cf521958293 [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 <algorithm> // std::swap (pre-C++11)
15#include <cassert>
16#include <cstring>
17#include <utility> // std::swap (C++11 and later)
kwiberg36220ae2016-01-12 07:24:19 -080018
19#include "webrtc/base/deprecation.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020#include "webrtc/base/scoped_ptr.h"
21
22namespace rtc {
23
Karl Wiberg94784372015-04-20 14:03:07 +020024namespace internal {
25
26// (Internal; please don't use outside this file.) ByteType<T>::t is int if T
27// is uint8_t, int8_t, or char; otherwise, it's a compilation error. Use like
28// this:
29//
30// template <typename T, typename ByteType<T>::t = 0>
31// void foo(T* x);
32//
33// to let foo<T> be defined only for byte-sized integers.
34template <typename T>
35struct ByteType {
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};
44
45} // namespace internal
46
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000047// Basic buffer class, can be grown and shrunk dynamically.
48// Unlike std::string/vector, does not initialize data when expanding capacity.
noahric27dfe202015-10-23 06:01:10 -070049class Buffer {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050 public:
Karl Wiberg94784372015-04-20 14:03:07 +020051 Buffer(); // An empty buffer.
52 Buffer(const Buffer& buf); // Copy size and contents of an existing buffer.
53 Buffer(Buffer&& buf); // Move contents from an existing buffer.
54
55 // Construct a buffer with the specified number of uninitialized bytes.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +000056 explicit Buffer(size_t size);
Karl Wiberg94784372015-04-20 14:03:07 +020057 Buffer(size_t size, size_t capacity);
58
59 // Construct a buffer and copy the specified number of bytes into it. The
60 // source array may be (const) uint8_t*, int8_t*, or char*.
Karl Wibergc56ac1e2015-05-04 14:54:55 +020061 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020062 Buffer(const T* data, size_t size)
63 : Buffer(data, size, size) {}
Karl Wibergc56ac1e2015-05-04 14:54:55 +020064 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020065 Buffer(const T* data, size_t size, size_t capacity)
66 : Buffer(size, capacity) {
67 std::memcpy(data_.get(), data, size);
68 }
69
70 // Construct a buffer from the contents of an array.
71 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
72 Buffer(const T(&array)[N])
73 : Buffer(array, N) {}
74
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000075 ~Buffer();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076
Karl Wibergc56ac1e2015-05-04 14:54:55 +020077 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
78 // but you may also use .data<int8_t>() and .data<char>().
79 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020080 const T* data() const {
81 assert(IsConsistent());
82 return reinterpret_cast<T*>(data_.get());
83 }
Karl Wibergc56ac1e2015-05-04 14:54:55 +020084 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020085 T* data() {
86 assert(IsConsistent());
87 return reinterpret_cast<T*>(data_.get());
88 }
89
90 size_t size() const {
91 assert(IsConsistent());
92 return size_;
93 }
94 size_t capacity() const {
95 assert(IsConsistent());
96 return capacity_;
97 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098
99 Buffer& operator=(const Buffer& buf) {
Karl Wiberg94784372015-04-20 14:03:07 +0200100 if (&buf != this)
101 SetData(buf.data(), buf.size());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102 return *this;
103 }
Karl Wiberg94784372015-04-20 14:03:07 +0200104 Buffer& operator=(Buffer&& buf) {
105 assert(IsConsistent());
106 assert(buf.IsConsistent());
107 size_ = buf.size_;
108 capacity_ = buf.capacity_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800109 data_ = std::move(buf.data_);
Karl Wiberg94784372015-04-20 14:03:07 +0200110 buf.OnMovedFrom();
111 return *this;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000112 }
113
Karl Wiberg94784372015-04-20 14:03:07 +0200114 bool operator==(const Buffer& buf) const {
115 assert(IsConsistent());
116 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 }
Karl Wiberg94784372015-04-20 14:03:07 +0200118
119 bool operator!=(const Buffer& buf) const { return !(*this == buf); }
120
121 // Replace the contents of the buffer. Accepts the same types as the
122 // constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200123 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200124 void SetData(const T* data, size_t size) {
125 assert(IsConsistent());
126 size_ = 0;
127 AppendData(data, size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 }
Karl Wiberg94784372015-04-20 14:03:07 +0200129 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
130 void SetData(const T(&array)[N]) {
131 SetData(array, N);
132 }
133 void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); }
134
135 // Append data to the buffer. Accepts the same types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200136 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200137 void AppendData(const T* data, size_t size) {
138 assert(IsConsistent());
139 const size_t new_size = size_ + size;
140 EnsureCapacity(new_size);
141 std::memcpy(data_.get() + size_, data, size);
142 size_ = new_size;
143 assert(IsConsistent());
144 }
145 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
146 void AppendData(const T(&array)[N]) {
147 AppendData(array, N);
148 }
149 void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); }
150
151 // Sets the size of the buffer. If the new size is smaller than the old, the
152 // buffer contents will be kept but truncated; if the new size is greater,
153 // the existing contents will be kept and the new space will be
154 // uninitialized.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000155 void SetSize(size_t size) {
Karl Wiberg94784372015-04-20 14:03:07 +0200156 EnsureCapacity(size);
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000157 size_ = size;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 }
Karl Wiberg94784372015-04-20 14:03:07 +0200159
160 // Ensure that the buffer size can be increased to at least capacity without
161 // further reallocation. (Of course, this operation might need to reallocate
162 // the buffer.)
163 void EnsureCapacity(size_t capacity) {
164 assert(IsConsistent());
165 if (capacity <= capacity_)
166 return;
167 scoped_ptr<uint8_t[]> new_data(new uint8_t[capacity]);
168 std::memcpy(new_data.get(), data_.get(), size_);
kwiberg0eb15ed2015-12-17 03:04:15 -0800169 data_ = std::move(new_data);
Karl Wiberg94784372015-04-20 14:03:07 +0200170 capacity_ = capacity;
171 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000172 }
173
kwiberg0eb15ed2015-12-17 03:04:15 -0800174 // b.Pass() does the same thing as std::move(b).
kwiberg36220ae2016-01-12 07:24:19 -0800175 // Deprecated; remove in March 2016 (bug 5373).
176 RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); }
177 Buffer&& DEPRECATED_Pass() {
Karl Wiberg94784372015-04-20 14:03:07 +0200178 assert(IsConsistent());
kwibergcea7c2f2016-01-07 05:52:04 -0800179 return std::move(*this);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180 }
181
Karl Wiberg94784372015-04-20 14:03:07 +0200182 // Resets the buffer to zero size and capacity. Works even if the buffer has
183 // been moved from.
184 void Clear() {
185 data_.reset();
186 size_ = 0;
187 capacity_ = 0;
188 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189 }
190
Karl Wiberg94784372015-04-20 14:03:07 +0200191 // Swaps two buffers. Also works for buffers that have been moved from.
192 friend void swap(Buffer& a, Buffer& b) {
193 using std::swap;
194 swap(a.size_, b.size_);
195 swap(a.capacity_, b.capacity_);
196 swap(a.data_, b.data_);
197 }
198
199 private:
200 // Precondition for all methods except Clear and the destructor.
201 // Postcondition for all methods except move construction and move
202 // assignment, which leave the moved-from object in a possibly inconsistent
203 // state.
204 bool IsConsistent() const {
205 return (data_ || capacity_ == 0) && capacity_ >= size_;
206 }
207
208 // Called when *this has been moved from. Conceptually it's a no-op, but we
209 // can mutate the state slightly to help subsequent sanity checks catch bugs.
210 void OnMovedFrom() {
211#ifdef NDEBUG
212 // Make *this consistent and empty. Shouldn't be necessary, but better safe
213 // than sorry.
214 size_ = 0;
215 capacity_ = 0;
216#else
217 // Ensure that *this is always inconsistent, to provoke bugs.
218 size_ = 1;
219 capacity_ = 0;
220#endif
221 }
222
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000223 size_t size_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 size_t capacity_;
Karl Wiberg94784372015-04-20 14:03:07 +0200225 scoped_ptr<uint8_t[]> data_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226};
227
228} // namespace rtc
229
230#endif // WEBRTC_BASE_BUFFER_H_