# Graphs

> UStore for C++

A `graph_collection_t` batches edges and vertices, and can be used from inside a transaction like any other handle:

```cpp
auto [graph, status] = db.create<graph_collection_t>("graph");
status = graph.write_edge(edge_t {key_from_integer(1), key_from_integer(2), key_from_integer(9)});

std::array<edge_t, 2> triplets {edge_t {key_from_integer(2), key_from_integer(3), key_from_integer(10)}, edge_t {key_from_integer(3), key_from_integer(4), key_from_integer(11)}};
status = graph.write_edges(edges(triplets));

expected<ustore_vertex_degree_t> degree = graph.degree(key_from_integer(2));
expected<bool> present = graph.present(key_from_integer(2));
auto successors = graph.successors(key_from_integer(2), arena);
auto between = graph.edges_between(key_from_integer(1), key_from_integer(2), arena);
auto touching = graph.read_edges(key_from_integer(3), arena, ustore_vertex_role_target_k);

std::array<ustore_key_t, 3> vertices {key_from_integer(1), key_from_integer(7), key_from_integer(2)};
expected<edges_view_t> leaving = graph.read_edges(strided(vertices).immutable(), arena);
edges_view_t of_missing = leaving->of_vertex(1); // empty, as vertex 7 is missing
```

`degree` and `present` of one vertex are shorthand, copying a scalar out of a one-off arena, while edges, neighbors and the degrees of a batch land in the arena the call is given.
The edges of a batch come in the order of its vertices, and their `offsets` split them by vertex, so `of_vertex(i)` views the edges of vertex `i` and a missing vertex has none.
`edges` streams every edge of the collection, and `vertex_stream` every vertex, both reading ahead in batches.

`#include <ustore/graph_collection.hpp>`

`#include <ustore/graph_stream.hpp>`

`#include <ustore/ranges.hpp>`

## graph_collection_t

A handle to one graph collection that reads and writes the head or the view of a transaction.

```cpp
class graph_collection_t
```

## edges_span

Edges as three strided columns of sources, targets and edge identifiers, which the offsets of the read that exported them split by vertex.

```cpp
template <typename id_type_>
struct edges_span
```

- `sources` `strided_span<id_type_>`
- `targets` `strided_span<id_type_>`
- `ids` `strided_span<id_type_>`
- `offsets` `std::span<ustore_length_t const>`: One offset per vertex of the read plus one, counted in edges, where a missing vertex spans none; empty for edges no read exported.

## graph_read_collection_t

A handle to one graph collection that only reads, stored as an inverted index from every vertex to its edges, cheap to construct and to copy.

```cpp
class graph_read_collection_t
```

It holds no state of its own, so any number of threads share it, at the head, inside a transaction or at a snapshot.

## read_only_t

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

```cpp
using read_only_t = graph_read_collection_t;
```

## deferred_t

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

```cpp
using deferred_t = deferred_graph_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;
```

## graph_read_collection_t

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

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

## degree

Reads the degree of `vertex` in `role` through a one-off arena.

```cpp
expected<ustore_vertex_degree_t> degree(
    ustore_key_t vertex,
    ustore_vertex_role_t role = ustore_vertex_role_any_k,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## degrees

Reads the degree of every vertex into `arena`.

```cpp
expected<std::span<ustore_vertex_degree_t const>> degrees(
    strided_span<ustore_key_t const> vertices,
    arena_t & arena,
    strided_span<ustore_vertex_role_t const> roles = {},
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## present

Checks whether `vertex` is present through a one-off arena, including a vertex without edges, as a vertex whose degree is known.

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

```cpp
expected<bits_view_t> present(
    strided_span<ustore_key_t const> const & vertices,
    std::span<ustore_octet_t> presences,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Marks in `presences`, one bit per vertex, which of `vertices` are present, including those without any edges, reading their degrees into `arena`.

Statuses: - `status_code_t::invalid_argument_k` The `presences` hold fewer bits than `vertices`.

## size

Counts the vertices by streaming through all of them.

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

## number_of_edges

Counts the edges by streaming through the outgoing edges of every vertex.

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

## read_edges

Reads every edge that has `vertex` in `role` into `arena`.

```cpp
expected<edges_view_t> read_edges(
    ustore_key_t vertex,
    arena_t & arena,
    ustore_vertex_role_t role = ustore_vertex_role_any_k,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

```cpp
expected<edges_view_t> read_edges(
    strided_span<ustore_key_t const> vertices,
    arena_t & arena,
    strided_span<ustore_vertex_role_t const> roles = {},
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

Reads every edge that has any of `vertices` in an allowed role into `arena`, split by vertex through the offsets of the answer, where undirected graphs may repeat an edge reversed.

## edges_between

Reads the edges from `source` to `target` into `arena`.

```cpp
expected<edges_view_t> edges_between(
    ustore_key_t source,
    ustore_key_t target,
    arena_t & arena,
    ustore_watch_t watch = ustore_watch_keys_k) noexcept;
```

## successors

Reads the targets of the edges leaving `vertex` into `arena`.

```cpp
expected<strided_span<ustore_key_t const>> successors(
    ustore_key_t vertex,
    arena_t & arena) noexcept;
```

## predecessors

Reads the sources of the edges entering `vertex` into `arena`.

```cpp
expected<strided_span<ustore_key_t const>> predecessors(
    ustore_key_t vertex,
    arena_t & arena) noexcept;
```

## neighbors

Lists the distinct neighbors of `vertex` in `arena`, reordering the edges it fetched there in place.

```cpp
expected<strided_span<ustore_key_t const>> neighbors(
    ustore_key_t vertex,
    arena_t & arena,
    ustore_vertex_role_t role = ustore_vertex_role_any_k) noexcept;
```

## graph_stream_t

A stream of every edge in a graph, pulled one page of vertices at a time from the vertex scans of its stream and in no particular order, the vertices into the arena of that stream and their edges into an arena of its own, as a read never takes its inputs from the arena it rewinds.

```cpp
class graph_stream_t
```

It owns both for its lifetime as shorthand for a range-based loop, with no place for an arena. A default-constructed stream is at the end.

## graph_stream_t

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

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

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

## operator=

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

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

## operator++

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

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

## edges_batch

Exposes the whole fetched page, passed edges included, for use with [`seek_to_next_batch`](https://www.unum.cloud/docs/ustore/cpp/scans.md#seek_to_next_batch).

```cpp
edges_view_t edges_batch() noexcept;
```

## operator==

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

## make

Opens a stream over the edges of `collection` in `role`, from the vertex `start` onwards, fetching the edges of `read_ahead` vertices a page.

```cpp
expected<graph_stream_t> make(
    receiver_t receiver,
    ustore_collection_id_t collection,
    ustore_vertex_role_t role,
    ustore_key_t start,
    std::size_t read_ahead = keys_stream_t::default_read_ahead_k) noexcept;
```

## exported_edges

The edges a read of `count` vertices exported into its arena, split by vertex through its `offsets`.

```cpp
edges_view_t exported_edges(
    ustore_key_t const *edges,
    ustore_length_t const *offsets,
    std::size_t count) noexcept;
```

## edges

Views a contiguous container of `edge_t` as strided edge columns.

```cpp
template <std::ranges::contiguous_range tuples_type_>
requires std::ranges::sized_range<tuples_type_>
auto edges(tuples_type_ && tuples) noexcept;
```

