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_t offset, uint32_t length, uint32_t to_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_t offset, uint32_t length, uint32_t to_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_t header, uint32_t offset, 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_t header, uint32_t offset, 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

Records