tiny.reducer.reduce
Defined in bytes.reduction.
Shortens an initial byte sequence against the caller's failure predicate.
Source
Source: lib/reducer/src/bytes/reduce.zig:205
zig
/// Shortens an initial byte sequence against the caller's failure predicate.////// ## Preconditions////// - `storage` sits in the `alloc_phase.capacity.Phase.steady` phase, which/// `storage.activate()` reaches after `Storage.init()`./// - No other run holds `storage`, so `storage.status().in_use` is false./// - `initial.len` is at most `storage.status().max_input_bytes`./// - The memory of `initial` stays valid and unchanged for the whole call./// - The oracle answers interesting for `initial`./// - `settings.max_attempts` is above 0.////// ## Execution Semantics and Error Isolation////// 1. A `settings.max_attempts` of 0 returns `error.AttemptBudgetExhausted` at/// once, without reaching for the workspace, so an earlier run's hold on the/// workspace stands untouched./// 2. The call then acquires the workspace. A workspace another run already/// holds returns `error.ReductionStorageInUse`, and an `initial.len` above/// the capacity returns `error.InputCapacityExceeded`. Both return before/// any workspace byte changes, so a call refused as busy leaves an earlier/// live `Result` holding its lease./// 3. Once the workspace is acquired, `errdefer storage.release()` gives up/// this run's lease on any later failure. Giving up the lease restores/// neither the scratch bytes the run overwrote nor any side effect the/// callback produced./// 4. The oracle calls start with attempt 1 on `initial`, where the oracle/// receives the caller's own slice before any copy. An `initial` the oracle/// answers uninteresting for returns `error.InitialInputUninteresting` and/// gives up the lease./// 5. The call then tests chunk deletions of the current chunk size, starting/// at `current.len` and halving with ceiling division down to 1. Each trial/// candidate is built in the scratch lane by copying the bytes that survive/// the deletion, through `without()`./// 6. When the oracle accepts a candidate, the locals `current` and `spare`/// swap without copying bytes back, `reductions` goes up by one, and `chunk`/// resets to the new `current.len`./// 7. The call terminates on one of three conditions:/// - A full pass at a chunk of 1 that finishes with every unit deletion/// rejected sets `completion = .one_minimal`, and that final sweep may/// finish on the exact last allowed attempt./// - A `current.len` of 0 sets `completion = .one_minimal`./// - An `attempts` count that reaches `settings.max_attempts` leaves/// `completion = .budget_exhausted`.////// ## Memory and Allocation////// Once the workspace is acquired, the loop calls no allocator of its own, the/// workspace owns every byte the run touches, and the memory the callback/// allocates along with its side effects sit outside that account.////// ## Errors////// It returns `Error`, which is `Exhaustion || InputError`, or any error the/// oracle returned. Only an error raised after the workspace was acquired gives/// up the lease.////// ## Example////// ```zig/// const std = @import("std");/// const reducer = @import("reducer");////// const Context = struct { needle: []const u8 };////// fn checkContains(input: []const u8, ctx_ptr: *anyopaque) anyerror!reducer.Interesting {/// const ctx: *const Context = @ptrCast(@alignCast(ctx_ptr));/// return if (std.mem.indexOf(u8, input, ctx.needle) != null)/// .interesting/// else/// .uninteresting;/// }////// test "basic reduce invocation" {/// const allocator = std.testing.allocator;/// const initial_input = "prefix_ERR_suffix";/// var storage = try reducer.Storage.init(allocator, .{/// .max_input_bytes = initial_input.len,/// });/// defer storage.deinit(allocator);/// storage.activate();////// var ctx = Context{ .needle = "ERR" };/// var res = try reducer.reduce(&storage, initial_input, checkContains, &ctx, .{});/// defer res.deinit();////// try std.testing.expectEqualSlices(u8, "ERR", res.bytes);/// try std.testing.expectEqual(reducer.Completion.one_minimal, res.completion);/// }/// ```pub fn reduce( storage: *storage_mod.Storage, initial: []const u8, interesting_fn: model.InterestingFn, context: *anyopaque, settings: model.Settings,) anyerror!Result { if (settings.max_attempts == 0) return error.AttemptBudgetExhausted; const regions = try storage.acquire(initial.len); errdefer storage.release(); std.debug.assert(regions.current.len == initial.len); std.debug.assert(regions.candidate.len >= initial.len -| 1); var attempts: usize = 1; if (try interesting_fn(initial, context) == .uninteresting) { return error.InitialInputUninteresting; } @memcpy(regions.current, initial); var current = regions.current; var spare = regions.candidate; var reductions: usize = 0; var chunk = current.len; var completion: model.Completion = if (current.len == 0) .one_minimal else .budget_exhausted; while (chunk > 0 and attempts < settings.max_attempts) { var improved = false; var sweep_finished = false; var start: usize = 0; while (start < current.len and attempts < settings.max_attempts) { const end = if (chunk > current.len - start) current.len else start + chunk; const candidate = without(spare, current, start, end); attempts += 1; const candidate_status = try interesting_fn(candidate, context); if (candidate_status == .interesting) { std.debug.assert(candidate.len < current.len); spare = current; current = candidate; reductions += 1; chunk = current.len; improved = true; if (current.len == 0) completion = .one_minimal; break; } if (end == current.len) { sweep_finished = true; break; } start += chunk; } if (improved) continue; if (chunk == 1) { if (sweep_finished) completion = .one_minimal; break; } if (!sweep_finished) break; chunk = chunk / 2 + chunk % 2; } std.debug.assert(attempts <= settings.max_attempts); std.debug.assert(current.len <= initial.len); if (completion == .one_minimal and current.len > 0) { std.debug.assert(chunk == 1); } return makeResult(storage, current, attempts, reductions, completion);}Source: lib/reducer/src/root.zig:354
zig
/// Shortens an initial byte sequence against the caller's oracle.pub const reduce = bytes.reduce;Also reachable as
Audit
| Definitions | 1 |
|---|---|
| Public names | 3 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |