• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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