copy_on_write_buffer.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright 2016 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. #ifndef RTC_BASE_COPY_ON_WRITE_BUFFER_H_
  11. #define RTC_BASE_COPY_ON_WRITE_BUFFER_H_
  12. #include <stdint.h>
  13. #include <algorithm>
  14. #include <cstring>
  15. #include <string>
  16. #include <type_traits>
  17. #include <utility>
  18. #include "api/scoped_refptr.h"
  19. #include "rtc_base/buffer.h"
  20. #include "rtc_base/checks.h"
  21. #include "rtc_base/ref_counted_object.h"
  22. #include "rtc_base/system/rtc_export.h"
  23. namespace rtc {
  24. class RTC_EXPORT CopyOnWriteBuffer {
  25. public:
  26. // An empty buffer.
  27. CopyOnWriteBuffer();
  28. // Share the data with an existing buffer.
  29. CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
  30. // Move contents from an existing buffer.
  31. CopyOnWriteBuffer(CopyOnWriteBuffer&& buf);
  32. // Construct a buffer from a string, convenient for unittests.
  33. CopyOnWriteBuffer(const std::string& s);
  34. // Construct a buffer with the specified number of uninitialized bytes.
  35. explicit CopyOnWriteBuffer(size_t size);
  36. CopyOnWriteBuffer(size_t size, size_t capacity);
  37. // Construct a buffer and copy the specified number of bytes into it. The
  38. // source array may be (const) uint8_t*, int8_t*, or char*.
  39. template <typename T,
  40. typename std::enable_if<
  41. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  42. CopyOnWriteBuffer(const T* data, size_t size)
  43. : CopyOnWriteBuffer(data, size, size) {}
  44. template <typename T,
  45. typename std::enable_if<
  46. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  47. CopyOnWriteBuffer(const T* data, size_t size, size_t capacity)
  48. : CopyOnWriteBuffer(size, capacity) {
  49. if (buffer_) {
  50. std::memcpy(buffer_->data(), data, size);
  51. offset_ = 0;
  52. size_ = size;
  53. }
  54. }
  55. // Construct a buffer from the contents of an array.
  56. template <typename T,
  57. size_t N,
  58. typename std::enable_if<
  59. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  60. CopyOnWriteBuffer(const T (&array)[N]) // NOLINT: runtime/explicit
  61. : CopyOnWriteBuffer(array, N) {}
  62. ~CopyOnWriteBuffer();
  63. // Get a pointer to the data. Just .data() will give you a (const) uint8_t*,
  64. // but you may also use .data<int8_t>() and .data<char>().
  65. template <typename T = uint8_t,
  66. typename std::enable_if<
  67. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  68. const T* data() const {
  69. return cdata<T>();
  70. }
  71. // Get writable pointer to the data. This will create a copy of the underlying
  72. // data if it is shared with other buffers.
  73. template <typename T = uint8_t,
  74. typename std::enable_if<
  75. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  76. T* data() {
  77. RTC_DCHECK(IsConsistent());
  78. if (!buffer_) {
  79. return nullptr;
  80. }
  81. UnshareAndEnsureCapacity(capacity());
  82. return buffer_->data<T>() + offset_;
  83. }
  84. // Get const pointer to the data. This will not create a copy of the
  85. // underlying data if it is shared with other buffers.
  86. template <typename T = uint8_t,
  87. typename std::enable_if<
  88. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  89. const T* cdata() const {
  90. RTC_DCHECK(IsConsistent());
  91. if (!buffer_) {
  92. return nullptr;
  93. }
  94. return buffer_->data<T>() + offset_;
  95. }
  96. size_t size() const {
  97. RTC_DCHECK(IsConsistent());
  98. return size_;
  99. }
  100. size_t capacity() const {
  101. RTC_DCHECK(IsConsistent());
  102. return buffer_ ? buffer_->capacity() - offset_ : 0;
  103. }
  104. CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
  105. RTC_DCHECK(IsConsistent());
  106. RTC_DCHECK(buf.IsConsistent());
  107. if (&buf != this) {
  108. buffer_ = buf.buffer_;
  109. offset_ = buf.offset_;
  110. size_ = buf.size_;
  111. }
  112. return *this;
  113. }
  114. CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
  115. RTC_DCHECK(IsConsistent());
  116. RTC_DCHECK(buf.IsConsistent());
  117. buffer_ = std::move(buf.buffer_);
  118. offset_ = buf.offset_;
  119. size_ = buf.size_;
  120. buf.offset_ = 0;
  121. buf.size_ = 0;
  122. return *this;
  123. }
  124. bool operator==(const CopyOnWriteBuffer& buf) const;
  125. bool operator!=(const CopyOnWriteBuffer& buf) const {
  126. return !(*this == buf);
  127. }
  128. uint8_t& operator[](size_t index) {
  129. RTC_DCHECK_LT(index, size());
  130. return data()[index];
  131. }
  132. uint8_t operator[](size_t index) const {
  133. RTC_DCHECK_LT(index, size());
  134. return cdata()[index];
  135. }
  136. // Replace the contents of the buffer. Accepts the same types as the
  137. // constructors.
  138. template <typename T,
  139. typename std::enable_if<
  140. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  141. void SetData(const T* data, size_t size) {
  142. RTC_DCHECK(IsConsistent());
  143. if (!buffer_) {
  144. buffer_ = size > 0 ? new RefCountedObject<Buffer>(data, size) : nullptr;
  145. } else if (!buffer_->HasOneRef()) {
  146. buffer_ = new RefCountedObject<Buffer>(data, size, capacity());
  147. } else {
  148. buffer_->SetData(data, size);
  149. }
  150. offset_ = 0;
  151. size_ = size;
  152. RTC_DCHECK(IsConsistent());
  153. }
  154. template <typename T,
  155. size_t N,
  156. typename std::enable_if<
  157. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  158. void SetData(const T (&array)[N]) {
  159. SetData(array, N);
  160. }
  161. void SetData(const CopyOnWriteBuffer& buf) {
  162. RTC_DCHECK(IsConsistent());
  163. RTC_DCHECK(buf.IsConsistent());
  164. if (&buf != this) {
  165. buffer_ = buf.buffer_;
  166. offset_ = buf.offset_;
  167. size_ = buf.size_;
  168. }
  169. }
  170. // Append data to the buffer. Accepts the same types as the constructors.
  171. template <typename T,
  172. typename std::enable_if<
  173. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  174. void AppendData(const T* data, size_t size) {
  175. RTC_DCHECK(IsConsistent());
  176. if (!buffer_) {
  177. buffer_ = new RefCountedObject<Buffer>(data, size);
  178. offset_ = 0;
  179. size_ = size;
  180. RTC_DCHECK(IsConsistent());
  181. return;
  182. }
  183. UnshareAndEnsureCapacity(std::max(capacity(), size_ + size));
  184. buffer_->SetSize(offset_ +
  185. size_); // Remove data to the right of the slice.
  186. buffer_->AppendData(data, size);
  187. size_ += size;
  188. RTC_DCHECK(IsConsistent());
  189. }
  190. template <typename T,
  191. size_t N,
  192. typename std::enable_if<
  193. internal::BufferCompat<uint8_t, T>::value>::type* = nullptr>
  194. void AppendData(const T (&array)[N]) {
  195. AppendData(array, N);
  196. }
  197. void AppendData(const CopyOnWriteBuffer& buf) {
  198. AppendData(buf.data(), buf.size());
  199. }
  200. // 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.
  204. void SetSize(size_t size);
  205. // Ensure that the buffer size can be increased to at least capacity without
  206. // further reallocation. (Of course, this operation might need to reallocate
  207. // the buffer.)
  208. void EnsureCapacity(size_t capacity);
  209. // Resets the buffer to zero size without altering capacity. Works even if the
  210. // buffer has been moved from.
  211. void Clear();
  212. // Swaps two buffers.
  213. friend void swap(CopyOnWriteBuffer& a, CopyOnWriteBuffer& b) {
  214. std::swap(a.buffer_, b.buffer_);
  215. std::swap(a.offset_, b.offset_);
  216. std::swap(a.size_, b.size_);
  217. }
  218. CopyOnWriteBuffer Slice(size_t offset, size_t length) const {
  219. CopyOnWriteBuffer slice(*this);
  220. RTC_DCHECK_LE(offset, size_);
  221. RTC_DCHECK_LE(length + offset, size_);
  222. slice.offset_ += offset;
  223. slice.size_ = length;
  224. return slice;
  225. }
  226. private:
  227. // Create a copy of the underlying data if it is referenced from other Buffer
  228. // objects or there is not enough capacity.
  229. void UnshareAndEnsureCapacity(size_t new_capacity);
  230. // Pre- and postcondition of all methods.
  231. bool IsConsistent() const {
  232. if (buffer_) {
  233. return buffer_->capacity() > 0 && offset_ <= buffer_->size() &&
  234. offset_ + size_ <= buffer_->size();
  235. } else {
  236. return size_ == 0 && offset_ == 0;
  237. }
  238. }
  239. // buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
  240. scoped_refptr<RefCountedObject<Buffer>> buffer_;
  241. // This buffer may represent a slice of a original data.
  242. size_t offset_; // Offset of a current slice in the original data in buffer_.
  243. // Should be 0 if the buffer_ is empty.
  244. size_t size_; // Size of a current slice in the original data in buffer_.
  245. // Should be 0 if the buffer_ is empty.
  246. };
  247. } // namespace rtc
  248. #endif // RTC_BASE_COPY_ON_WRITE_BUFFER_H_