# Reads and Writes

> UStore for C++

### Blobs

No collection exists until one is created, so every call names one.
A collection handle is cheap to construct and holds no state, and its `[]` operator returns a `blobs_ref` over one key or a batch of keys that reads and writes through the C interface:

```cpp
auto [blobs, create_status] = db.create<blobs_collection_t>("blobs");

status_t status = blobs[key_from_integer(42)].assign("purpose of life");
expected<owned_value_t> value = blobs[key_from_integer(42)].value();
bool const matches = value && *value == "purpose of life";

status = blobs[{key_from_integer(43), key_from_integer(44)}].assign("same value");
expected<bool> present = blobs[key_from_integer(43)].present();
status = blobs[key_from_integer(43)].remove();

auto [arena, arena_status] = arena_t::make();
std::array<ustore_key_t, 3> keys {key_from_integer(65), key_from_integer(66), key_from_integer(67)};
expected<values_view_t> values = blobs.read(keys, arena);
for (value_view_t found : *values)
    std::printf("%zu bytes\n", found.size());
```

Read without an arena, `value`, `present` and `length` are shorthand: a single key answers an `owned_value_t`, a `bool` or a length, and a batch an `owned<values_view_t>`, an owned `bits_view_t` or owned `lengths_view_t`.
Given an `arena_t&`, as `blobs.read(keys, arena)` or `blobs[keys].value(arena)`, `.present(arena)` and `.length(arena)` are, the same reads answer plain views into that arena.
`remove` removes the keys, while `clear_values` keeps them and empties their values.
`keys` and `pairs` range over a collection in key order from a `start_key` to an `end_key`, and `size_range` estimates how many keys it holds.
Each stream is shorthand for a range-based loop, which has no place for an arena, so it pulls pages from a cursor into one arena it owns for its lifetime.

`#include <ustore/blobs_collection.hpp>`

`#include <ustore/blobs_ref.hpp>`

`#include <ustore/ranges.hpp>`

`#include <ustore/strings_collection.hpp>`

`#include <ustore/types.hpp>`

`#include <ustore/blobs_range.hpp>`

## bits_span_t

A mutable view of individual bits packed into octets.

```cpp
class bits_span_t
```

## bits_view_t

A read-only view of individual bits packed into octets.

```cpp
class bits_view_t
```

## strided_span

A counted run of strided elements, writable unless `element_type_` is `const`, like `std::span`.

```cpp
template <typename element_type_>
class strided_span
```

## range

A pair of iterators, so that a move-only stream can drive a range-based loop.

```cpp
template <typename iterator_type_>
class range
```

## place_t

One task of a batched read or write.

```cpp
struct place_t
```

- `collection` `ustore_collection_id_t`
- `key` `ustore_key_t const &`
- `field` `std::string_view`

## locations_in_collection

A batch of locations that all live in one collection the batch does not name itself.

```cpp
template <typename locations_type_>
struct locations_in_collection
```

- `without` `location_store<locations_type_>`: The locations, stored by value or by reference.
- `collection` `ustore_collection_id_t`: Collection every location lives in.

## strided_strings

Lends a strided run of string-like elements to the C ABI through a `[ustore_strings_view_t](https://www.unum.cloud/docs/ustore/c/reads-and-writes.md#ustore_strings_view_t)` accessor, where a zero stride repeats the first element for every task.

```cpp
template <string_like_concept element_type_>
class strided_strings
```

The view it hands out points at the object itself, so the object outlives every call given the view.

## lengths_view_t

The lengths a read exports into an arena beside its presence bits, where an absent value reads as `missing_length_k`, and a read that left its presences out reports every value present.

```cpp
class lengths_view_t
```

## values_view_t

The values a read exports into an arena as Apache Arrow does: presence bits and the tape of values, of either offset width, where an absent value reads as a missing view.

```cpp
class values_view_t
```

## strings_cursor_t

Owns a walk over the strings of one prefix from its open until its destruction, which every pull resumes past the last string the pull before it handed out, at the view its receiver read at the open.

```cpp
class strings_cursor_t
```

The explicit form of `[strings_stream_t](#strings_stream_t):` every pull takes the caller's arena, which holds the page until its next call. The cursor copies its prefix and start, and moves but never copies itself.

## blobs_range_t

A slice of keys in one collection, which streams its keys through the scan of the collection's `modality`, and, in a blobs collection, streams its pairs and estimates its size.

```cpp
class blobs_range_t
```

## blobs_collection_t

A handle to one binary collection, cheap to construct, that reads and writes the latest state or the view of a transaction.

```cpp
class blobs_collection_t
```

## deferred_t

The twin a deferred receiver hands out, whose verbs answer deferred calls.

```cpp
using deferred_t = deferred_blobs_collection_t;
```

## clear_values

Removes every value and keeps the keys.

```cpp
status_t clear_values() noexcept;
```

## clear

Removes every key and value and keeps the collection.

```cpp
status_t clear() noexcept;
```

## drop

Removes the collection with its name and every pair it holds.

```cpp
status_t drop() noexcept;
```

## at

Addresses one location or a batch of them inside this collection, whose own collection wins.

```cpp
blobs_ref<place_batch_t> at(
    std::initializer_list<ustore_key_t> keys) noexcept;
```

```cpp
blobs_ref<place_batch_t> at(keys_view_t keys) noexcept;
```

```cpp
template <typename keys_argument_type_>
auto at(keys_argument_type_ && keys) noexcept;
```

Addresses one location or a batch of them inside this collection, whose own collection wins.

## blobs_read_collection_t

A handle to one binary collection that only reads, cheap to construct and to copy, which addresses the latest state or the view of a transaction or snapshot.

```cpp
class blobs_read_collection_t
```

It holds no state of its own, so any number of threads share it, and it never outlives its database.

## read_only_t

The handle a snapshot hands out for this kind of collection, which only reads.

```cpp
using read_only_t = blobs_read_collection_t;
```

## deferred_t

The twin a deferred receiver hands out, whose verbs answer deferred calls.

```cpp
using deferred_t = deferred_blobs_read_collection_t;
```

## modality_k

What the collections this kind of handle addresses hold, which a creation records and a lookup checks.

```cpp
ustore_modality_t modality_k;
```

## blobs_read_collection_t

```cpp
blobs_read_collection_t() noexcept=default;
```

```cpp
blobs_read_collection_t(
    receiver_t receiver,
    ustore_collection_id_t collection) noexcept;
```

## size

Counts the keys by streaming through all of them.

```cpp
expected<std::size_t> size() const noexcept;
```

## read

Reads the values of a batch of [`keys`](#keys) into `arena`, the verb that reuses one arena call after call.

```cpp
template <batch_concept keys_argument_type_>
expected<values_view_t> read(
    keys_argument_type_ && keys,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

- `keys` (in): Keys to read, in any batch the ``[] operator takes.
- `arena` (in): Memory the values land in, which the answer views until its next call.
- `watch` (in): Whether a read inside a transaction records the keys for conflicts.

## at

Addresses one location or a batch of them inside this collection, whose own collection wins.

```cpp
blobs_read_ref<place_batch_t> at(
    std::initializer_list<ustore_key_t> keys) noexcept;
```

```cpp
blobs_read_ref<place_batch_t> at(keys_view_t keys) noexcept;
```

```cpp
template <typename keys_argument_type_>
auto at(keys_argument_type_ && keys) noexcept;
```

Addresses one location or a batch of them inside this collection, whose own collection wins.

## blobs_read_ref

A proxy that reads the values at one location or at a batch of locations, through a snapshot, a transaction or the head, and never writes them.

```cpp
template <typename locations_type_>
class blobs_read_ref
```

A read given an arena answers views into it, valid until the next call given that arena. The same read without one is shorthand: it makes a one-off arena and answers a result owning it, or a scalar copied out of it, which is slower than reusing an arena and keeps no state anywhere.

## blobs_read_ref

```cpp
blobs_read_ref(
    receiver_t receiver,
    locations_type_ && locations) noexcept;
```

## value

Reads the values into `arena`.

```cpp
expected<value_t> value(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<value_t>> value(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads the values into a one-off arena, which the answer owns.

## length

Reads the lengths of the values into `arena`.

```cpp
expected<length_t> length(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<length_t>> length(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads the lengths of the values into a one-off arena.

## present

Checks which keys are present into `arena`, where a present value may still be empty.

```cpp
expected<present_t> present(
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<one_off_answer_of<present_t>> present(
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Checks which keys are present into a one-off arena.

## blobs_ref

A proxy that reads or writes the values at one location or at a batch of locations, at the head or through a transaction.

```cpp
template <typename locations_type_>
class blobs_ref
```

One value may go to one key or to many keys, and many values to as many keys.

## assign

Assigns values to the keys pairwise, or one value to every key.

```cpp
template <typename values_argument_type_>
status_t assign(
    values_argument_type_ && values,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

- `values` (in): Values to assign.
- `durability` (in): Whether the call returns only after the data reaches the disk.

## remove

Removes the keys together with their values.

```cpp
status_t remove(
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

- `durability` (in): Whether the call returns only after the data reaches the disk.

## clear_values

Keeps the keys but empties their values.

```cpp
status_t clear_values(
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

- `durability` (in): Whether the call returns only after the data reaches the disk.

## strided_iterator

A pointer that advances by a byte stride instead of the size of its element.

```cpp
template <typename element_type_>
class strided_iterator
```

A zero stride repeats one element, so every task of a batch can share a single argument.

## strided_iterator

```cpp
strided_iterator(
    element_type_ *pointer = nullptr,
    ustore_size_t stride = 0) noexcept;
```

## operator-

The number of strides between two iterators, meaningful only for a stride that is a multiple of the element.

```cpp
strided_iterator operator-(std::ptrdiff_t count) const noexcept;
```

```cpp
std::ptrdiff_t operator-(strided_iterator other) const noexcept;
```

The number of strides between two iterators, meaningful only for a stride that is a multiple of the element.

## repeats

Whether a zero stride repeats the same element forever.

```cpp
bool repeats() const noexcept;
```

## is_continuous

Whether the elements sit next to each other without gaps.

```cpp
bool is_continuous() const noexcept;
```

## members

Views one member of every element with the same stride.

```cpp
template <typename member_type_, typename parent_type_>
auto members(
    member_type_ parent_type_::* member_pointer) const noexcept;
```

## strings_collection_t

A handle to one collection mapping variable-length strings onto keys, cheap to construct, which reads and writes the head or the view of a transaction.

```cpp
class strings_collection_t
```

## deferred_t

The twin a deferred receiver hands out, whose verbs answer deferred calls.

```cpp
using deferred_t = deferred_strings_collection_t;
```

## assign

Upserts the key one string maps onto.

```cpp
status_t assign(
    value_view_t text,
    ustore_key_t key,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

```cpp
status_t assign(
    std::span<value_view_t const> texts,
    std::span<ustore_key_t const> keys,
    ustore_durability_t durability = ustore_durability_buffered_k) noexcept;
```

Upserts the keys a batch of strings map onto, one per string.

Statuses: - `status_code_t::invalid_argument_k` The `texts` and [`keys`](#keys) differ in count.

## clear

Removes every string, keeping the collection.

```cpp
status_t clear() noexcept;
```

## drop

Removes the collection with all its strings.

```cpp
status_t drop() noexcept;
```

## strings_read_collection_t

A handle to one collection mapping variable-length strings onto keys that only reads, cheap to construct and to copy.

```cpp
class strings_read_collection_t
```

It addresses either the latest state or the view of a transaction or snapshot, holds no state of its own, so any number of threads share it, and never outlives its database. Strings carry explicit lengths, so a zero byte inside one is stored like any other, and the empty string is an ordinary key.

## read_only_t

The handle a snapshot hands out for this kind of collection, which only reads.

```cpp
using read_only_t = strings_read_collection_t;
```

## deferred_t

The twin a deferred receiver hands out, whose verbs answer deferred calls.

```cpp
using deferred_t = deferred_strings_read_collection_t;
```

## modality_k

What the collections this kind of handle addresses hold, which a creation records and a lookup checks.

```cpp
ustore_modality_t modality_k;
```

## strings_read_collection_t

```cpp
strings_read_collection_t() noexcept=default;
```

```cpp
strings_read_collection_t(
    receiver_t receiver,
    ustore_collection_id_t collection) noexcept;
```

## read

Reads the keys a batch of strings map onto into `arena`, where a missing string reads as the nil UUID, and marks the present strings in `presences` when asked.

```cpp
expected<keys_view_t> read(
    std::span<value_view_t const> texts,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k,
    bits_view_t *presences = nullptr) noexcept;
```

## value

Reads the key `text` maps onto through a one-off arena, the nil UUID when the collection lacks the string.

```cpp
expected<ustore_key_t> value(
    value_view_t text,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## present

Checks whether the collection holds `text` through a one-off arena.

```cpp
expected<bool> present(
    value_view_t text,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## prefixed_page

Lists up to `limit` strings of `prefix` into `arena`, in the order of their text.

```cpp
expected<sz::strings_view_t> prefixed_page(
    value_view_t prefix,
    std::size_t limit,
    arena_t & arena,
    value_view_t start = value_view_t::make_empty(),
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

The page starts at `start`, which it returns too when the collection holds it, so a walk that pages by hand skips the string it resumed from, and [`prefixed`](#prefixed) streams the pages instead.

## prefix_begin

Opens a stream over the strings of `prefix`, which outlives the stream.

```cpp
expected<strings_stream_t> prefix_begin(
    value_view_t prefix = value_view_t::make_empty(),
    std::size_t read_ahead = strings_stream_t::default_read_ahead_k) const noexcept;
```

## prefixed

Walks every string of `prefix`, which outlives the range, in the order of their text.

```cpp
expected<prefix_range_t> prefixed(
    value_view_t prefix = value_view_t::make_empty(),
    std::size_t read_ahead = strings_stream_t::default_read_ahead_k) const noexcept;
```

## size

Counts the strings of `prefix` by streaming through all of them.

```cpp
expected<std::size_t> size(
    value_view_t prefix = value_view_t::make_empty()) const noexcept;
```

## strings_stream_t

A stream over the strings of one prefix that pulls them in pages from a cursor, in the order of their text.

```cpp
class strings_stream_t
```

As shorthand for a range-based loop, which has no place for an arena, it owns one arena for its lifetime, where `[strings_cursor_t](#strings_cursor_t)` takes the caller's per pull. The prefix it walks is borrowed, so it outlives the stream, a page short of the read-ahead ends the walk, and a default-constructed stream is the end of every walk.

## default_read_ahead_k

Strings one page of a walk pulls.

```cpp
std::size_t default_read_ahead_k;
```

## strings_stream_t

```cpp
strings_stream_t() noexcept=default;
```

```cpp
strings_stream_t(strings_stream_t &&) noexcept=default;
```

```cpp
strings_stream_t(strings_stream_t const &)=delete;
```

## operator=

```cpp
strings_stream_t & operator=(strings_stream_t &&) noexcept=default;
```

```cpp
strings_stream_t & operator=(strings_stream_t const &)=delete;
```

## seek

Restarts the walk at `start`, which is returned too when the collection holds it, through a cursor opened there.

```cpp
status_t seek(value_view_t start) noexcept;
```

## seek_to_first

Restarts the walk at the first string of the prefix.

```cpp
status_t seek_to_first() noexcept;
```

## operator++

Advances like `advance`, but a failed pull ends the walk since a reference carries no status.

```cpp
strings_stream_t & operator++() noexcept;
```

## strings_batch

The whole page in hand, passed strings included, which the next `advance` leaves behind.

```cpp
sz::strings_view_t strings_batch() noexcept;
```

## operator==

```cpp
bool operator==(strings_stream_t const & other) const noexcept;
```

## make

Opens a walk over the strings of `prefix` in `collection`, pulling `read_ahead` of them a page into an arena made where the executor of [`receiver`](https://www.unum.cloud/docs/ustore/cpp/quickstart.md#receiver) computes.

```cpp
expected<strings_stream_t> make(
    receiver_t receiver,
    ustore_collection_id_t collection,
    value_view_t prefix,
    std::size_t read_ahead = default_read_ahead_k) noexcept;
```

## place_batch_t

The locations of a batched read or write, as the C ABI receives them.

```cpp
struct place_batch_t
```

## same_collection

Whether every task addresses the same collection.

```cpp
bool same_collection() const noexcept;
```

## *

The collections as the C ABI takes them.

```cpp
ustore_collections_view_t collections() const noexcept;
```

- `collections`
- `keys`

## strided

Views a contiguous container as a strided span that steps by the size of its elements.

```cpp
template <std::ranges::contiguous_range container_type_>
requires std::ranges::sized_range<container_type_>
strided_span<std::remove_reference_t<std::ranges::range_reference_t<container_type_>>> strided(
    container_type_ && container) noexcept;
```

```cpp
template <typename element_type_>
strided_span<element_type_> strided(
    element_type_ *begin,
    element_type_ *end) noexcept;
```

Views the contiguous elements from `begin` up to `end` as a strided span.

```cpp
template <typename view_type_>
requires requires(view_type_ view) { { *view.data }; { view.stride } -> std::convertible_to<ustore_size_t>; }
strided_iterator<std::remove_reference_t<decltype(*view_type_ {}.data)>> strided(
    view_type_ view) noexcept;
```

Iterates the strided run `view` of the C ABI describes, such as a `[ustore_keys_view_t](https://www.unum.cloud/docs/ustore/c/collections.md#ustore_keys_view_t)`, null when it has no data.

## tape_of

The tape `strings` pass to the C ABI as, or a zeroed view, the input's default, when they hold none.

```cpp
ustore_strings_view_t tape_of(values_tape_t const & strings) noexcept;
```

## strings_of

StringZilla's view of the `count` strings of an output `tape`, of either offset width.

```cpp
sz::strings_view_t strings_of(
    ustore_strings_view_t const & tape,
    std::size_t count) noexcept;
```

## tape_string

The string at `index` of an output `tape`, read through the offsets its layout names.

```cpp
ustore_bytes_view_t tape_string(
    ustore_strings_view_t const & tape,
    std::size_t index) noexcept;
```

## tape_slice

The strings of an output `tape` from `first` on, viewing the same bytes, as a slice keeps its parent's offsets.

```cpp
ustore_strings_view_t tape_slice(
    ustore_strings_view_t tape,
    std::size_t first) noexcept;
```

## scan_strings_page

Scans one page of up to `limit` strings of `prefix` from `start` into `arena`, keeping the strings `match` admits and writing one BM25 score per string into `scores` when it is not null and the patterns carry weights.

```cpp
expected<sz::strings_view_t> scan_strings_page(
    receiver_t const & receiver,
    ustore_watch_t watch,
    ustore_collection_id_t const & collection,
    value_view_t const & prefix,
    value_view_t const & start,
    std::size_t limit,
    ustore_arena_t arena,
    match_t const & match = {},
    float const **scores = nullptr) noexcept;
```

## value_view

Views the bytes of a contiguous container.

```cpp
template <std::ranges::contiguous_range container_type_>
requires std::ranges::sized_range<container_type_>
value_view_t value_view(container_type_ && container) noexcept;
```

