subview: narrowing a window costs arithmetic (L1 views)

A view is {owner, offset, length}, so narrowing one is arithmetic on the offset and the length plus a refcount bump (reference 08). This is the primitive every zero-copy slice in the library reduces to: a child TLV’s payload, a routed path suffix, a value handed to a subscriber. The pointers are the proof — a sub-window’s bytes().data() is the parent’s plus the offset, in the same segment.

What to notice

  • Nesting composes against the segment, not the window. whole.subview(4, 8).subview(2, 4) has offset == 6 — offsets accumulate, and the second call’s 2 is relative to the first window. Reading byte 0 of the inner view yields byte 6 of the segment.

  • Narrowing extends lifetime. The sub-window holds its own reference, so it may outlive the wide view it came from. That is what lets a decoder hand a caller a payload and forget the frame.

  • The window invariant is debug-asserted. bytes() asserts offset + length <= owner->bytes.size() — zero cost in a release build, and the reason an out-of-bounds window is caught at its source on the sanitizer CI leg rather than as a mysterious read somewhere downstream.

  • A view is one contiguous window over one segment. Spanning several segments is the rope’s job, and taking a sub-range of one is subrope — the same idea one level up.

  • Nothing here is conditional — the target builds and runs under every CI leg.

Source

 1/*
 2 * SPDX-License-Identifier: Apache-2.0
 3 * SPDX-FileCopyrightText: Copyright 2026 avatarsd LLC
 4 */
 5
 6/**
 7 * @file
 8 * @brief ONE CONCEPT — `subview`: a narrower window over the SAME segment, no copy.
 9 *
10 * A view is `{owner, offset, length}`, so narrowing it is arithmetic on the offset and the
11 * length plus a refcount bump — never a memcpy (`docs/reference/08-views-and-ownership.md`).
12 * This is the primitive every zero-copy slice in the library is built from: a child TLV's
13 * payload, a routed path suffix, a value handed to a subscriber. The pointers prove it —
14 * a sub-window's `bytes().data()` is the parent's plus the offset, in the same segment.
15 *
16 * Narrowing also EXTENDS lifetime: the sub-window holds its own reference, so the segment
17 * outlives the wide view it came from. `view_t::bytes()` debug-asserts the window invariant
18 * (`offset + length <= owner->bytes.size()`), which is why the sanitizer CI leg is where an
19 * out-of-bounds window is caught at its source.
20 *
21 * Runs under ctest as `example_view_subview`; returns non-zero on any failed check.
22 */
23
24#include <cstddef>
25#include <cstdio>
26#include <optional>
27
28#include "libtracer/tracer.hpp"
29
30namespace {
31
32/** @brief Report expectation @p what and record a failure on @p ok. */
33void check(bool& ok, bool cond, const char* what) {
34    std::printf("  [%s] %s\n", cond ? "ok" : "FAIL", what);
35    ok = ok && cond;
36}
37
38}  // namespace
39
40int main() {
41    bool ok = true;
42    tr::view::segment_ptr_t seg = tr::view::heap_alloc(16);
43    check(ok, static_cast<bool>(seg), "a 16-byte heap segment");
44    if (!seg) return 1;
45    for (std::size_t i = 0; i < seg->bytes.size(); ++i) seg->bytes[i] = static_cast<std::byte>(i);
46
47    const tr::view::view_t whole = tr::view::view_t::over(seg);
48    check(ok, whole.length == 16, "over() covers the whole segment");
49
50    const tr::view::view_t mid = whole.subview(4, 8);  // bytes 4..11
51    std::printf("whole=[0,16) sub=[%zu,%zu) use_count=%u\n", mid.offset, mid.offset + mid.length,
52                seg.use_count());
53    check(ok, mid.length == 8 && mid.offset == 4, "the sub-window is {offset, length} arithmetic");
54    check(ok, mid.bytes().data() == whole.bytes().data() + 4,
55          "and addresses the parent's bytes directly — zero copies");
56
57    const tr::view::view_t inner = mid.subview(2, 4);  // bytes 6..9, relative to `mid`
58    check(ok, inner.offset == 6, "nesting composes offsets against the SEGMENT, not the window");
59    check(ok, inner.bytes()[0] == std::byte{6}, "so the first byte read back is byte 6");
60
61    const std::uint_least32_t held = seg.use_count();
62    check(ok, held == 4, "segment + three windows, each holding its own reference");
63    check(ok, !whole.empty() && !inner.empty(), "a narrowed window is still a view over bytes");
64    return ok ? 0 : 1;
65}

See also: views module · segment module · views & ownership reference.