C/C++ API Reference
Loading...
Searching...
No Matches
byte_builder.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <algorithm>
17#include <array>
18#include <cstddef>
19#include <cstring>
20
21#include "pw_bytes/bit.h"
22#include "pw_bytes/endian.h"
23#include "pw_bytes/span.h"
24#include "pw_containers/iterator.h"
25#include "pw_preprocessor/compiler.h"
26#include "pw_status/status.h"
27#include "pw_status/status_with_size.h"
28
29namespace pw {
30
32
41 public:
45 class iterator {
46 public:
47 using difference_type = ptrdiff_t;
48 using value_type = std::byte;
49 using element_type = const std::byte;
50 using pointer = const std::byte*;
51 using reference = const std::byte&;
52 using iterator_category = containers::contiguous_iterator_tag;
53
54 explicit constexpr iterator(const std::byte* byte_ptr = nullptr)
55 : byte_(byte_ptr) {}
56
57 constexpr iterator& operator++() {
58 byte_ += 1;
59 return *this;
60 }
61
62 constexpr iterator operator++(int) {
63 iterator previous(byte_);
64 operator++();
65 return previous;
66 }
67
68 constexpr iterator& operator--() {
69 byte_ -= 1;
70 return *this;
71 }
72
73 constexpr iterator operator--(int) {
74 iterator previous(byte_);
75 operator--();
76 return previous;
77 }
78
79 constexpr iterator& operator+=(int n) {
80 byte_ += n;
81 return *this;
82 }
83
84 constexpr iterator operator+(int n) const { return iterator(byte_ + n); }
85
86 constexpr iterator& operator-=(int n) { return operator+=(-n); }
87
88 constexpr iterator operator-(int n) const { return iterator(byte_ - n); }
89
90 constexpr difference_type operator-(const iterator& rhs) const {
91 return byte_ - rhs.byte_;
92 }
93
94 constexpr reference operator*() const { return *byte_; }
95
96 constexpr pointer operator->() const { return byte_; }
97
98 constexpr reference operator[](int index) const { return byte_[index]; }
99
100 constexpr bool operator==(const iterator& rhs) const {
101 return byte_ == rhs.byte_;
102 }
103
104 constexpr bool operator!=(const iterator& rhs) const {
105 return byte_ != rhs.byte_;
106 }
107
108 constexpr bool operator<(const iterator& rhs) const {
109 return byte_ < rhs.byte_;
110 }
111
112 constexpr bool operator>(const iterator& rhs) const {
113 return byte_ > rhs.byte_;
114 }
115
116 constexpr bool operator<=(const iterator& rhs) const {
117 return !operator>(rhs);
118 }
119
120 constexpr bool operator>=(const iterator& rhs) const {
121 return !operator<(rhs);
122 }
123
126 int8_t PeekInt8() const { return static_cast<int8_t>(PeekUint8()); }
127
128 uint8_t PeekUint8() const {
129 return bytes::ReadInOrder<uint8_t>(endian::little, byte_);
130 }
131
132 int16_t PeekInt16(endian order = endian::little) const {
133 return static_cast<int16_t>(PeekUint16(order));
134 }
135
136 uint16_t PeekUint16(endian order = endian::little) const {
137 return bytes::ReadInOrder<uint16_t>(order, byte_);
138 }
139
140 int32_t PeekInt32(endian order = endian::little) const {
141 return static_cast<int32_t>(PeekUint32(order));
142 }
143
144 uint32_t PeekUint32(endian order = endian::little) const {
145 return bytes::ReadInOrder<uint32_t>(order, byte_);
146 }
147
148 int64_t PeekInt64(endian order = endian::little) const {
149 return static_cast<int64_t>(PeekUint64(order));
150 }
151
152 uint64_t PeekUint64(endian order = endian::little) const {
153 return bytes::ReadInOrder<uint64_t>(order, byte_);
154 }
155
159 int8_t ReadInt8() { return static_cast<int8_t>(ReadUint8()); }
160
161 uint8_t ReadUint8() {
162 uint8_t value = bytes::ReadInOrder<uint8_t>(endian::little, byte_);
163 byte_ += 1;
164 return value;
165 }
166
167 int16_t ReadInt16(endian order = endian::little) {
168 return static_cast<int16_t>(ReadUint16(order));
169 }
170
171 uint16_t ReadUint16(endian order = endian::little) {
172 uint16_t value = bytes::ReadInOrder<uint16_t>(order, byte_);
173 byte_ += 2;
174 return value;
175 }
176
177 int32_t ReadInt32(endian order = endian::little) {
178 return static_cast<int32_t>(ReadUint32(order));
179 }
180
181 uint32_t ReadUint32(endian order = endian::little) {
182 uint32_t value = bytes::ReadInOrder<uint32_t>(order, byte_);
183 byte_ += 4;
184 return value;
185 }
186
187 int64_t ReadInt64(endian order = endian::little) {
188 return static_cast<int64_t>(ReadUint64(order));
189 }
190
191 uint64_t ReadUint64(endian order = endian::little) {
192 uint64_t value = bytes::ReadInOrder<uint64_t>(order, byte_);
193 byte_ += 8;
194 return value;
195 }
196
197 private:
198 const std::byte* byte_;
199 };
200
201 using element_type = const std::byte;
202 using value_type = std::byte;
203 using pointer = std::byte*;
204 using reference = std::byte&;
205 using iterator = iterator;
206 using const_iterator = iterator;
207
209 constexpr ByteBuilder(ByteSpan buffer) : buffer_(buffer), size_(0) {}
210
213 ByteBuilder(const ByteBuilder&) = delete;
214
215 ByteBuilder& operator=(const ByteBuilder&) = delete;
216
218 const std::byte* data() const { return buffer_.data(); }
219
229 Status status() const { return status_; }
230
233 return StatusWithSize(status_, size_);
234 }
235
237 bool ok() const { return status_.ok(); }
238
240 bool empty() const { return size() == 0u; }
241
243 size_t size() const { return size_; }
244
246 size_t max_size() const { return buffer_.size(); }
247
249 void clear() {
250 size_ = 0;
251 status_ = OkStatus();
252 }
253
255 void clear_status() { status_ = OkStatus(); }
256
259 void push_back(std::byte b) { append(1, b); }
260
263 void pop_back() PW_NO_SANITIZE("unsigned-integer-overflow") {
264 resize(size() - 1);
265 }
266
268 const_iterator begin() const { return iterator(data()); }
269 const_iterator cbegin() const { return begin(); }
270
272 const_iterator end() const { return iterator(data() + size()); }
273 const_iterator cend() const { return end(); }
274
276 const std::byte& front() const { return buffer_[0]; }
277 const std::byte& back() const { return buffer_[size() - 1]; }
278
280 ByteBuilder& append(size_t count, std::byte b);
281
285 ByteBuilder& append(const void* bytes, size_t count);
286
289 return append(bytes.data(), bytes.size());
290 }
291
294 void resize(size_t new_size);
295
297 ByteBuilder& PutUint8(uint8_t val) { return WriteInOrder(val); }
298
299 ByteBuilder& PutInt8(int8_t val) { return WriteInOrder(val); }
300
302 ByteBuilder& PutUint16(uint16_t value, endian order = endian::little) {
303 return WriteInOrder(bytes::ConvertOrderTo(order, value));
304 }
305
306 ByteBuilder& PutInt16(int16_t value, endian order = endian::little) {
307 return PutUint16(static_cast<uint16_t>(value), order);
308 }
309
311 ByteBuilder& PutUint32(uint32_t value, endian order = endian::little) {
312 return WriteInOrder(bytes::ConvertOrderTo(order, value));
313 }
314
315 ByteBuilder& PutInt32(int32_t value, endian order = endian::little) {
316 return PutUint32(static_cast<uint32_t>(value), order);
317 }
318
320 ByteBuilder& PutUint64(uint64_t value, endian order = endian::little) {
321 return WriteInOrder(bytes::ConvertOrderTo(order, value));
322 }
323
324 ByteBuilder& PutInt64(int64_t value, endian order = endian::little) {
325 return PutUint64(static_cast<uint64_t>(value), order);
326 }
327
328 protected:
330 constexpr ByteBuilder(const ByteSpan& buffer, const ByteBuilder& other)
331 : buffer_(buffer), size_(other.size_), status_(other.status_) {}
332
333 void CopySizeAndStatus(const ByteBuilder& other) {
334 size_ = other.size_;
335 status_ = other.status_;
336 }
337
338 private:
339 template <typename T>
340 ByteBuilder& WriteInOrder(T value) {
341 return append(&value, sizeof(value));
342 }
343 size_t ResizeForAppend(size_t bytes_to_append);
344
345 const ByteSpan buffer_;
346
347 size_t size_;
348 Status status_;
349};
350
352template <size_t kSizeBytes>
353class ByteBuffer : public ByteBuilder {
354 public:
355 ByteBuffer() : ByteBuilder(buffer_) {}
356
357 // Implicit copy constructors are not provided in order to prevent
358 // accidental copies of data when passing around ByteByffers.
359 //
360 // Copy assignment, however, is provided, as it requires the user to
361 // explicitly declare a separate local.
362 ByteBuffer(ByteBuffer& other) = delete;
363
364 template <size_t kOtherSizeBytes>
365 ByteBuffer& operator=(const ByteBuffer<kOtherSizeBytes>& other) {
366 assign<kOtherSizeBytes>(other);
367 return *this;
368 }
369
370 ByteBuffer& operator=(const ByteBuffer& other) {
371 assign<kSizeBytes>(other);
372 return *this;
373 }
374
375 template <size_t kOtherSizeBytes>
376 ByteBuffer& assign(const ByteBuffer<kOtherSizeBytes>& other) {
378 "A ByteBuffer cannot be copied into a smaller buffer");
379 CopySizeAndStatus(other);
380 CopyContents(other);
381 return *this;
382 }
383
385 ByteBuffer(ByteBuffer&& other) = delete;
386
388 ByteBuffer& operator=(ByteBuffer&& other) = delete;
389
392 static constexpr size_t max_size() { return kSizeBytes; }
393
396 template <typename... Args>
397 ByteBuffer& append(Args&&... args) {
398 ByteBuilder::append(std::forward<Args>(args)...);
399 return *this;
400 }
401
402 private:
403 template <size_t kOtherSize>
404 void CopyContents(const ByteBuffer<kOtherSize>& other) {
405 std::memcpy(buffer_.data(), other.data(), other.size());
406 }
407
408 std::array<std::byte, kSizeBytes> buffer_;
409};
410
411constexpr ByteBuilder::iterator operator+(int n, ByteBuilder::iterator it) {
412 return it + n;
413}
414
416
417} // namespace pw
ByteBuffers declare a buffer along with a ByteBuilder.
Definition: byte_builder.h:353
static constexpr size_t max_size()
Definition: byte_builder.h:392
ByteBuffer & append(Args &&... args)
Definition: byte_builder.h:397
ByteBuffer & operator=(ByteBuffer &&other)=delete
ByteBuffers are not movable: the underlying data must be copied.
ByteBuffer(ByteBuffer &&other)=delete
ByteBuffers are not movable: the underlying data must be copied.
Definition: byte_builder.h:45
int8_t PeekInt8() const
Definition: byte_builder.h:126
int8_t ReadInt8()
Definition: byte_builder.h:159
Definition: byte_builder.h:40
void pop_back()
Definition: byte_builder.h:263
void resize(size_t new_size)
ByteBuilder & append(size_t count, std::byte b)
Appends the provided byte count times.
Status status() const
Definition: byte_builder.h:229
ByteBuilder & PutUint32(uint32_t value, endian order=endian::little)
Put methods for inserting different 32-bit ints.
Definition: byte_builder.h:311
void clear_status()
Sets the statuses to OkStatus();.
Definition: byte_builder.h:255
size_t size() const
Returns the current length of the bytes.
Definition: byte_builder.h:243
const std::byte & front() const
Front and Back C++ container functions.
Definition: byte_builder.h:276
void clear()
Clears the bytes and resets its error state.
Definition: byte_builder.h:249
bool ok() const
True if status() is OkStatus().
Definition: byte_builder.h:237
ByteBuilder & PutUint64(uint64_t value, endian order=endian::little)
Put methods for inserting different 64-bit ints.
Definition: byte_builder.h:320
bool empty() const
True if the bytes builder is empty.
Definition: byte_builder.h:240
const std::byte * data() const
Returns the contents of the bytes buffer.
Definition: byte_builder.h:218
void push_back(std::byte b)
Definition: byte_builder.h:259
ByteBuilder & PutUint8(uint8_t val)
Put methods for inserting different 8-bit ints.
Definition: byte_builder.h:297
ByteBuilder & append(const void *bytes, size_t count)
const_iterator end() const
End of bytebuffer wrapped in iterator type.
Definition: byte_builder.h:272
ByteBuilder & append(ConstByteSpan bytes)
Appends bytes from a byte span that calls the pointer/length version.
Definition: byte_builder.h:288
const_iterator begin() const
Root of bytebuffer wrapped in iterator type.
Definition: byte_builder.h:268
StatusWithSize status_with_size() const
Returns status() and size() as a StatusWithSize.
Definition: byte_builder.h:232
ByteBuilder(const ByteBuilder &)=delete
constexpr ByteBuilder(const ByteSpan &buffer, const ByteBuilder &other)
Functions to support ByteBuffer copies.
Definition: byte_builder.h:330
ByteBuilder & PutUint16(uint16_t value, endian order=endian::little)
Put methods for inserting different 16-bit ints.
Definition: byte_builder.h:302
size_t max_size() const
Returns the maximum length of the bytes.
Definition: byte_builder.h:246
constexpr ByteBuilder(ByteSpan buffer)
Creates an empty ByteBuilder.
Definition: byte_builder.h:209
Definition: status.h:120
constexpr bool ok() const
Definition: status.h:346
Definition: status_with_size.h:51
constexpr T ConvertOrderTo(endian to_endianness, T value)
Definition: endian.h:131
#define PW_NO_SANITIZE(check)
Definition: compiler.h:158
constexpr Status OkStatus()
Definition: status.h:450
The Pigweed namespace.
Definition: alignment.h:27