Pigweed
C/C++ API Reference
|
Public Types | |
using | size_type = typename Deque::size_type |
using | difference_type = typename Deque::difference_type |
using | iterator = internal::ByteIterator< size_type, false > |
using | const_iterator = internal::ByteIterator< size_type, true > |
using | pointer = iterator::pointer |
using | const_pointer = const_iterator::pointer |
using | reference = iterator::reference |
using | const_reference = const_iterator::reference |
using | value_type = std::conditional_t< is_const(), const_iterator::value_type, iterator::value_type > |
Public Member Functions | |||||||||
BasicMultiBuf (const BasicMultiBuf &)=delete | |||||||||
template<Property... kOtherProperties> | |||||||||
BasicMultiBuf (const BasicMultiBuf< kOtherProperties... > &)=delete | |||||||||
BasicMultiBuf & | operator= (const BasicMultiBuf &)=delete | ||||||||
template<Property... kOtherProperties> | |||||||||
BasicMultiBuf & | operator= (const BasicMultiBuf< kOtherProperties... > &)=delete | ||||||||
BasicMultiBuf (BasicMultiBuf &&)=delete | |||||||||
template<Property... kOtherProperties> | |||||||||
BasicMultiBuf (BasicMultiBuf< kOtherProperties... > &&)=delete | |||||||||
BasicMultiBuf & | operator= (BasicMultiBuf &&)=delete | ||||||||
template<Property... kOtherProperties> | |||||||||
BasicMultiBuf & | operator= (BasicMultiBuf< kOtherProperties... > &&)=delete | ||||||||
template<typename OtherMultiBuf > | |||||||||
OtherMultiBuf & | as () | ||||||||
template<typename OtherMultiBuf > | |||||||||
const OtherMultiBuf & | as () const | ||||||||
template<typename OtherMultiBuf , typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>> | |||||||||
operator OtherMultiBuf & () | |||||||||
template<typename OtherMultiBuf , typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>> | |||||||||
operator const OtherMultiBuf & () const | |||||||||
constexpr bool | empty () const | ||||||||
constexpr size_t | size () const | ||||||||
bool | IsCompatible (const BasicMultiBuf &mb) const | ||||||||
bool | TryReserveChunks (size_type num_chunks) | ||||||||
template<Property... kOtherProperties> | |||||||||
bool | TryReserveForInsert (const_iterator pos, const BasicMultiBuf< kOtherProperties... > &mb) | ||||||||
template<int &... kExplicitGuard, typename T , typename = std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>> | |||||||||
bool | TryReserveForInsert (const_iterator pos, const T &bytes) | ||||||||
template<Property... kOtherProperties> | |||||||||
void | Insert (const_iterator pos, BasicMultiBuf< kOtherProperties... > &&mb) | ||||||||
template<int &... kExplicitGuard, typename T , typename = std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>> | |||||||||
void | Insert (const_iterator pos, const T &bytes) | ||||||||
template<Property... kOtherProperties> | |||||||||
bool | TryReserveForPushBack (const BasicMultiBuf< kOtherProperties... > &mb) | ||||||||
template<int &... kExplicitGuard, typename T , typename = std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>> | |||||||||
bool | TryReserveForPushBack (const T &bytes) | ||||||||
template<Property... kOtherProperties> | |||||||||
void | PushBack (BasicMultiBuf< kOtherProperties... > &&mb) | ||||||||
template<int &... kExplicitGuard, typename T , typename = std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>> | |||||||||
void | PushBack (const T &bytes) | ||||||||
bool | IsRemovable (const_iterator pos, size_t size) const | ||||||||
Result< Instance< BasicMultiBuf > > | Remove (const_iterator pos, size_t size) | ||||||||
Result< Instance< BasicMultiBuf > > | PopFrontFragment () | ||||||||
Result< const_iterator > | Discard (const_iterator pos, size_t size) | ||||||||
bool | IsReleasable (const_iterator pos) const | ||||||||
UniquePtr< value_type[]> | Release (const_iterator pos) | ||||||||
bool | IsShareable (const_iterator pos) const | ||||||||
SharedPtr< value_type[]> | Share (const_iterator pos) | ||||||||
size_t | CopyTo (ByteSpan dst, size_t offset=0) const | ||||||||
size_t | CopyFrom (ConstByteSpan src, size_t offset=0) | ||||||||
ConstByteSpan | Get (ByteSpan copy, size_t offset=0) const | ||||||||
template<int &... kExplicitGuard, typename Visitor > | |||||||||
auto | Visit (Visitor visitor, ByteSpan copy, size_t offset) | ||||||||
void | Clear () | ||||||||
constexpr Observer * | observer () const | ||||||||
void | set_observer (Observer *observer) | ||||||||
size_type | NumFragments () const | ||||||||
constexpr size_type | NumLayers () const | ||||||||
bool | AddLayer (size_t offset, size_t length=dynamic_extent) | ||||||||
void | SealTopLayer () | ||||||||
void | UnsealTopLayer () | ||||||||
bool | ResizeTopLayer (size_t offset, size_t length=dynamic_extent) | ||||||||
bool | PopLayer () | ||||||||
at | |||||||||
Returns a reference to the byte at specified index.
Use | |||||||||
template<bool kMutable = !is_const()> | |||||||||
std::enable_if_t< kMutable, reference > | at (size_t index) | ||||||||
const_reference | at (size_t index) const | ||||||||
template<bool kMutable = !is_const()> | |||||||||
std::enable_if_t< kMutable, reference > | operator[] (size_t index) | ||||||||
const_reference | operator[] (size_t index) const | ||||||||
Chunks | |||||||||
Returns a chunk-iterable view of the MultiBuf. This can be used in a range-based for-loop, e.g. for (ConstByteSpan chunk : multibuf.ConstChunks()) {
Read(chunk);
}
| |||||||||
template<bool kMutable = !is_const()> | |||||||||
constexpr std::enable_if_t< kMutable, ChunksType > | Chunks () | ||||||||
ConstChunksType | Chunks () const | ||||||||
ConstChunksType | ConstChunks () const | ||||||||
begin | |||||||||
Returns an iterator to the start of the MultiBuf's bytes.
Use | |||||||||
template<bool kMutable = !is_const()> | |||||||||
constexpr std::enable_if_t< kMutable, iterator > | begin () | ||||||||
constexpr const_iterator | begin () const | ||||||||
constexpr const_iterator | cbegin () const | ||||||||
end | |||||||||
Returns an iterator past the end of the MultiBuf's bytes.
Use | |||||||||
template<bool kMutable = !is_const()> | |||||||||
constexpr std::enable_if_t< kMutable, iterator > | end () | ||||||||
constexpr const_iterator | end () const | ||||||||
constexpr const_iterator | cend () const | ||||||||
IsCompatible | |||||||||
Returns whether the shared memory can be added to this object. To be compatible, the shared pointer must be the first shared pointer added to the object, or match the shared pointer previously added.
| |||||||||
bool | IsCompatible (const UniquePtr< std::byte[]> &bytes) const | ||||||||
bool | IsCompatible (const UniquePtr< const std::byte[]> &bytes) const | ||||||||
bool | IsCompatible (const SharedPtr< std::byte[]> &bytes) const | ||||||||
bool | IsCompatible (const SharedPtr< const std::byte[]> &bytes) const | ||||||||
TryReserveForInsert | |||||||||
Attempts to modify this object to be able to accept the given shared memory, and returns whether successful. It is an error to call this method with an invalid iterator or incompatible MultiBuf, if applicable. If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
| |||||||||
bool | TryReserveForInsert (const_iterator pos, const UniquePtr< std::byte[]> &bytes) | ||||||||
bool | TryReserveForInsert (const_iterator pos, const UniquePtr< const std::byte[]> &bytes) | ||||||||
bool | TryReserveForInsert (const_iterator pos, const SharedPtr< std::byte[]> &bytes) | ||||||||
bool | TryReserveForInsert (const_iterator pos, const SharedPtr< const std::byte[]> &bytes) | ||||||||
Insert | |||||||||
Insert memory before the given iterator. It is a fatal error if this method cannot allocate space for necessary metadata. See also
| |||||||||
void | Insert (const_iterator pos, UniquePtr< std::byte[]> &&bytes) | ||||||||
void | Insert (const_iterator pos, UniquePtr< const std::byte[]> &&bytes) | ||||||||
void | Insert (const_iterator pos, UniquePtr< std::byte[]> &&bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | Insert (const_iterator pos, UniquePtr< const std::byte[]> &&bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | Insert (const_iterator pos, const SharedPtr< std::byte[]> &bytes) | ||||||||
void | Insert (const_iterator pos, const SharedPtr< const std::byte[]> &bytes) | ||||||||
void | Insert (const_iterator pos, const SharedPtr< std::byte[]> &bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | Insert (const_iterator pos, const SharedPtr< const std::byte[]> &bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
TryReserveForPushBack | |||||||||
Attempts to modify this object to be able to move the given shared memory to the end of this object. If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
| |||||||||
bool | TryReserveForPushBack (const UniquePtr< std::byte[]> &bytes) | ||||||||
bool | TryReserveForPushBack (const UniquePtr< const std::byte[]> &bytes) | ||||||||
bool | TryReserveForPushBack (const SharedPtr< std::byte[]> &bytes) | ||||||||
bool | TryReserveForPushBack (const SharedPtr< const std::byte[]> &bytes) | ||||||||
PushBack | |||||||||
Moves memory to the end of this object. It is a fatal error if this method cannot allocate space for necessary metadata. See also
| |||||||||
void | PushBack (UniquePtr< std::byte[]> &&bytes) | ||||||||
void | PushBack (UniquePtr< const std::byte[]> &&bytes) | ||||||||
void | PushBack (UniquePtr< std::byte[]> &&bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | PushBack (UniquePtr< const std::byte[]> &&bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | PushBack (const SharedPtr< std::byte[]> &bytes) | ||||||||
void | PushBack (const SharedPtr< const std::byte[]> &bytes) | ||||||||
void | PushBack (const SharedPtr< std::byte[]> &bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
void | PushBack (const SharedPtr< const std::byte[]> &bytes, size_t offset, size_t length=dynamic_extent) | ||||||||
Static Public Member Functions | |
static constexpr bool | is_const () |
Returns whether the MultiBuf data is immutable. | |
static constexpr bool | is_layerable () |
Returns whether additional views can be layered on the MultiBuf. | |
static constexpr bool | is_observable () |
Returns whether an observer can be registered on the MultiBuf. | |
Protected Types | |
using | Deque = DynamicDeque< internal::Entry > |
using | ChunksType = internal::Chunks< typename Deque::size_type > |
using | ConstChunksType = internal::ConstChunks< typename Deque::size_type > |
using | GenericMultiBuf = internal::GenericMultiBuf |
Logical byte sequence representing a sequence of memory buffers.
MultiBufs have been designed with network data processing in mind. They facilitate assembling and disassembling multiple buffers to and from a single sequence. This class refers to these individual spans of bytes as Chunks
.
Small amounts of this data, such as protocol headers, can be accessed using methods such as Get
, Visit
, and the byte iterators. These methods avoid copying unless strictly necessary, such as when operating over chunks that are not contiguous in memory.
Larger amounts of data, such as application data, can be accessed using methods such as CopyFrom
, CopyTo
, and the chunk iterators.
MultiBufs are defined with zero or more properties which add or constrain additional behavior:
operator[]
and CopyFrom
, are not available when this property is set.Type aliases are provided for standard combinations of these properties.
A MultiBuf may be converted to another with different properties using the as
method, provided those properties are compatible. This allows writing method and function signatures that only specify the necessary behavior. For example:
In order to provide for such conversions, this class only represents the interface of a particular MultiBuf type, and not its instantiation. To create a concrete instantiation of BasicMultiBuf<kProperties>
, use Instance<BasicMultiBuf<kProperties>
, as described below.
MultiBufs are designed to be built either "bottom-up" or "top-down":
The "bottom-up" approach also provides the concept of message "fragments". Whenever a layer is added, a MultiBuf considers the new top layer to be a "fragment". These boundaries are preserved when appending additional data, and can be used to break the MultiBuf back up into lower-level messages when writing data to the network.
For example, consider a TCP/IP example. You could use a "bottom-up", layerable MultiBuf to access and manipulate TCP data. In the following:
Alterantively, you could use a "top-down", unlayered MultiBuf to represent same. The following might be the result of adding statically owned headers and footers to a portion of the application data:
kProperties | Zero or more Property values. These must not be duplicated, and must appear in the order specified by that type. |
|
inline |
Adds a layer.
Each layer provides a span-like view of memory. An empty MultiBuf has no layers, while a non-empty MultiBuf has at least one. Additional layers provide a subspan-like view of the layer beneath it. This is useful in representing nested protocols, where the payloads of one level make up the messages of the next level.
This will modify the apparent byte sequence to be a view of the previous top layer.
The range given by offset
and length
MUST fall within this MultiBuf.
If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
[in] | offset | Offset from the start of the previous top layer for the new top layer. |
[in] | length | Length of the new top layer. |
|
inline |
Releases all memory from this object.
If this object has a deallocator, it will be used to free the memory owned by this object. When this method returns, the MultiBuf will be restored to an initial, empty state.
|
inline |
|
inline |
|
inline |
Removes if a range of bytes from this object.
The range given by pos
and size
MUST fall within this MultiBuf.
This method may fail if space for additional metadata is needed but cannot be allocated.
On successful completion, this method will return a valid iterator pointing to the memory following that which was discarded.
On failure, the original MultiBuf is unmodified.
"Owned" chunks, i.e. those added using a UniquePtr
, which are fully discarded as a result of this call will be deallocated.
pos | Location from which to discard memory from the MultiBuf. |
size | Amount of memory to discard. |
embed:rst:leading-asterisk * * .. pw-status-codes:: * * OK: The memory range has been discarded. * * RESOURCE_EXHAUSTED: Failed to allocate memory for the new MultiBuf's * metadata. *
|
inlineconstexpr |
Returns whether the MultiBuf is empty, i.e. whether it has no chunks or fragments.
|
inline |
Returns a byte span containing data at the given offset
.
If the data is contiguous, a view to it is returned directly. Otherwise, it is copied from the non-contiguous buffers into the provided span, which is then returned.
As a result, this method should only be used on small regions of data, e.g. packet headers.
copy | A buffer that may be used to hold data if the requested region is non-contiguous. Its length determines the maximum number of bytes that may be copied. |
offset | Offset from the start of the MultiBuf to start copying from. |
void pw::multibuf::BasicMultiBuf< kProperties >::Insert | ( | const_iterator | pos, |
BasicMultiBuf< kOtherProperties... > && | mb | ||
) |
Insert memory before the given iterator.
It is a fatal error if this method cannot allocate space for necessary metadata. See also TryReserveForInsert
, which can be used to try to pre-allocate the needed space without crashing.
void pw::multibuf::BasicMultiBuf< kProperties >::Insert | ( | const_iterator | pos, |
const T & | bytes | ||
) |
Insert memory before the given iterator.
It is a fatal error if this method cannot allocate space for necessary metadata. See also TryReserveForInsert
, which can be used to try to pre-allocate the needed space without crashing.
pos | Location to insert memory within the MultiBuf. |
bytes | Unowned memory to be inserted. |
|
inline |
Returns whether the MultiBuf can be added to this object.
To be compatible, the memory for each of incoming MultiBuf's chunks must be one of the following:
mb | MultiBuf to check for compatibility. |
|
inline |
|
inline |
Returns whether the given range can be removed.
A range may not be valid to Remove
if it does not fall within the MultiBuf, or if it splits "owned" chunks. Owned chunks are those added using a UniquePtr
. Splitting them between different MultiBufs would result in conflicting ownership, and is therefore disallowed.
pos | Location from which to remove memory from the MultiBuf. |
size | Amount of memory to remove. |
|
inline |
|
inline |
Returns the number of fragments in the top layer.
Whenever a new layer is added, its boundary is marked and it is treated as a single fragment of a larger message or packet. These boundaries markers are preserved by Insert
and PushBack
. They can be used to delineate how much memory to return when PopFront
is called.
|
inlineconstexpr |
Returns the number layers in the MultiBuf.
This will always be at least 1.
|
inlineconstexpr |
Result< Instance< BasicMultiBuf< kProperties... > > > pw::multibuf::BasicMultiBuf< kProperties >::PopFrontFragment |
Removes the first fragment from this object and returns it.
Without any layers, each chunk is a fragment. Layered MultiBufs may group multiple chunks into a single fragment.
It is an error to call this method when the MultiBuf is empty.
embed:rst:leading-asterisk * * .. pw-status-codes:: * * OK: Returns the fragment in a new MultiBuf. * * RESOURCE_EXHAUSTED: Attempting to reserve space for the new MultiBuf * failed. * *
|
inline |
Removes the top layer.
After this call, the layer beneath the top layer will be the new top layer.
It is an error to call this method when NumLayers()
< 2.
Returns false and leaves the object unmodified if the top layer is sealed; otherwise returns true.
void pw::multibuf::BasicMultiBuf< kProperties >::PushBack | ( | BasicMultiBuf< kOtherProperties... > && | mb | ) |
Moves bytes to the end of this object.
It is a fatal error if this method cannot allocate space for necessary metadata. See also TryReserveForPushBack
, which can be used to try to pre-allocate the needed space without crashing.
mb | MultiBuf to be inserted. |
void pw::multibuf::BasicMultiBuf< kProperties >::PushBack | ( | const T & | bytes | ) |
Moves memory to the end of this object.
It is a fatal error if this method cannot allocate space for necessary metadata. See also TryReserveForPushBack
, which can be used to try to pre-allocate the needed space without crashing.
bytes | Unowned memory to be inserted. |
UniquePtr< typename BasicMultiBuf< kProperties... >::value_type[]> pw::multibuf::BasicMultiBuf< kProperties >::Release | ( | const_iterator | pos | ) |
Removes a memory allocation from this object and releases ownership of it.
The location given by pos
and MUST be releasable, as described by IsReleasable
: It MUST fall within an "owned" chunk.
This method returns a UniquePtr
which owns the removed memory.
The entire owned chunk containing the location indicated by the iterator will be removed and returned. An iterator to the middle of an owned chunk will result in some bytes before the iterator being removed.
pos | Location within the MultiBuf of the memory to release. |
Result< Instance< BasicMultiBuf< kProperties... > > > pw::multibuf::BasicMultiBuf< kProperties >::Remove | ( | const_iterator | pos, |
size_t | size | ||
) |
Removes if a range of bytes from this object.
The range given by pos
and size
MUST be removable, as described by IsRemovable
: It MUST fall within this MultiBuf, and not split "owned" chunks.
This method may fail if unable to allocate metadata for a new MultiBuf.
On successful completion, this method will return a MultiBuf populated with entries corresponding to the removed memory range.
On failure, the original MultiBuf is unmodified.
pos | Location from which to remove memory from the MultiBuf. |
size | Amount of memory to remove. |
embed:rst:leading-asterisk * * .. pw-status-codes:: * * OK: The returned MultiBuf contains the removed chunks. * * RESOURCE_EXHAUSTED: Failed to allocate memory for the new MultiBuf's * metadata. *
|
inline |
Resizes the current top layer.
The range given by offset
and length
MUST fall within this MultiBuf. It is an error to call this method when NumLayers()
< 2.
Returns false and leaves the object unmodified if the top layer is sealed; otherwise returns true.
[in] | offset | New offset from the start of layer beneath the top layer. |
[in] | length | New length of the top layer. |
|
inline |
Marks the top layer as "sealed", preventing it from being resized or popped.
|
inline |
SharedPtr< typename BasicMultiBuf< kProperties... >::value_type[]> pw::multibuf::BasicMultiBuf< kProperties >::Share | ( | const_iterator | pos | ) |
Returns the shared memory at the given location.
The location given by pos
and MUST be shareable, as described by IsShareable
: It MUST fall within a "shared" chunk.
This method returns a SharedPtr
which shares ownership of the indicated memory. the memory will not be freed until all shared pointers to it go out of scope.
The returned pointer will reference the entire shared chunk containing the location indicated by the iterator. The shared pointer for an iterator to the middle of a shared chunk will include some bytes before the iterator.
pos | Location within the MultiBuf of the memory to share. |
|
inlineconstexpr |
Returns the size of a MultiBuf in bytes, which is the sum of the lengths of the views that make up its topmost layer.
|
inline |
Attempts to reserves memory to hold metadata for the given number of total chunks.
embed:rst:leading-asterisk * * .. pw-status-codes:: * * OK: The object has space for the chunks. * * RESOURCE_EXHAUSTED: Out of memory; cannot add the chunks. * *
bool pw::multibuf::BasicMultiBuf< kProperties >::TryReserveForInsert | ( | const_iterator | pos, |
const BasicMultiBuf< kOtherProperties... > & | mb | ||
) |
Attempts to modify this object to be able to insert the given MultiBuf, and returns whether successful.
It is an error to call this method with an invalid iterator or incompatible MultiBuf, if applicable.
If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
bool pw::multibuf::BasicMultiBuf< kProperties >::TryReserveForInsert | ( | const_iterator | pos, |
const T & | bytes | ||
) |
Attempts to modify this object to be able to accept the given unowned memory, and returns whether successful.
It is an error to call this method with an invalid iterator or incompatible MultiBuf, if applicable.
If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
pos | Location to insert memory within the MultiBuf. |
bytes | Unowned memory to be inserted. |
bool pw::multibuf::BasicMultiBuf< kProperties >::TryReserveForPushBack | ( | const BasicMultiBuf< kOtherProperties... > & | mb | ) |
bool pw::multibuf::BasicMultiBuf< kProperties >::TryReserveForPushBack | ( | const T & | bytes | ) |
Attempts to modify this object to be able to move the given unowned memory to the end of this object.
If unable to allocate space for the metadata, returns false and leaves the object unchanged. Otherwise, returns true.
bytes | Unowned memory to be inserted. |
|
inline |
Clears the "sealed" flag from the top layer, allowing it to be resized or popped.
|
inline |
Passes a byte span containing data at the given offset
to a visitor
.
If the data is contiguous, the visitor
is called on it directly. Otherwise, data is copied from the non-contiguous buffers into the provided span, which is then passed to visitor
.
visitor | A callable object, such as a function pointer or lambda, that can be called on a ConstByteSpan . |
copy | A buffer that may be used to hold data if the requested region is non-contiguous. Its length determines the maximum number of bytes that may be copied. |
offset | Offset from the start of the MultiBuf to start copying from. |
visitor
on the requested range.