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 samebytes().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 apool_tover 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::overtakes 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 thatsegkeeps 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.