pw_bytes#

Utilities for manipulating binary data

Stable C++ Rust

pw_bytes is a collection of utilities for manipulating binary data.

Dependencies#

  • pw_preprocessor

  • pw_status

  • pw_span

Features#

pw_bytes/packed_ptr.h#

Wrapper type that allows storing data in the least significant bits of a pointer that would otherwise be unused.

template<typename T>
class PackedPtr#

Pointer wrapper that can store extra data in otherwise unused bits.

Pointers to types that have an alignment of more than 1 will always have their least significant bit(s) set to zero. For example, if alignof(T) is 8, than the 3 least significant bits are always 0. In certain contexts where overhead needs to be tightly constrained, reusing these bits and avoiding additional fields may be worth the performance and code size penalties that arise from masking values.

Public Functions

inline constexpr T *get() const#

Returns the pointer.

inline constexpr uintptr_t packed_value() const#

Returns the packed_value packed into the unused bits of the pointer.

inline constexpr void set(T *ptr)#

Sets the pointer without changing the packed value.

inline constexpr void set_packed_value(uintptr_t packed_value)#

Packs a packed_value into the unused bits of the pointer.

Pre:

The given packed_value must fit in the available bits.

pw_bytes/alignment.h#

Functions for aligning sizes and addresses to memory alignment boundaries.

inline bool pw::IsAlignedAs(const void *ptr, size_t alignment)#

Returns whether the given pointer meets the given alignment requirement.

template<typename T>
bool pw::IsAlignedAs(const void *ptr)#

Returns whether the given pointer meets the alignment requirement for the given type.

constexpr size_t pw::AlignDown(uintptr_t value, size_t alignment)#

Returns the value rounded down to the nearest multiple of alignment.

template<typename T>
constexpr T *pw::AlignDown(T *value, size_t alignment)#

Returns the value rounded down to the nearest multiple of alignment.

constexpr size_t pw::AlignUp(uintptr_t value, size_t alignment)#

Returns the value rounded up to the nearest multiple of alignment.

template<typename T>
constexpr T *pw::AlignUp(T *value, size_t alignment)#

Returns the value rounded up to the nearest multiple of alignment.

constexpr size_t pw::Padding(size_t length, size_t alignment)#

Returns the number of padding bytes required to align the provided length.

ByteSpan pw::GetAlignedSubspan(ByteSpan bytes, size_t alignment)#

Returns the largest aligned subspan of a given byte span.

The subspan will start and end on alignment boundaries.

Returns:

A ByteSpan within bytes aligned to alignment, or an empty ByteSpan if alignment was not possible.

pw_bytes/array.h#

Functions for working with byte arrays, primarily for building fixed-size byte arrays at compile time.

pw_bytes/byte_builder.h#

class ByteBuilder#

ByteBuilder facilitates building bytes in a fixed-size buffer. BytesBuilders never overflow. Status is tracked for each operation and an overall status is maintained, which reflects the most recent error.

A ByteBuilder does not own the buffer it writes to. It can be used to write bytes to any buffer. The ByteBuffer template class, defined below, allocates a buffer alongside a ByteBuilder.

Subclassed by pw::ByteBuffer< kSizeBytes >

Public Functions

inline constexpr ByteBuilder(ByteSpan buffer)#

Creates an empty ByteBuilder.

ByteBuilder(const ByteBuilder&) = delete#

Disallow copy/assign to avoid confusion about where the bytes is actually stored. ByteBuffers may be copied into one another.

inline const std::byte *data() const#

Returns the contents of the bytes buffer.

inline Status status() const#

Returns the ByteBuilder’s status, which reflects the most recent error that occurred while updating the bytes. After an update fails, the status remains non-OK until it is cleared with clear() or clear_status().

Returns:

Code

Description

OK

No errors have occurred.

RESOURCE_EXHAUSTED

Output to the ByteBuilder was truncated.

INVALID_ARGUMENT

printf-style formatting failed.

OUT_OF_RANGE

An operation outside the buffer was attempted.

inline StatusWithSize status_with_size() const#

Returns status() and size() as a StatusWithSize.

inline bool ok() const#

True if status() is OkStatus().

inline bool empty() const#

True if the bytes builder is empty.

inline size_t size() const#

Returns the current length of the bytes.

inline size_t max_size() const#

Returns the maximum length of the bytes.

inline void clear()#

Clears the bytes and resets its error state.

inline void clear_status()#

Sets the statuses to OkStatus();.

inline void push_back(std::byte b)#

Appends a single byte. Sets the status to RESOURCE_EXHAUSTED if the byte cannot be added because the buffer is full.

inline void pop_back()#

Removes the last byte. Sets the status to OUT_OF_RANGE if the buffer is empty (in which case the unsigned overflow is intentional).

inline const_iterator begin() const#

Root of bytebuffer wrapped in iterator type.

inline const_iterator end() const#

End of bytebuffer wrapped in iterator type.

inline const std::byte &front() const#

Front and Back C++ container functions.

ByteBuilder &append(size_t count, std::byte b)#

Appends the provided byte count times.

ByteBuilder &append(const void *bytes, size_t count)#

Appends count bytes from ‘bytes’ to the end of the ByteBuilder. If count exceeds the remaining space in the ByteBuffer, no bytes will be appended and the status is set to RESOURCE_EXHAUSTED.

inline ByteBuilder &append(ConstByteSpan bytes)#

Appends bytes from a byte span that calls the pointer/length version.

void resize(size_t new_size)#

Sets the ByteBuilder’s size. This function only truncates; if new_size > size(), it sets status to OUT_OF_RANGE and does nothing.

inline ByteBuilder &PutUint8(uint8_t val)#

Put methods for inserting different 8-bit ints.

inline ByteBuilder &PutUint16(uint16_t value, endian order = endian::little)#

Put methods for inserting different 16-bit ints.

inline ByteBuilder &PutUint32(uint32_t value, endian order = endian::little)#

Put methods for inserting different 32-bit ints.

inline ByteBuilder &PutUint64(uint64_t value, endian order = endian::little)#

Put methods for inserting different 64-bit ints.

class iterator#

iterator class will allow users of ByteBuilder and ByteBuffer to access the data stored in the buffer. It has the functionality of C++’s random access iterator.

Public Functions

inline int8_t PeekInt8() const#

The Peek methods will retreive ordered (Little/Big Endian) values located at the iterator position without moving the iterator forward.

inline int8_t ReadInt8()#

The Read methods will retreive ordered (Little/Big Endian) values located at the iterator position and move the iterator forward by sizeof(value) positions forward.

template<size_t kSizeBytes>
class ByteBuffer : public pw::ByteBuilder#

ByteBuffers declare a buffer along with a ByteBuilder.

Public Functions

ByteBuffer(ByteBuffer &&other) = delete#

ByteBuffers are not movable: the underlying data must be copied.

ByteBuffer &operator=(ByteBuffer &&other) = delete#

ByteBuffers are not movable: the underlying data must be copied.

template<typename ...Args>
inline ByteBuffer &append(Args&&... args)#

Returns a ByteBuffer<kSizeBytes>& instead of a generic ByteBuilder& for append calls.

Public Static Functions

static inline constexpr size_t max_size()#

Returns the maximum length of the bytes that can be inserted in the bytes buffer.

Size report: using ByteBuffer#

Label

Segment

Delta

Using ByteBuilder vs not using it

FLASH

-18

main

-4

p05.0

NEW

+52

memmove

NEW

+36

pw::ByteBuilder::ResizeForAppend()

NEW

+36

pw::bytes::PutBytes()

NEW

+32

pw::ByteBuilder::append()

NEW

+14

pw::ByteBuilder::WriteInOrder<>()

NEW

+4

__aeabi_memmove

+152

pw_bytes/bit.h#

Implementation of features provided by C++20’s <bit> header. Supported features:

  • pw::endian – Implementation of the std::endian enum. If std::endian is available, pw::endian is an alias of it.

  • Additional functions for bit-level operations.

    template<std::size_t kBitWidth, typename T>
    constexpr T pw::bytes::SignExtend(T nbit_value)#

    Extends the nth bit to the left. Useful for expanding singed values into larger integer types.

    template<typename OutType, std::size_t kMsb, std::size_t kLsb, typename InType>
    constexpr OutType pw::bytes::ExtractBits(
    InType value,
    )#

    Extracts bits between msb and lsb from a value.

    Example (extrat bits between 10 and 5 from a uint32_t and return as a uint8_t):

    constexpr uint32_t number = 0xA0A0A0A0;
    constexpr uint8_t extracted_number = ExtractBits<uint8_t, 10, 5>(number);
    
    Template Parameters:
    • OutType – The type of output number to be extracted from input number.

    • kMsb – The left bit (included) that extraction starts at.

    • kLsb – The right bit (included) that extraction ends at.

    • InType – The type of input number.

    Parameters:

    value[in] The input number.

pw_bytes/endian.h#

Functions for converting the endianness of integral values.

pw_bytes/suffix.h#

This module exports a single _b literal, making it easier to create std::byte values for tests.

constexpr std::byte operator""_b(unsigned long long value)#

Note

This should not be used in header files, as it requires a using declaration that will be publicly exported at whatever level it is used.

Example:

#include "pw_bytes/units.h"

using ::pw::operator""_b;

constexpr std::byte kValue = 5_b;

pw_bytes/units.h#

Constants, functions and user-defined literals for specifying a number of bytes in powers of two, as defined by IEC 60027-2 A.2 and ISO/IEC 80000:13-2008.

The supported suffixes include:

  • _B for bytes (10240)

  • _KiB for kibibytes (10241)

  • _MiB for mebibytes (10242)

  • _GiB for gibibytes (10243)

  • _TiB for tebibytes (10244)

  • _PiB for pebibytes (10245)

  • _EiB for exbibytes (10246)

In order to use these you must use a using namespace directive, for example:

#include "pw_bytes/units.h"

using namespace pw::bytes::unit_literals;

constexpr size_t kRandomBufferSizeBytes = 1_MiB + 42_KiB;

In some cases, the use of user-defined literals is not permitted because of the required using namespace directive. One example of this is in header files, where it is undesirable to pollute the namespace. For this situation, there are also similar functions:

#include "pw_bytes/units.h"

constexpr size_t kBufferSizeBytes = pw::bytes::MiB(1) + pw::bytes::KiB(42);

Zephyr#

To enable pw_bytes for Zephyr add CONFIG_PIGWEED_BYTES=y to the project’s configuration.

Rust API#

pw_bytes’s Rust API is documented in our rustdoc API docs.