Skip to documentation
SLOP

tiny.reducer.bytes.storage

Reference tiny.reducer bytes storage

Defined in bytes.

Storage holds the backing memory a byte reduction run needs, allocated once up front and reused for every run: the workspace.

API (3)

Types and contracts

Public types and contracts.

No direct callersNo direct callsbytesstorage
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/reducer/src/bytes/root.zig:56

zig
/// Module holding the workspace, allocated up front and double-buffered, and/// the phase-checked lifecycle around it.pub const storage = @import("storage.zig");

Source: lib/reducer/src/bytes/storage.zig

zig
//! `Storage` holds the backing memory a byte reduction run needs, allocated//! once up front and reused for every run: the *workspace*. The `alloc_phase`//! checker tracks the phase and establishes that the owner makes no further//! backing allocation once the workspace is activated into steady state.//!//! ## Workspace Lifecycle//!//! | Operation | Effect / Transition |//! | :--- | :--- |//! | `storage.activate()` | Moves `initialization` to `steady (idle)` |//! | `storage.acquire(bytes)` | Leases `steady (idle)` to `steady (acquired)` |//! | `result.deinit()` / `storage.release()` | Releases `steady (acquired)` back to `steady (idle)` |//! | `storage.deinit(allocator)` (unactivated) | Frees unactivated `initialization` to `teardown` |//! | `storage.deinit(allocator)` (idle) | Frees idle `steady` to `teardown` (invalid while acquired) |//!//! 1. **Initialization (`Phase.initialization`)**: `Storage.init()` derives the//!    layout, which comes to $N + \max(N - 1, 0)$ bytes (its *capacity*), and//!    allocates the backing buffer once. The instance starts out with//!    `phase = .initialization`. A workspace that is never activated can be//!    freed straight away by `storage.deinit(allocator)`, using the allocator//!    `init()` received. Filling in `Storage` fields by hand is unsafe, so//!    callers reach a valid workspace through `init()`.//! 2. **Activation (`Phase.steady`)**: the caller calls `storage.activate()`,//!    which seals the initialization phase and moves the workspace to steady//!    and idle. In steady state the workspace owner allocates nothing further.//! 3. **Acquisition (`in_use = true`)**: inside `reduce()`,//!    `storage.acquire(input_bytes)` checks that the workspace is in steady//!    phase, checks that no lease is out, and checks that `input_bytes` is//!    within `max_input_bytes`. It sets `in_use = true` and returns the two//!    byte lanes as `Regions`, returning slices, copying nothing into the//!    witness lane and initializing nothing. An oversized input returns//!    `error.InputCapacityExceeded`, and a request made while a lease is out//!    returns `error.ReductionStorageInUse`, both before any workspace byte//!    changes.//! 4. **Release and reuse (`in_use = false`)**: when a run finishes,//!    `Result.deinit()`, or `storage.release()`, clears `in_use`. The workspace//!    returns to steady and idle, and a later run can acquire it with no//!    further allocation.//! 5. **Teardown (`Phase.teardown`)**: `storage.deinit(allocator)` checks that//!    no lease is out, sets `phase = .teardown`, and frees the backing buffer//!    with the same allocator `init()` received.//!//! ## Ownership and Concurrency Constraints//! - `Storage` offers no thread safety. `in_use` is a plain boolean that turns//!   away a second use on one thread, so reaching one workspace from multiple//!   threads at once is the caller's to synchronize.//! - Zig checks no linear or affine type at compile time, and a runtime check//!   catches no shallow copy of a `Storage` or a `Result`, so one owner holds//!   each of them, makes no shallow duplicate, and leaves the bookkeeping//!   fields alone.//! - The capacity claim `reducer.byte_storage` covers the two internal byte//!   lanes. It leaves out the caller's own initial input bytes, the predicate's//!   context, and every allocation and foreign side effect the callback//!   performs.const std = @import("std");const alloc_phase = @import("alloc_phase");const capacity_mod = @import("capacity.zig");const model = @import("model.zig");/// Pair of memory lane slices `Storage.acquire()` returns. `acquire()` copies/// nothing into these slices and initializes nothing in them: they are/// sub-slices of the backing allocation.pub const Regions = struct {    /// Slice of the witness lane sized to this run's `input_bytes`.    current: []u8,    /// Scratch lane, whose length is `candidate_bytes`, which is    /// $\max(N - 1, 0)$.    candidate: []u8,};/// Snapshot of one workspace's state, taken by value at the moment of the call.pub const Status = struct {    /// Workspace current phase, one of `.initialization`, `.steady`, or    /// `.teardown`.    phase: alloc_phase.capacity.Phase,    /// Flag recording whether a running reduction or a `Result` whose    /// `deinit()` has yet to be called currently holds the workspace.    in_use: bool,    /// Derived capacity the workspace was configured for, which is    /// $N + \max(N - 1, 0)$ bytes. The figure is a record of the configured    /// size, and it stays recorded after teardown.    storage_bytes: usize,    /// Longest input in bytes this workspace serves, which is $N$.    max_input_bytes: usize,};/// Workspace, allocated up front and double-buffered, that carries reduction in/// steady state. It holds the backing allocation and tracks the phase it is in/// and whether a lease is out.pub const Storage = struct {    /// Lifecycle phase that `alloc_phase` enforces.    phase: alloc_phase.capacity.Phase,    /// Layout derived while initializing.    capacity: capacity_mod.Capacity,    /// Entire contiguous backing byte allocation.    bytes: []u8,    /// Fixed sub-slice reserved for the witness lane, spanning $0 \dots N$.    current: []u8,    /// Fixed sub-slice reserved for the scratch lane, spanning    /// $N \dots N + \max(N - 1, 0)$.    candidate: []u8,    /// Flag recording that a lease is out, turning away a reentrant acquisition    /// and one made while an earlier result is still live.    in_use: bool = false,    /// Re-export of the capacity limits type.    pub const Limits: type = capacity_mod.Limits;    /// Re-export of the derived capacity type.    pub const Capacity: type = capacity_mod.Capacity;    /// Re-export of the exhaustion error set.    pub const Exhaustion: type = model.Exhaustion;    /// Errors `Storage.init()` may return.    pub const InitError = std.mem.Allocator.Error || capacity_mod.DeriveError;    /// Stardust capacity declaration that phase-directed allocation    /// verification reads. It records that the workspace owner makes no further    /// backing allocation once sealed into steady state. It bounds the storage    /// by $2 \times \text{max\_input\_bytes}$. It leaves out the memory and the    /// effects the caller's predicate owns.    pub const claim: alloc_phase.capacity.Declaration = .{        .source = .{            .id = "reducer.byte_storage",            .kind = .phase_static,            .limit_source = .caller,            .storage = .{                .covered = &.{                    .{                        .id = "accepted_input_and_borrowed_result_bytes",                        .lifetime = .steady,                        .detail = "accepted input and borrowed result bytes",                    },                    .{                        .id = "deletion_candidate_scratch_bytes",                        .lifetime = .steady,                        .detail = "deletion candidate scratch bytes",                    },                },                .excluded = &.{                    "caller-owned initial input bytes",                    "caller-owned predicate context, allocation, and effects",                },            },            .capacity = .{                .inputs = &.{                    alloc_phase.capacity.bindInput(Limits, "max_input_bytes", "max_input_bytes"),                },                .type_selectors = &.{},                .nodes = &.{                    .{ .input = 0 },                    .{ .scale = .{ .node = 0, .coefficient = .{ .literal = 2 } } },                },                .assertions = &.{.{                    .scope = .closure_total,                    .measure = .retained,                    .relation = .upper_bound,                    .expression = 1,                }},            },            .overload = .{                .kind = .reject_before_mutation,                .detail = "oversize and concurrent requests fail before workspace bytes change",            },            .risks = .{                .transitive = .{                    .status = .witnessed,                    .detail = "reduction uses byte lanes; predicate effects remain caller-owned",                },                .foreign = .{                    .status = .excluded,                    .detail = "predicate and operating-system effects are caller-owned",                },            },            .obligations = &.{                .{ .key = "reducer_byte_capacity", .role = .capacity_model },                .{ .key = "reducer_byte_acquisition", .role = .custom },                .{ .key = "reducer_byte_oom", .role = .custom },                .{ .key = "reducer_byte_boundaries", .role = .overload },                .{ .key = "reducer_byte_reuse", .role = .overload },                .{ .key = "reducer_byte_sealed", .role = .transitive_risk },                .{ .key = "reducer_byte_callback", .role = .foreign_risk },                .{ .key = "reducer_byte_root", .role = .custom },            },        },        .bindings = .{            .owner = @This(),            .seal = .{                .family = alloc_phase.capacity.selector(@This().activate),                .premise = .{                    .class = .checked_semantic_fact,                    .authority = .checker,                },            },            .teardown = .{                .family = alloc_phase.capacity.selector(@This().deinit),                .premise = .{                    .class = .checked_semantic_fact,                    .authority = .checker,                },            },        },    };    /// Allocates a reduction workspace and divides it into the two lanes, sized    /// for inputs up to `limits.max_input_bytes`. The new workspace is in    /// `.initialization`, and the caller calls `storage.activate()` on it    /// before passing it to `reduce()`. A workspace that is never activated can    /// be freed directly by `storage.deinit()`.    ///    /// ## Errors    /// - `error.CapacityOverflow` when $N + \max(N - 1, 0)$ overflows `usize`.    /// - `error.OutOfMemory` when the allocator declines the request.    pub fn init(allocator: std.mem.Allocator, limits: Limits) InitError!Storage {        const capacity = try Capacity.derive(limits);        const bytes = try allocator.alloc(u8, capacity.storage_bytes);        const owner = Storage{            .phase = .initialization,            .capacity = capacity,            .bytes = bytes,            .current = bytes[0..limits.max_input_bytes],            .candidate = bytes[capacity.candidate_offset..][0..capacity.candidate_bytes],        };        std.debug.assert(owner.current.len == limits.max_input_bytes);        std.debug.assert(owner.candidate.len == capacity.candidate_bytes);        std.debug.assert(owner.current.len + owner.candidate.len == owner.bytes.len);        return owner;    }    /// Moves the workspace from `.initialization` to `.steady`. Once it    /// returns, the workspace owner makes no further heap allocation.    ///    /// ## Preconditions    /// - `self.phase` is `.initialization`.    /// - The backing allocation's length equals `self.capacity.storage_bytes`.    pub fn activate(self: *Storage) void {        std.debug.assert(self.phase == .initialization);        std.debug.assert(self.bytes.len == self.capacity.storage_bytes);        self.phase = .steady;    }    /// Takes exclusive use of the workspace for a run over `input_bytes` bytes.    /// It returns `Regions` holding sub-slices of the backing buffer. It copies    /// nothing into `Regions.current`.    ///    /// ## Preconditions    /// - `self.phase` is `.steady`.    ///    /// ## Errors    /// - `error.ReductionStorageInUse` when `self.in_use` is already true. A    ///   reentrant call, and a call made while an earlier result is still live,    ///   are both turned away without disturbing the hold that is already out.    /// - `error.InputCapacityExceeded` when `input_bytes` exceeds    ///   `max_input_bytes`.    pub fn acquire(self: *Storage, input_bytes: usize) Exhaustion!Regions {        std.debug.assert(self.phase == .steady);        if (self.in_use) return error.ReductionStorageInUse;        if (input_bytes > self.capacity.limits.max_input_bytes) {            return error.InputCapacityExceeded;        }        std.debug.assert(self.current.len == self.capacity.limits.max_input_bytes);        std.debug.assert(self.candidate.len == self.capacity.candidate_bytes);        self.in_use = true;        return .{            .current = self.current[0..input_bytes],            .candidate = self.candidate,        };    }    /// Gives up this run's lease, returning the workspace to steady and idle so    /// it can serve another run. `Result.deinit()` calls it, and it moves the    /// workspace no closer to teardown.    ///    /// ## Preconditions    /// - `self.phase` is `.steady`.    /// - `self.in_use` is true.    pub fn release(self: *Storage) void {        std.debug.assert(self.phase == .steady);        std.debug.assert(self.in_use);        self.in_use = false;        std.debug.assert(!self.in_use);    }    /// Returns a snapshot of this workspace, taken by value at the moment of    /// the call.    pub fn status(self: *const Storage) Status {        return .{            .phase = self.phase,            .in_use = self.in_use,            .storage_bytes = self.capacity.storage_bytes,            .max_input_bytes = self.capacity.limits.max_input_bytes,        };    }    /// Frees the backing allocation and moves the workspace to `.teardown`. It    /// works on an idle steady workspace and on one still in `.initialization`    /// that was never activated. It needs the same allocator `Storage.init()`    /// received.    ///    /// ## Preconditions    /// - `self.phase` is anything other than `.teardown`.    /// - `self.in_use` is false, so every result has had its `deinit()` called.    pub fn deinit(self: *Storage, allocator: std.mem.Allocator) void {        std.debug.assert(self.phase != .teardown);        std.debug.assert(!self.in_use);        std.debug.assert(self.bytes.len == self.capacity.storage_bytes);        self.phase = .teardown;        allocator.free(self.bytes);        self.bytes = &.{};        self.current = &.{};        self.candidate = &.{};    }};fn checkInitFailures(allocator: std.mem.Allocator) !void {    var storage = try Storage.init(allocator, .{ .max_input_bytes = 9 });    storage.deinit(allocator);}test "byte reduction storage acquires one exact region" {    comptime {        @stardustClaim(            @import("alloc_phase").capacity.witness(Storage, "reducer_byte_acquisition"),            null,            null,            null,            null,            null,            null,        );    }    var counting = std.testing.FailingAllocator.init(std.testing.allocator, .{});    const limits = capacity_mod.Limits{ .max_input_bytes = 9 };    const capacity = try capacity_mod.Capacity.derive(limits);    var storage = try Storage.init(counting.allocator(), limits);    defer storage.deinit(counting.allocator());    try std.testing.expectEqual(@as(usize, 1), counting.alloc_index);    try std.testing.expectEqual(capacity.storage_bytes, counting.allocated_bytes);    try std.testing.expectEqual(alloc_phase.capacity.Phase.initialization, storage.status().phase);    storage.activate();    const regions = try storage.acquire(9);    defer storage.release();    try std.testing.expectEqual(@intFromPtr(storage.bytes.ptr), @intFromPtr(regions.current.ptr));    try std.testing.expectEqual(        @intFromPtr(storage.bytes.ptr) + capacity.candidate_offset,        @intFromPtr(regions.candidate.ptr),    );}test "byte reduction storage retries after every allocation failure" {    comptime {        @stardustClaim(            @import("alloc_phase").capacity.witness(Storage, "reducer_byte_oom"),            null,            null,            null,            null,            null,            null,        );    }    try std.testing.checkAllAllocationFailures(std.testing.allocator, checkInitFailures, .{});}comptime {    alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage);}

Audit

Definitions2
Public names2
Members2
Version26.7.0
Revisiondaab053ee433