template <StorageApi Storage>
class View
Defined at line 114 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
The zbitl::View class provides functionality for processing ZBI items in various
storage formats.
For example, the entries in a ZBI present in memory can be enumerated as follows:
```
void ProcessZbiEntries(std::string_view data) {
// Create the view.
zbitl::View
<std
::string_view> view{data};
// Iterate over entries.
for (const auto
&
entry : view) {
printf("Found entry of type %x with payload size %ld.\n",
entry.header->type, // entry.header has type similar to "zbi_header_t *".
entry.payload.size()); // entry.payload has type "std::string_view".
}
// Callers are required to check for errors (or call "ignore_error")
// prior to object destruction. See "Error checking" below.
if (auto error = view.take_error(); error.is_error()) {
printf("Error encountered!\n");
// ...
}
}
```
zbitl::View satisfies the C++20 std::forward_range concept; it satisfies the
std::view concept if the Storage and Storage::error_type types support
constant-time copy/move/assignment.
## Error checking
The "error-checking view" pattern means that the container/range/view API
of begin() and end() iterators is supported, but when begin() or
iterator::operator++() encounters an error, it simply returns end() so that
loops terminate normally. Thereafter, take_error() must be called to check
whether the loop terminated because it iterated past the last item or
because it encountered an error. Once begin() has been called,
take_error() must be called before the View is destroyed, so no error goes
undetected. Since all use of iterators updates the error state, use of any
zbitl::View object must be serialized and after begin() or operator++()
yields end(), take_error() must be checked before using begin() again.
## Iteration
Each time begin() is called the underlying storage is examined afresh, so
it's safe to reuse a zbitl::View object after changing the data. Reducing
the size of the underlying storage invalidates any iterators that pointed
past the new end of the image. It's simplest just to assume that changing
the underlying storage always invalidates all iterators.
## Storage
The Storage type is some type that can be abstractly considered to have
non-owning "view" semantics: it doesn't hold the storage of the ZBI, it
just refers to it somehow. The zbitl::View:Error type describes errors
encountered while iterating. It uses the Storage::error_type type to
propagate errors caused by access to the underlying storage.
Usually Storage and Storage:error_type types are small and can be copied.
zbitl::View is move-only if Storage is move-only or if Storage::error_type
is move-only. Note that copying zbitl::View copies its error-checking
state exactly, so if the original View needed to be checked for errors
before destruction then both the original and the copy need to be checked
before their respective destructions. A moved-from zbitl::View can always
be destroyed without checking.
Public Methods
void View<Storage> ()
Defined at line 119 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void View<Storage> (const View<Storage> & )
Defined at line 120 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
View<Storage> & operator= (const View<Storage> & )
Defined at line 121 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void View<Storage> (View<Storage> && other)
This is almost the same as the default move behavior. But it also
explicitly resets the moved-from error state to kUnused so that the
moved-from View can be destroyed without checking it.
Defined at line 126 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
View<Storage> & operator= (View<Storage> && other)
Defined at line 131 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void View<Storage> (storage_type storage)
Defined at line 140 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void ~View<Storage> ()
Defined at line 142 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<Error> take_error ()
Check the container for errors after using iterators. When begin() or
iterator::operator++() encounters an error, it simply returns end() so
that loops terminate normally. Thereafter, take_error() must be called
to check whether the loop terminated because it iterated past the last
item or because it encountered an error. Once begin() has been called,
take_error() must be called before the View is destroyed, so no error
goes undetected. After take_error() is called the error state is
consumed and take_error() cannot be called again until another begin() or
iterator::operator++() call has been made.
Defined at line 297 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
bool haz_error ()
Defined at line 308 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void ignore_error ()
If you explicitly don't care about any error that might have terminated
the last loop early, then call ignore_error() instead of take_error().
Defined at line 312 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
storage_type & storage ()
Trivial accessors for the underlying Storage (view) object.
Defined at line 315 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
const storage_type & storage ()
Defined at line 316 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<Error, zbi_header_t> container_header ()
This returns its own error state and does not affect the `take_error()`
state of the View.
Defined at line 482 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
iterator begin ()
After calling begin(), it's mandatory to call take_error() before
destroying the View object. An iteration that encounters an error will
simply end early, i.e. begin() or operator++() will yield an iterator
that equals end(). At the end of a loop, call take_error() to check for
errors. It's also acceptable to call take_error() during an iteration
that hasn't reached end() yet, but it cannot be called again before the
next begin() or operator++() call.
Defined at line 523 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
iterator end ()
Defined at line 536 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
size_t size_bytes ()
Defined at line 538 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
iterator find (uint32_t type)
Looks up an item by type, returning the iterator pointing to the first
match or else end().
Like begin(), find() resets the internal error state and it is the
responsibility of the caller to take or ignore that error before calling
this method.
Defined at line 554 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<typename Traits::error_type> EditHeader (const iterator & item, const zbi_header_t & header)
Replace an item's header with a new one, using an iterator into this
view.. This never changes the existing item's length (nor its payload).
So the header can be `{.type = XYZ}` alone or whatever fields and flags
matter. Note this returns only the storage error type, not an Error since
no ZBI format errors are possible here, only a storage failure to update.
This method is not available if zbitl::StorageTraits
<storage
_type>
doesn't support mutation.
Defined at line 568 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<typename Traits::error_type> EditHeader (iterator & item, const zbi_header_t & header)
When the iterator is mutable and not a temporary, make the next
operator*() consistent with the new header if it worked. For kReference
storage types, the change is reflected intrinsically.
Defined at line 583 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<Error, bool> CheckCrc32 (iterator it)
Verifies that a given View iterator points to an item with a valid CRC32.
Defined at line 600 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <typename CopyStorage>
fit::result<CopyError<std::decay_t<CopyStorage>>> Copy (CopyStorage &&to,uint32_toffset,uint32_tlength,uint32_tto_offset)
Copy a range of the underlying storage into an existing piece of storage,
which can be any mutable type with sufficient capacity. The Error return
value is for a read error. The "success" return value indicates there was
no read error. It's another fit::result
<error
_type> for the writing side
(which may be different than the type used in Error::storage_error). The
optional `to_offset` argument says where in `to` the data is written, as a
byte offset that is zero by default.
Defined at line 646 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto Copy (uint32_toffset,uint32_tlength,uint32_tto_offset)
Copy a range of the underlying storage into a freshly-created new piece of
storage (whatever that means for this storage type). The Error return
value is for a read error. The "success" return value indicates there was
no read error. It's another fit::result
<read
_error_type, T> for some
T akin to storage_type, possibly storage_type itself. For example, all
the unowned VMO storage types yield zx::vmo as the owning equivalent
storage type. If the optional `to_offset` argument is nonzero, the new
storage starts with that many zero bytes before the copied data.
Defined at line 747 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <WritableStorageApi CopyStorage>
fit::result<CopyError<std::decay_t<CopyStorage>>> CopyRawItem (CopyStorage && to, const iterator & it)
Copy a single item's payload into supplied storage.
Defined at line 767 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto CopyRawItem (const iterator & it)
Copy a single item's payload into newly-created storage.
Defined at line 773 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <WritableStorageApi CopyStorage>
auto CopyRawItemWithHeader (CopyStorage && to, const iterator & it)
Copy a single item's header and payload into supplied storage.
Defined at line 781 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto CopyRawItemWithHeader (const iterator & it)
Copy a single item's header and payload into newly-created storage.
Defined at line 787 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <WritableStorageApi CopyStorage, invocable<size_t> ScratchAllocator>
fit::result<CopyError<std::decay_t<CopyStorage>>> CopyStorageItem (CopyStorage &&to,const iterator &it,ScratchAllocator &&scratch)
Copy a single item's payload into supplied storage, including
decompressing a ZBI_TYPE_STORAGE_* item if necessary. This statically
determines based on the input and output storage types whether it has to
use streaming decompression or can use the one-shot mode (which is more
efficient and requires less scratch memory). So the unused part of the
decompression library can be elided at link time.
If decompression is necessary, then this calls `scratch(size_t{bytes})` to
allocate scratch memory for the decompression engine. This returns
`fit::result
<std
::string_view, T>` where T is any movable object that has
a `get()` method returning a pointer (of any type implicitly converted to
`void*`) to the scratch memory. The returned object is destroyed after
decompression is finished and the scratch memory is no longer needed.
zbitl::decompress:DefaultAllocator is a default-constructible class that
can serve as `scratch`. The overloads below with fewer arguments use it.
Defined at line 812 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <typename ScratchAllocator>
auto CopyStorageItem (const iterator & it, ScratchAllocator && scratch)
Defined at line 822 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <typename CopyStorage>
fit::result<CopyError<std::decay_t<CopyStorage>>> CopyStorageItem (CopyStorage && to, const iterator & it)
These overloads have the effect of default arguments for the allocator
arguments to the general versions above, but template argument deduction
doesn't work with default arguments.
Defined at line 861 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto CopyStorageItem (const iterator & it)
Defined at line 866 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
template <typename CopyStorage>
fit::result<CopyError<std::decay_t<CopyStorage>>> Copy (CopyStorage &&to,const iterator &first,const iterator &last)
Copy the subrange `[first,last)` of the ZBI into supplied storage.
The storage will contain a new ZBI container with only those items.
Defined at line 875 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto Copy (const iterator & first, const iterator & last)
Copy the subrange `[first,last)` of the ZBI into newly-created storage.
The storage will contain a new ZBI container with only those items.
Defined at line 898 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
Protected Methods
auto ReadContainerHeader (Storage & storage)
Fetches the container header.
Defined at line 970 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
auto ReadItemHeader (Storage & storage, uint32_t offset)
Fetches an item header at a given offset.
Defined at line 975 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<typename Traits::error_type, zbi_header_t> WriteHeader (zbi_header_theader,uint32_toffset,std::optional<uint32_t>new_length)
WriteHeader sanitizes and optionally updates the length of a provided
header, writes it to the provided offset, and returns the modified header
on success.
Defined at line 982 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
fit::result<typename Traits::error_type, zbi_header_t> WriteHeader (zbi_header_theader,uint32_toffset,std::optional<uint32_t>new_length)
WriteHeader sanitizes and optionally updates the length of a provided
header, writes it to the provided offset, and returns the modified header
on success.
Defined at line 982 of file ../../src/lib/zbitl/include/lib/zbitl/view.h
void set_limit (uint32_t limit)
Defined at line 994 of file ../../src/lib/zbitl/include/lib/zbitl/view.h