/Users/deen/code/yugabyte-db/src/yb/util/byte_buffer.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #ifndef YB_UTIL_BYTE_BUFFER_H |
15 | | #define YB_UTIL_BYTE_BUFFER_H |
16 | | |
17 | | #include <cstddef> |
18 | | #include <string> |
19 | | |
20 | | #include "yb/util/slice.h" |
21 | | |
22 | | namespace yb { |
23 | | |
24 | | // Utility class to store arbitrary amount of byte with inplace buffer of specified size. |
25 | | template <size_t SmallLen> |
26 | | class ByteBuffer { |
27 | | public: |
28 | | static_assert(SmallLen >= sizeof(void*), "Too small buffer"); |
29 | | |
30 | 702M | ByteBuffer() : size_(0) {} |
31 | | |
32 | 431k | explicit ByteBuffer(const std::string& str) { |
33 | 431k | Assign(str.c_str(), str.size()); |
34 | 431k | } |
35 | | |
36 | | void operator=(const std::string& str) { |
37 | | Assign(str.c_str(), str.size()); |
38 | | } |
39 | | |
40 | 818M | explicit ByteBuffer(const Slice& slice) { |
41 | 818M | Assign(slice.cdata(), slice.cend()); |
42 | 818M | } |
43 | | |
44 | 107 | void operator=(const Slice& slice) { |
45 | 107 | Assign(slice.cdata(), slice.cend()); |
46 | 107 | } |
47 | | |
48 | 1.04G | ByteBuffer(const ByteBuffer<SmallLen>& rhs) { |
49 | 1.04G | Assign(rhs.ptr(), rhs.size_); |
50 | 1.04G | } |
51 | | |
52 | 88.0M | void operator=(const ByteBuffer<SmallLen>& rhs) { |
53 | 88.0M | Assign(rhs.ptr(), rhs.size_); |
54 | 88.0M | } |
55 | | |
56 | 38.0M | ByteBuffer(ByteBuffer<SmallLen>&& rhs) { |
57 | 38.0M | if (!rhs.big()) { |
58 | 37.9M | memcpy(small_buffer_, rhs.small_buffer_, rhs.size_); |
59 | 37.9M | } else { |
60 | 108k | capacity_ = rhs.capacity_; |
61 | 108k | big_buffer_ = rhs.big_buffer_; |
62 | 108k | rhs.capacity_ = SmallLen; |
63 | 108k | } |
64 | | |
65 | 38.0M | size_ = rhs.size_; |
66 | 38.0M | rhs.size_ = 0; |
67 | 38.0M | } |
68 | | |
69 | 20.6M | void operator=(ByteBuffer<SmallLen>&& rhs) { |
70 | 20.6M | if (!rhs.big()) { |
71 | 20.6M | memcpy(ptr(), rhs.small_buffer_, rhs.size_); |
72 | 20.6M | } else { |
73 | 24.4k | if (big()827 ) { |
74 | 24.4k | free(big_buffer_); |
75 | 24.4k | } |
76 | 827 | capacity_ = rhs.capacity_; |
77 | 827 | big_buffer_ = rhs.big_buffer_; |
78 | 827 | rhs.capacity_ = SmallLen; |
79 | 827 | } |
80 | | |
81 | 20.6M | size_ = rhs.size_; |
82 | 20.6M | rhs.size_ = 0; |
83 | 20.6M | } |
84 | | |
85 | 2.61G | ~ByteBuffer() { |
86 | 2.61G | if (big()) { |
87 | 156M | free(big_buffer_); |
88 | 156M | } |
89 | 2.61G | } |
90 | | |
91 | 11.0G | bool empty() const { |
92 | 11.0G | return size_ == 0; |
93 | 11.0G | } |
94 | | |
95 | 3.58G | size_t size() const { |
96 | 3.58G | return size_; |
97 | 3.58G | } |
98 | | |
99 | 453M | void Clear() { |
100 | 453M | size_ = 0; |
101 | 453M | } |
102 | | |
103 | 153M | char& Back() { |
104 | 153M | return ptr()[size_ - 1]; |
105 | 153M | } |
106 | | |
107 | | char Back() const { |
108 | | return ptr()[size_ - 1]; |
109 | | } |
110 | | |
111 | 272 | char& operator[](size_t len) { |
112 | 272 | return ptr()[len]; |
113 | 272 | } |
114 | | |
115 | | char operator[](size_t len) const { |
116 | | return ptr()[len]; |
117 | | } |
118 | | |
119 | 315M | void PopBack() { |
120 | 315M | --size_; |
121 | 315M | } |
122 | | |
123 | 1.56G | void Truncate(size_t new_size) { |
124 | 1.56G | size_ = new_size; |
125 | 1.56G | } |
126 | | |
127 | | void Assign(const Slice& slice) { |
128 | | Assign(slice.cdata(), slice.cend()); |
129 | | } |
130 | | |
131 | 818M | void Assign(const char* a, const char* b) { |
132 | 818M | Assign(a, b - a); |
133 | 818M | } |
134 | | |
135 | 2.19G | void Assign(const char* a, size_t size) { |
136 | 2.19G | DoAppend(0, a, size); |
137 | 2.19G | } |
138 | | |
139 | 1.69G | void Append(const Slice& slice) { |
140 | 1.69G | Append(slice.cdata(), slice.cend()); |
141 | 1.69G | } |
142 | | |
143 | | template <size_t OtherSmallLen> |
144 | 0 | void Append(const ByteBuffer<OtherSmallLen>& rhs) { |
145 | 0 | Append(rhs.ptr(), rhs.size_); |
146 | 0 | } |
147 | | |
148 | 1.71G | void Append(const char* a, const char* b) { |
149 | 1.71G | Append(a, b - a); |
150 | 1.71G | } |
151 | | |
152 | 3.05G | void Append(const char* a, size_t size) { |
153 | 3.05G | DoAppend(size_, a, size); |
154 | 3.05G | } |
155 | | |
156 | 1.20G | void Reserve(size_t capacity) { |
157 | 1.20G | EnsureCapacity(capacity, size_); |
158 | 1.20G | } |
159 | | |
160 | 2.90G | void PushBack(char ch) { |
161 | 2.90G | *(EnsureCapacity(size_ + 1, size_) + size_) = ch; |
162 | 2.90G | ++size_; |
163 | 2.90G | } |
164 | | |
165 | 81.9M | std::string ToStringBuffer() const { |
166 | 81.9M | return AsSlice().ToBuffer(); |
167 | 81.9M | } |
168 | | |
169 | 0 | std::string ToString() const { |
170 | 0 | return AsSlice().ToDebugHexString(); |
171 | 0 | } |
172 | | |
173 | 8.10G | Slice AsSlice() const { |
174 | 8.10G | return Slice(ptr(), size_); |
175 | 8.10G | } |
176 | | |
177 | | // STL container compatibility |
178 | 453M | void clear() { |
179 | 453M | Clear(); |
180 | 453M | } |
181 | | |
182 | | template <class... Args> |
183 | 3.06G | void append(Args&&... args) { |
184 | 3.06G | Append(std::forward<Args>(args)...); |
185 | 3.06G | } Unexecuted instantiation: void yb::ByteBuffer<64ul>::append<yb::ByteBuffer<64ul> const&>(yb::ByteBuffer<64ul> const&) void yb::ByteBuffer<64ul>::append<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Line | Count | Source | 183 | 46.3M | void append(Args&&... args) { | 184 | 46.3M | Append(std::forward<Args>(args)...); | 185 | 46.3M | } |
void yb::ByteBuffer<64ul>::append<yb::Slice const&>(yb::Slice const&) Line | Count | Source | 183 | 1.65G | void append(Args&&... args) { | 184 | 1.65G | Append(std::forward<Args>(args)...); | 185 | 1.65G | } |
void yb::ByteBuffer<64ul>::append<char (&) [8], unsigned long>(char (&) [8], unsigned long&&) Line | Count | Source | 183 | 5.54M | void append(Args&&... args) { | 184 | 5.54M | Append(std::forward<Args>(args)...); | 185 | 5.54M | } |
void yb::ByteBuffer<64ul>::append<char (&) [4], unsigned long>(char (&) [4], unsigned long&&) Line | Count | Source | 183 | 77.8M | void append(Args&&... args) { | 184 | 77.8M | Append(std::forward<Args>(args)...); | 185 | 77.8M | } |
void yb::ByteBuffer<64ul>::append<char (&) [30], char*>(char (&) [30], char*&&) Line | Count | Source | 183 | 11.2M | void append(Args&&... args) { | 184 | 11.2M | Append(std::forward<Args>(args)...); | 185 | 11.2M | } |
void yb::ByteBuffer<64ul>::append<char (&) [16], unsigned long&>(char (&) [16], unsigned long&) Line | Count | Source | 183 | 821M | void append(Args&&... args) { | 184 | 821M | Append(std::forward<Args>(args)...); | 185 | 821M | } |
void yb::ByteBuffer<64ul>::append<char (&) [2], unsigned long>(char (&) [2], unsigned long&&) Line | Count | Source | 183 | 47.4M | void append(Args&&... args) { | 184 | 47.4M | Append(std::forward<Args>(args)...); | 185 | 47.4M | } |
void yb::ByteBuffer<64ul>::append<char const*, unsigned long>(char const*&&, unsigned long&&) Line | Count | Source | 183 | 196M | void append(Args&&... args) { | 184 | 196M | Append(std::forward<Args>(args)...); | 185 | 196M | } |
void yb::ByteBuffer<64ul>::append<char const*&, unsigned long&>(char const*&, unsigned long&) Line | Count | Source | 183 | 201M | void append(Args&&... args) { | 184 | 201M | Append(std::forward<Args>(args)...); | 185 | 201M | } |
|
186 | | |
187 | | template <class... Args> |
188 | 236M | void assign(Args&&... args) { |
189 | 236M | Assign(std::forward<Args>(args)...); |
190 | 236M | } Unexecuted instantiation: void yb::ByteBuffer<64ul>::assign<char const*&, unsigned long&>(char const*&, unsigned long&) void yb::ByteBuffer<64ul>::assign<char const*, unsigned long>(char const*&&, unsigned long&&) Line | Count | Source | 188 | 236M | void assign(Args&&... args) { | 189 | 236M | Assign(std::forward<Args>(args)...); | 190 | 236M | } |
|
191 | | |
192 | 1.20G | void reserve(size_t capacity) { |
193 | 1.20G | Reserve(capacity); |
194 | 1.20G | } |
195 | | |
196 | 2.90G | void push_back(char ch) { |
197 | 2.90G | PushBack(ch); |
198 | 2.90G | } |
199 | | |
200 | 153M | char& back() { |
201 | 153M | return Back(); |
202 | 153M | } |
203 | | |
204 | | char back() const { |
205 | | return Back(); |
206 | | } |
207 | | |
208 | 315M | void pop_back() { |
209 | 315M | PopBack(); |
210 | 315M | } |
211 | | |
212 | | private: |
213 | 5.22G | void DoAppend(size_t keep_size, const char* a, size_t len) { |
214 | 5.22G | size_t new_size = keep_size + len; |
215 | 5.22G | memcpy(EnsureCapacity(new_size, keep_size) + keep_size, a, len); |
216 | 5.22G | size_ = new_size; |
217 | 5.22G | } |
218 | | |
219 | | // Ensures that buffer could contain at least capacity bytes. |
220 | | // In case of relocation, keep_size bytes will be copied. |
221 | 9.28G | char* EnsureCapacity(size_t capacity, size_t keep_size) { |
222 | 9.28G | if (capacity <= capacity_) { |
223 | 9.13G | return ptr(); |
224 | 9.13G | } |
225 | | |
226 | 153M | bool was_big = big(); |
227 | 222M | while ((capacity_ <<= 1ULL) < capacity) {}69.5M |
228 | 153M | char* new_buffer = static_cast<char*>(malloc(capacity_)); |
229 | 153M | char*& big_buffer = big_buffer_; |
230 | 153M | if (was_big) { |
231 | 151k | memcpy(new_buffer, big_buffer, keep_size); |
232 | 151k | free(big_buffer); |
233 | 153M | } else { |
234 | 153M | memcpy(new_buffer, small_buffer_, keep_size); |
235 | 153M | } |
236 | 153M | return big_buffer = new_buffer; |
237 | 9.28G | } |
238 | | |
239 | 21.2G | bool big() const { |
240 | 21.2G | return capacity_ > SmallLen; |
241 | 21.2G | } |
242 | | |
243 | 9.30G | char* ptr() { |
244 | 9.30G | return !big() ? small_buffer_5.17G : big_buffer_4.13G ; |
245 | 9.30G | } |
246 | | |
247 | 9.23G | const char* ptr() const { |
248 | 9.23G | return !big() ? small_buffer_5.91G : big_buffer_3.31G ; |
249 | 9.23G | } |
250 | | |
251 | | size_t capacity_ = SmallLen; |
252 | | size_t size_; |
253 | | union { |
254 | | char small_buffer_[SmallLen]; |
255 | | char* big_buffer_; |
256 | | }; |
257 | | }; |
258 | | |
259 | | template <size_t SmallLenLhs, size_t SmallLenRhs> |
260 | 875M | bool operator<(const ByteBuffer<SmallLenLhs>& lhs, const ByteBuffer<SmallLenRhs>& rhs) { |
261 | 875M | return lhs.AsSlice().compare(rhs.AsSlice()) < 0; |
262 | 875M | } |
263 | | |
264 | | template <size_t SmallLenLhs, size_t SmallLenRhs> |
265 | 210M | bool operator==(const ByteBuffer<SmallLenLhs>& lhs, const ByteBuffer<SmallLenRhs>& rhs) { |
266 | 210M | return lhs.AsSlice() == rhs.AsSlice(); |
267 | 210M | } |
268 | | |
269 | | struct ByteBufferHash { |
270 | | typedef std::size_t result_type; |
271 | | |
272 | | template <size_t SmallLen> |
273 | 202M | result_type operator()(const ByteBuffer<SmallLen>& buffer) const { |
274 | 202M | return buffer.AsSlice().hash(); |
275 | 202M | } |
276 | | }; |
277 | | |
278 | | } // namespace yb |
279 | | |
280 | | #endif // YB_UTIL_BYTE_BUFFER_H |