The segment, and its refcount (L1 views)

Almost every other example on this site opens by allocating a segment and putting a view over it. This page is what that line means.

A segment is the L0↔L1 boundary object: real bytes, the backend that reclaims them, and an intrusive refcount (reference 08). A view is a {owner, offset, length} window over one segment, and it holds a segment_ptr_t — so copying a view clones the reference and the bytes stay alive as long as any view names them. That is the entire safety argument behind zero-copy fan-out: a decoded TLV’s spans remain valid because the view that produced them is still holding its segment.

What to notice

  • Copy means clone, not copy. use_count() moves 1 → 2 → 3 as a view is taken and then copied, and both windows report the same bytes().data(). No payload byte is touched.

  • The last drop is what reclaims. Reclaim is not a destructor on the view; it is the backend’s destroy, fired when the refcount reaches zero — wherever that happens, on whatever thread. The example uses a pool_t over a stack slab so the free slot count moves visibly; the heap backend reclaims just as correctly and invisibly.

  • That “whatever thread” is a real obligation. A subscriber or a transport receive thread is a normal place for a last reference to die, which is why a backend at a shared seam must be thread-safe — see view_sync_pool.

  • use_count() is diagnostics, not synchronization. It is an acquire load for a human, and reading it never makes a decision safe.

  • view_t::over takes the handle by value. Passing a named handle copies it (the count goes up); std::move-ing it transfers. The example passes a copy deliberately so that seg keeps its own reference to inspect.

  • 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 — a segment is refcounted, and copying a view is a refcount bump.
 9 *
10 * The L0↔L1 boundary object is a **segment**: real bytes, the backend that reclaims them,
11 * and an intrusive refcount (`docs/reference/08-views-and-ownership.md`). A **view** is a
12 * `{owner, offset, length}` window over one segment, and it holds a `segment_ptr_t` — so
13 * copying a view CLONES the reference and the bytes stay alive as long as any view names
14 * them. That is the whole safety story behind zero-copy fan-out: a decoded TLV's spans stay
15 * valid because the view that produced them is still holding its segment.
16 *
17 * Reclaim is observed here through a `tr::mem::pool_t` over a stack slab, whose free-slot
18 * count moves — the heap backend would reclaim just as correctly, but invisibly.
19 *
20 * Runs under ctest as `example_view_segment_refcount`; returns non-zero on any failed check.
21 */
22
23#include <array>
24#include <cstddef>
25#include <cstdio>
26#include <optional>
27#include <span>
28
29#include "libtracer/tracer.hpp"
30
31namespace {
32
33/** @brief Report expectation @p what and record a failure on @p ok. */
34void check(bool& ok, bool cond, const char* what) {
35    std::printf("  [%s] %s\n", cond ? "ok" : "FAIL", what);
36    ok = ok && cond;
37}
38
39}  // namespace
40
41int main() {
42    bool ok = true;
43    alignas(std::max_align_t) std::array<std::byte, 1024> slab{};
44    tr::mem::pool_t pool{slab, 64};
45
46    tr::view::segment_ptr_t seg = tr::view::segment_alloc(pool, 8);
47    check(ok, static_cast<bool>(seg), "the pool handed out a segment");
48    if (!seg) return 1;
49    std::printf("fresh segment: use_count=%u, pool has %zu/%zu slots free\n", seg.use_count(),
50                pool.available(), pool.capacity());
51    check(ok, seg.use_count() == 1, "a fresh segment starts at one reference");
52
53    {
54        // over() takes the handle by value, so passing a COPY leaves `seg` holding its own.
55        tr::view::view_t v = tr::view::view_t::over(seg);
56        check(ok, seg.use_count() == 2, "a view over it holds a second reference");
57
58        tr::view::view_t clone = v;  // copy == clone: a refcount bump, never a byte copy
59        check(ok, seg.use_count() == 3, "copying the view clones the reference, not the bytes");
60        check(ok, clone.bytes().data() == v.bytes().data(), "both windows address the same bytes");
61        std::printf("two views later: use_count=%u\n", seg.use_count());
62    }
63    check(ok, seg.use_count() == 1, "the views went out of scope and released");
64    check(ok, pool.available() == pool.capacity() - 1, "the slot is still held — one ref remains");
65
66    seg.reset();  // the LAST reference: this is what fires the backend's destroy
67    std::printf("after the last drop: pool has %zu/%zu slots free\n", pool.available(),
68                pool.capacity());
69    check(ok, pool.available() == pool.capacity(), "the bytes are reclaimed at the last drop");
70    return ok ? 0 : 1;
71}

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