blob: 234039607a1c862aa11763936ec236380d3252c5 [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>
kwiberg8fb35572016-02-11 13:36:43 -080017#include <memory>
Karl Wiberg94784372015-04-20 14:03:07 +020018#include <utility> // std::swap (C++11 and later)
kwiberg36220ae2016-01-12 07:24:19 -080019
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) {}
Karl Wibergc56ac1e2015-05-04 14:54:55 +020065 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020066 Buffer(const T* data, size_t size, size_t capacity)
67 : Buffer(size, capacity) {
68 std::memcpy(data_.get(), data, size);
69 }
70
71 // Construct a buffer from the contents of an array.
72 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
73 Buffer(const T(&array)[N])
74 : Buffer(array, N) {}
75
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000076 ~Buffer();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077
Karl Wibergc56ac1e2015-05-04 14:54:55 +020078 // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
79 // but you may also use .data<int8_t>() and .data<char>().
80 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020081 const T* data() const {
82 assert(IsConsistent());
83 return reinterpret_cast<T*>(data_.get());
84 }
Karl Wibergc56ac1e2015-05-04 14:54:55 +020085 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +020086 T* data() {
87 assert(IsConsistent());
88 return reinterpret_cast<T*>(data_.get());
89 }
90
91 size_t size() const {
92 assert(IsConsistent());
93 return size_;
94 }
95 size_t capacity() const {
96 assert(IsConsistent());
97 return capacity_;
98 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099
100 Buffer& operator=(const Buffer& buf) {
Karl Wiberg94784372015-04-20 14:03:07 +0200101 if (&buf != this)
102 SetData(buf.data(), buf.size());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000103 return *this;
104 }
Karl Wiberg94784372015-04-20 14:03:07 +0200105 Buffer& operator=(Buffer&& buf) {
106 assert(IsConsistent());
107 assert(buf.IsConsistent());
108 size_ = buf.size_;
109 capacity_ = buf.capacity_;
kwiberg0eb15ed2015-12-17 03:04:15 -0800110 data_ = std::move(buf.data_);
Karl Wiberg94784372015-04-20 14:03:07 +0200111 buf.OnMovedFrom();
112 return *this;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113 }
114
Karl Wiberg94784372015-04-20 14:03:07 +0200115 bool operator==(const Buffer& buf) const {
116 assert(IsConsistent());
117 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118 }
Karl Wiberg94784372015-04-20 14:03:07 +0200119
120 bool operator!=(const Buffer& buf) const { return !(*this == buf); }
121
122 // Replace the contents of the buffer. Accepts the same types as the
123 // constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200124 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200125 void SetData(const T* data, size_t size) {
126 assert(IsConsistent());
127 size_ = 0;
128 AppendData(data, size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129 }
Karl Wiberg94784372015-04-20 14:03:07 +0200130 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
131 void SetData(const T(&array)[N]) {
132 SetData(array, N);
133 }
134 void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); }
135
136 // Append data to the buffer. Accepts the same types as the constructors.
Karl Wibergc56ac1e2015-05-04 14:54:55 +0200137 template <typename T, typename internal::ByteType<T>::t = 0>
Karl Wiberg94784372015-04-20 14:03:07 +0200138 void AppendData(const T* data, size_t size) {
139 assert(IsConsistent());
140 const size_t new_size = size_ + size;
141 EnsureCapacity(new_size);
142 std::memcpy(data_.get() + size_, data, size);
143 size_ = new_size;
144 assert(IsConsistent());
145 }
146 template <typename T, size_t N, typename internal::ByteType<T>::t = 0>
147 void AppendData(const T(&array)[N]) {
148 AppendData(array, N);
149 }
150 void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); }
151
152 // Sets the size of the buffer. If the new size is smaller than the old, the
153 // buffer contents will be kept but truncated; if the new size is greater,
154 // the existing contents will be kept and the new space will be
155 // uninitialized.
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000156 void SetSize(size_t size) {
Karl Wiberg94784372015-04-20 14:03:07 +0200157 EnsureCapacity(size);
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000158 size_ = size;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 }
Karl Wiberg94784372015-04-20 14:03:07 +0200160
161 // Ensure that the buffer size can be increased to at least capacity without
162 // further reallocation. (Of course, this operation might need to reallocate
163 // the buffer.)
164 void EnsureCapacity(size_t capacity) {
165 assert(IsConsistent());
166 if (capacity <= capacity_)
167 return;
kwiberg8fb35572016-02-11 13:36:43 -0800168 std::unique_ptr<uint8_t[]> new_data(new uint8_t[capacity]);
Karl Wiberg94784372015-04-20 14:03:07 +0200169 std::memcpy(new_data.get(), data_.get(), size_);
kwiberg0eb15ed2015-12-17 03:04:15 -0800170 data_ = std::move(new_data);
Karl Wiberg94784372015-04-20 14:03:07 +0200171 capacity_ = capacity;
172 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000173 }
174
kwiberg0eb15ed2015-12-17 03:04:15 -0800175 // b.Pass() does the same thing as std::move(b).
kwiberg36220ae2016-01-12 07:24:19 -0800176 // Deprecated; remove in March 2016 (bug 5373).
177 RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); }
178 Buffer&& DEPRECATED_Pass() {
Karl Wiberg94784372015-04-20 14:03:07 +0200179 assert(IsConsistent());
kwibergcea7c2f2016-01-07 05:52:04 -0800180 return std::move(*this);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181 }
182
ossu728012e2016-02-19 02:38:32 -0800183 // Resets the buffer to zero size without altering capacity. Works even if the
184 // buffer has been moved from.
Karl Wiberg94784372015-04-20 14:03:07 +0200185 void Clear() {
Karl Wiberg94784372015-04-20 14:03:07 +0200186 size_ = 0;
Karl Wiberg94784372015-04-20 14:03:07 +0200187 assert(IsConsistent());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 }
189
Karl Wiberg94784372015-04-20 14:03:07 +0200190 // Swaps two buffers. Also works for buffers that have been moved from.
191 friend void swap(Buffer& a, Buffer& b) {
192 using std::swap;
193 swap(a.size_, b.size_);
194 swap(a.capacity_, b.capacity_);
195 swap(a.data_, b.data_);
196 }
197
198 private:
199 // Precondition for all methods except Clear and the destructor.
200 // Postcondition for all methods except move construction and move
201 // assignment, which leave the moved-from object in a possibly inconsistent
202 // state.
203 bool IsConsistent() const {
204 return (data_ || capacity_ == 0) && capacity_ >= size_;
205 }
206
207 // Called when *this has been moved from. Conceptually it's a no-op, but we
208 // can mutate the state slightly to help subsequent sanity checks catch bugs.
209 void OnMovedFrom() {
210#ifdef NDEBUG
211 // Make *this consistent and empty. Shouldn't be necessary, but better safe
212 // than sorry.
213 size_ = 0;
214 capacity_ = 0;
215#else
216 // Ensure that *this is always inconsistent, to provoke bugs.
217 size_ = 1;
218 capacity_ = 0;
219#endif
220 }
221
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000222 size_t size_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 size_t capacity_;
kwiberg8fb35572016-02-11 13:36:43 -0800224 std::unique_ptr<uint8_t[]> data_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225};
226
227} // namespace rtc
228
229#endif // WEBRTC_BASE_BUFFER_H_