Pigweed
 
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
39 public:
43 class iterator {
44 public:
45 using difference_type = ptrdiff_t;
46 using value_type = std::byte;
47 using element_type = const std::byte;
48 using pointer = const std::byte*;
49 using reference = const std::byte&;
50 using iterator_category = containers::contiguous_iterator_tag;
51
52 explicit constexpr iterator(const std::byte* byte_ptr = nullptr)
53 : byte_(byte_ptr) {}
54
55 constexpr iterator& operator++() {
56 byte_ += 1;
57 return *this;
58 }
59
60 constexpr iterator operator++(int) {
61 iterator previous(byte_);
62 operator++();
63 return previous;
64 }
65
66 constexpr iterator& operator--() {
67 byte_ -= 1;
68 return *this;
69 }
70
71 constexpr iterator operator--(int) {
72 iterator previous(byte_);
73 operator--();
74 return previous;
75 }
76
77 constexpr iterator& operator+=(int n) {
78 byte_ += n;
79 return *this;
80 }
81
82 constexpr iterator operator+(int n) const { return iterator(byte_ + n); }
83
84 constexpr iterator& operator-=(int n) { return operator+=(-n); }
85
86 constexpr iterator operator-(int n) const { return iterator(byte_ - n); }
87
88 constexpr difference_type operator-(const iterator& rhs) const {
89 return byte_ - rhs.byte_;
90 }
91
92 constexpr reference operator*() const { return *byte_; }
93
94 constexpr pointer operator->() const { return byte_; }
95
96 constexpr reference operator[](int index) const { return byte_[index]; }
97
98 constexpr bool operator==(const iterator& rhs) const {
99 return byte_ == rhs.byte_;
100 }
101
102 constexpr bool operator!=(const iterator& rhs) const {
103 return byte_ != rhs.byte_;
104 }
105
106 constexpr bool operator<(const iterator& rhs) const {
107 return byte_ < rhs.byte_;
108 }
109
110 constexpr bool operator>(const iterator& rhs) const {
111 return byte_ > rhs.byte_;
112 }
113
114 constexpr bool operator<=(const iterator& rhs) const {
115 return !operator>(rhs);
116 }
117
118 constexpr bool operator>=(const iterator& rhs) const {
119 return !operator<(rhs);
120 }
121
124 int8_t PeekInt8() const { return static_cast<int8_t>(PeekUint8()); }
125
126 uint8_t PeekUint8() const {
127 return bytes::ReadInOrder<uint8_t>(endian::little, byte_);
128 }
129
130 int16_t PeekInt16(endian order = endian::little) const {
131 return static_cast<int16_t>(PeekUint16(order));
132 }
133
134 uint16_t PeekUint16(endian order = endian::little) const {
135 return bytes::ReadInOrder<uint16_t>(order, byte_);
136 }
137
138 int32_t PeekInt32(endian order = endian::little) const {
139 return static_cast<int32_t>(PeekUint32(order));
140 }
141
142 uint32_t PeekUint32(endian order = endian::little) const {
143 return bytes::ReadInOrder<uint32_t>(order, byte_);
144 }
145
146 int64_t PeekInt64(endian order = endian::little) const {
147 return static_cast<int64_t>(PeekUint64(order));
148 }
149
150 uint64_t PeekUint64(endian order = endian::little) const {
151 return bytes::ReadInOrder<uint64_t>(order, byte_);
152 }
153
157 int8_t ReadInt8() { return static_cast<int8_t>(ReadUint8()); }
158
159 uint8_t ReadUint8() {
160 uint8_t value = bytes::ReadInOrder<uint8_t>(endian::little, byte_);
161 byte_ += 1;
162 return value;
163 }
164
165 int16_t ReadInt16(endian order = endian::little) {
166 return static_cast<int16_t>(ReadUint16(order));
167 }
168
169 uint16_t ReadUint16(endian order = endian::little) {
170 uint16_t value = bytes::ReadInOrder<uint16_t>(order, byte_);
171 byte_ += 2;
172 return value;
173 }
174
175 int32_t ReadInt32(endian order = endian::little) {
176 return static_cast<int32_t>(ReadUint32(order));
177 }
178
179 uint32_t ReadUint32(endian order = endian::little) {
180 uint32_t value = bytes::ReadInOrder<uint32_t>(order, byte_);
181 byte_ += 4;
182 return value;
183 }
184
185 int64_t ReadInt64(endian order = endian::little) {
186 return static_cast<int64_t>(ReadUint64(order));
187 }
188
189 uint64_t ReadUint64(endian order = endian::little) {
190 uint64_t value = bytes::ReadInOrder<uint64_t>(order, byte_);
191 byte_ += 8;
192 return value;
193 }
194
195 private:
196 const std::byte* byte_;
197 };
198
199 using element_type = const std::byte;
200 using value_type = std::byte;
201 using pointer = std::byte*;
202 using reference = std::byte&;
203 using iterator = iterator;
204 using const_iterator = iterator;
205
207 constexpr ByteBuilder(ByteSpan buffer) : buffer_(buffer), size_(0) {}
208
211 ByteBuilder(const ByteBuilder&) = delete;
212
213 ByteBuilder& operator=(const ByteBuilder&) = delete;
214
216 const std::byte* data() const { return buffer_.data(); }
217
235 Status status() const { return status_; }
236
239 return StatusWithSize(status_, size_);
240 }
241
243 bool ok() const { return status_.ok(); }
244
246 bool empty() const { return size() == 0u; }
247
249 size_t size() const { return size_; }
250
252 size_t max_size() const { return buffer_.size(); }
253
255 void clear() {
256 size_ = 0;
257 status_ = OkStatus();
258 }
259
261 void clear_status() { status_ = OkStatus(); }
262
265 void push_back(std::byte b) { append(1, b); }
266
269 void pop_back() PW_NO_SANITIZE("unsigned-integer-overflow") {
270 resize(size() - 1);
271 }
272
274 const_iterator begin() const { return iterator(data()); }
275 const_iterator cbegin() const { return begin(); }
276
278 const_iterator end() const { return iterator(data() + size()); }
279 const_iterator cend() const { return end(); }
280
282 const std::byte& front() const { return buffer_[0]; }
283 const std::byte& back() const { return buffer_[size() - 1]; }
284
286 ByteBuilder& append(size_t count, std::byte b);
287
291 ByteBuilder& append(const void* bytes, size_t count);
292
294 ByteBuilder& append(ConstByteSpan bytes) {
295 return append(bytes.data(), bytes.size());
296 }
297
300 void resize(size_t new_size);
301
303 ByteBuilder& PutUint8(uint8_t val) { return WriteInOrder(val); }
304
305 ByteBuilder& PutInt8(int8_t val) { return WriteInOrder(val); }
306
308 ByteBuilder& PutUint16(uint16_t value, endian order = endian::little) {
309 return WriteInOrder(bytes::ConvertOrderTo(order, value));
310 }
311
312 ByteBuilder& PutInt16(int16_t value, endian order = endian::little) {
313 return PutUint16(static_cast<uint16_t>(value), order);
314 }
315
317 ByteBuilder& PutUint32(uint32_t value, endian order = endian::little) {
318 return WriteInOrder(bytes::ConvertOrderTo(order, value));
319 }
320
321 ByteBuilder& PutInt32(int32_t value, endian order = endian::little) {
322 return PutUint32(static_cast<uint32_t>(value), order);
323 }
324
326 ByteBuilder& PutUint64(uint64_t value, endian order = endian::little) {
327 return WriteInOrder(bytes::ConvertOrderTo(order, value));
328 }
329
330 ByteBuilder& PutInt64(int64_t value, endian order = endian::little) {
331 return PutUint64(static_cast<uint64_t>(value), order);
332 }
333
334 protected:
336 constexpr ByteBuilder(const ByteSpan& buffer, const ByteBuilder& other)
337 : buffer_(buffer), size_(other.size_), status_(other.status_) {}
338
339 void CopySizeAndStatus(const ByteBuilder& other) {
340 size_ = other.size_;
341 status_ = other.status_;
342 }
343
344 private:
345 template <typename T>
346 ByteBuilder& WriteInOrder(T value) {
347 return append(&value, sizeof(value));
348 }
349 size_t ResizeForAppend(size_t bytes_to_append);
350
351 const ByteSpan buffer_;
352
353 size_t size_;
354 Status status_;
355};
356
358template <size_t kSizeBytes>
359class ByteBuffer : public ByteBuilder {
360 public:
361 ByteBuffer() : ByteBuilder(buffer_) {}
362
363 // Implicit copy constructors are not provided in order to prevent
364 // accidental copies of data when passing around ByteByffers.
365 //
366 // Copy assignment, however, is provided, as it requires the user to
367 // explicitly declare a separate local.
368 ByteBuffer(ByteBuffer& other) = delete;
369
370 template <size_t kOtherSizeBytes>
371 ByteBuffer& operator=(const ByteBuffer<kOtherSizeBytes>& other) {
372 assign<kOtherSizeBytes>(other);
373 return *this;
374 }
375
376 ByteBuffer& operator=(const ByteBuffer& other) {
377 assign<kSizeBytes>(other);
378 return *this;
379 }
380
381 template <size_t kOtherSizeBytes>
382 ByteBuffer& assign(const ByteBuffer<kOtherSizeBytes>& other) {
384 "A ByteBuffer cannot be copied into a smaller buffer");
385 CopySizeAndStatus(other);
386 CopyContents(other);
387 return *this;
388 }
389
391 ByteBuffer(ByteBuffer&& other) = delete;
392
394 ByteBuffer& operator=(ByteBuffer&& other) = delete;
395
398 static constexpr size_t max_size() { return kSizeBytes; }
399
402 template <typename... Args>
403 ByteBuffer& append(Args&&... args) {
404 ByteBuilder::append(std::forward<Args>(args)...);
405 return *this;
406 }
407
408 private:
409 template <size_t kOtherSize>
410 void CopyContents(const ByteBuffer<kOtherSize>& other) {
411 std::memcpy(buffer_.data(), other.data(), other.size());
412 }
413
414 std::array<std::byte, kSizeBytes> buffer_;
415};
416
417constexpr ByteBuilder::iterator operator+(int n, ByteBuilder::iterator it) {
418 return it + n;
419}
420
421} // namespace pw
ByteBuffers declare a buffer along with a ByteBuilder.
Definition: byte_builder.h:359
static constexpr size_t max_size()
Definition: byte_builder.h:398
ByteBuffer & append(Args &&... args)
Definition: byte_builder.h:403
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:43
int8_t PeekInt8() const
Definition: byte_builder.h:124
int8_t ReadInt8()
Definition: byte_builder.h:157
Definition: byte_builder.h:38
void pop_back()
Definition: byte_builder.h:269
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:235
ByteBuilder & PutUint32(uint32_t value, endian order=endian::little)
Put methods for inserting different 32-bit ints.
Definition: byte_builder.h:317
void clear_status()
Sets the statuses to OkStatus();.
Definition: byte_builder.h:261
size_t size() const
Returns the current length of the bytes.
Definition: byte_builder.h:249
const std::byte & front() const
Front and Back C++ container functions.
Definition: byte_builder.h:282
void clear()
Clears the bytes and resets its error state.
Definition: byte_builder.h:255
bool ok() const
True if status() is OkStatus().
Definition: byte_builder.h:243
ByteBuilder & PutUint64(uint64_t value, endian order=endian::little)
Put methods for inserting different 64-bit ints.
Definition: byte_builder.h:326
bool empty() const
True if the bytes builder is empty.
Definition: byte_builder.h:246
const std::byte * data() const
Returns the contents of the bytes buffer.
Definition: byte_builder.h:216
void push_back(std::byte b)
Definition: byte_builder.h:265
ByteBuilder & PutUint8(uint8_t val)
Put methods for inserting different 8-bit ints.
Definition: byte_builder.h:303
ByteBuilder & append(const void *bytes, size_t count)
const_iterator end() const
End of bytebuffer wrapped in iterator type.
Definition: byte_builder.h:278
ByteBuilder & append(ConstByteSpan bytes)
Appends bytes from a byte span that calls the pointer/length version.
Definition: byte_builder.h:294
const_iterator begin() const
Root of bytebuffer wrapped in iterator type.
Definition: byte_builder.h:274
StatusWithSize status_with_size() const
Returns status() and size() as a StatusWithSize.
Definition: byte_builder.h:238
ByteBuilder(const ByteBuilder &)=delete
constexpr ByteBuilder(const ByteSpan &buffer, const ByteBuilder &other)
Functions to support ByteBuffer copies.
Definition: byte_builder.h:336
ByteBuilder & PutUint16(uint16_t value, endian order=endian::little)
Put methods for inserting different 16-bit ints.
Definition: byte_builder.h:308
size_t max_size() const
Returns the maximum length of the bytes.
Definition: byte_builder.h:252
constexpr ByteBuilder(ByteSpan buffer)
Creates an empty ByteBuilder.
Definition: byte_builder.h:207
Definition: status.h:85
constexpr bool ok() const
Definition: status.h:157
Definition: status_with_size.h:49
#define PW_NO_SANITIZE(check)
Definition: compiler.h:155
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
constexpr Status OkStatus()
Definition: status.h:234