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
11 #include "rtc_base/copy_on_write_buffer.h"
12
13 #include <stddef.h>
14
15 #include "absl/strings/string_view.h"
16
17 namespace rtc {
18
CopyOnWriteBuffer()19 CopyOnWriteBuffer::CopyOnWriteBuffer() : offset_(0), size_(0) {
20 RTC_DCHECK(IsConsistent());
21 }
22
CopyOnWriteBuffer(const CopyOnWriteBuffer & buf)23 CopyOnWriteBuffer::CopyOnWriteBuffer(const CopyOnWriteBuffer& buf)
24 : buffer_(buf.buffer_), offset_(buf.offset_), size_(buf.size_) {}
25
CopyOnWriteBuffer(CopyOnWriteBuffer && buf)26 CopyOnWriteBuffer::CopyOnWriteBuffer(CopyOnWriteBuffer&& buf)
27 : buffer_(std::move(buf.buffer_)), offset_(buf.offset_), size_(buf.size_) {
28 buf.offset_ = 0;
29 buf.size_ = 0;
30 RTC_DCHECK(IsConsistent());
31 }
32
CopyOnWriteBuffer(absl::string_view s)33 CopyOnWriteBuffer::CopyOnWriteBuffer(absl::string_view s)
34 : CopyOnWriteBuffer(s.data(), s.length()) {}
35
CopyOnWriteBuffer(size_t size)36 CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size)
37 : buffer_(size > 0 ? new RefCountedBuffer(size) : nullptr),
38 offset_(0),
39 size_(size) {
40 RTC_DCHECK(IsConsistent());
41 }
42
CopyOnWriteBuffer(size_t size,size_t capacity)43 CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size, size_t capacity)
44 : buffer_(size > 0 || capacity > 0 ? new RefCountedBuffer(size, capacity)
45 : nullptr),
46 offset_(0),
47 size_(size) {
48 RTC_DCHECK(IsConsistent());
49 }
50
51 CopyOnWriteBuffer::~CopyOnWriteBuffer() = default;
52
operator ==(const CopyOnWriteBuffer & buf) const53 bool CopyOnWriteBuffer::operator==(const CopyOnWriteBuffer& buf) const {
54 // Must either be the same view of the same buffer or have the same contents.
55 RTC_DCHECK(IsConsistent());
56 RTC_DCHECK(buf.IsConsistent());
57 return size_ == buf.size_ &&
58 (cdata() == buf.cdata() || memcmp(cdata(), buf.cdata(), size_) == 0);
59 }
60
SetSize(size_t size)61 void CopyOnWriteBuffer::SetSize(size_t size) {
62 RTC_DCHECK(IsConsistent());
63 if (!buffer_) {
64 if (size > 0) {
65 buffer_ = new RefCountedBuffer(size);
66 offset_ = 0;
67 size_ = size;
68 }
69 RTC_DCHECK(IsConsistent());
70 return;
71 }
72
73 if (size <= size_) {
74 size_ = size;
75 return;
76 }
77
78 UnshareAndEnsureCapacity(std::max(capacity(), size));
79 buffer_->SetSize(size + offset_);
80 size_ = size;
81 RTC_DCHECK(IsConsistent());
82 }
83
EnsureCapacity(size_t new_capacity)84 void CopyOnWriteBuffer::EnsureCapacity(size_t new_capacity) {
85 RTC_DCHECK(IsConsistent());
86 if (!buffer_) {
87 if (new_capacity > 0) {
88 buffer_ = new RefCountedBuffer(0, new_capacity);
89 offset_ = 0;
90 size_ = 0;
91 }
92 RTC_DCHECK(IsConsistent());
93 return;
94 } else if (new_capacity <= capacity()) {
95 return;
96 }
97
98 UnshareAndEnsureCapacity(new_capacity);
99 RTC_DCHECK(IsConsistent());
100 }
101
Clear()102 void CopyOnWriteBuffer::Clear() {
103 if (!buffer_)
104 return;
105
106 if (buffer_->HasOneRef()) {
107 buffer_->Clear();
108 } else {
109 buffer_ = new RefCountedBuffer(0, capacity());
110 }
111 offset_ = 0;
112 size_ = 0;
113 RTC_DCHECK(IsConsistent());
114 }
115
UnshareAndEnsureCapacity(size_t new_capacity)116 void CopyOnWriteBuffer::UnshareAndEnsureCapacity(size_t new_capacity) {
117 if (buffer_->HasOneRef() && new_capacity <= capacity()) {
118 return;
119 }
120
121 buffer_ =
122 new RefCountedBuffer(buffer_->data() + offset_, size_, new_capacity);
123 offset_ = 0;
124 RTC_DCHECK(IsConsistent());
125 }
126
127 } // namespace rtc
128