1 /* 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 14 #include <algorithm> // std::swap (pre-C++11) 15 #include <cassert> 16 #include <cstring> 17 #include <utility> // std::swap (C++11 and later) 18 19 #include "webrtc/base/deprecation.h" 20 #include "webrtc/base/scoped_ptr.h" 21 22 namespace rtc { 23 24 namespace 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. 34 template <typename T> 35 struct 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 47 // Basic buffer class, can be grown and shrunk dynamically. 48 // Unlike std::string/vector, does not initialize data when expanding capacity. 49 class Buffer { 50 public: 51 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. 56 explicit Buffer(size_t size); 57 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*. 61 template <typename T, typename internal::ByteType<T>::t = 0> Buffer(const T * data,size_t size)62 Buffer(const T* data, size_t size) 63 : Buffer(data, size, size) {} 64 template <typename T, typename internal::ByteType<T>::t = 0> Buffer(const T * data,size_t size,size_t capacity)65 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> Buffer(const T (& array)[N])72 Buffer(const T(&array)[N]) 73 : Buffer(array, N) {} 74 75 ~Buffer(); 76 77 // 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> data()80 const T* data() const { 81 assert(IsConsistent()); 82 return reinterpret_cast<T*>(data_.get()); 83 } 84 template <typename T = uint8_t, typename internal::ByteType<T>::t = 0> data()85 T* data() { 86 assert(IsConsistent()); 87 return reinterpret_cast<T*>(data_.get()); 88 } 89 size()90 size_t size() const { 91 assert(IsConsistent()); 92 return size_; 93 } capacity()94 size_t capacity() const { 95 assert(IsConsistent()); 96 return capacity_; 97 } 98 99 Buffer& operator=(const Buffer& buf) { 100 if (&buf != this) 101 SetData(buf.data(), buf.size()); 102 return *this; 103 } 104 Buffer& operator=(Buffer&& buf) { 105 assert(IsConsistent()); 106 assert(buf.IsConsistent()); 107 size_ = buf.size_; 108 capacity_ = buf.capacity_; 109 data_ = std::move(buf.data_); 110 buf.OnMovedFrom(); 111 return *this; 112 } 113 114 bool operator==(const Buffer& buf) const { 115 assert(IsConsistent()); 116 return size_ == buf.size() && memcmp(data_.get(), buf.data(), size_) == 0; 117 } 118 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. 123 template <typename T, typename internal::ByteType<T>::t = 0> SetData(const T * data,size_t size)124 void SetData(const T* data, size_t size) { 125 assert(IsConsistent()); 126 size_ = 0; 127 AppendData(data, size); 128 } 129 template <typename T, size_t N, typename internal::ByteType<T>::t = 0> SetData(const T (& array)[N])130 void SetData(const T(&array)[N]) { 131 SetData(array, N); 132 } SetData(const Buffer & buf)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. 136 template <typename T, typename internal::ByteType<T>::t = 0> AppendData(const T * data,size_t size)137 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> AppendData(const T (& array)[N])146 void AppendData(const T(&array)[N]) { 147 AppendData(array, N); 148 } AppendData(const Buffer & buf)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. SetSize(size_t size)155 void SetSize(size_t size) { 156 EnsureCapacity(size); 157 size_ = size; 158 } 159 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.) EnsureCapacity(size_t capacity)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_); 169 data_ = std::move(new_data); 170 capacity_ = capacity; 171 assert(IsConsistent()); 172 } 173 174 // b.Pass() does the same thing as std::move(b). 175 // Deprecated; remove in March 2016 (bug 5373). Pass()176 RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); } DEPRECATED_Pass()177 Buffer&& DEPRECATED_Pass() { 178 assert(IsConsistent()); 179 return std::move(*this); 180 } 181 182 // Resets the buffer to zero size and capacity. Works even if the buffer has 183 // been moved from. Clear()184 void Clear() { 185 data_.reset(); 186 size_ = 0; 187 capacity_ = 0; 188 assert(IsConsistent()); 189 } 190 191 // Swaps two buffers. Also works for buffers that have been moved from. swap(Buffer & a,Buffer & b)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. IsConsistent()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. OnMovedFrom()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 223 size_t size_; 224 size_t capacity_; 225 scoped_ptr<uint8_t[]> data_; 226 }; 227 228 } // namespace rtc 229 230 #endif // WEBRTC_BASE_BUFFER_H_ 231