fn replacement_within_caps<PT: ProtocolTypes>(
trace: &Trace<PT>,
targets: &[TracePath],
representative_size: usize,
new_size: usize,
constraints: &TermConstraints,
) -> boolExpand description
Returns true iff replacing a term of size representative_size by one of size new_size at
every path in targets keeps each affected single step recipe within
constraints.max_result_term_size.
Precondition: the input trace is already within the caps. This is a loop invariant, not
something re-checked here: hand-written seeds are authored within the caps, and every
replacement mutation is reject-whole, so a trace that reached the corpus is always <= max_result_term_size. The size-neutral fast path below relies on it — a shrinking or
size-neutral replacement is accepted in O(1) precisely because it cannot push an already
bounded trace over a cap. The one way to break the invariant is to configure a result cap
below the size of an already-imported seed: such a seed is out of bounds before any mutation,
and a neutral replacement will (correctly, per this contract) keep it that way. Enforcing caps
against oversized inputs is a corpus-boundary concern, out of scope for the mutator.
Efficiency (why we don’t recompute every step’s size):
- a mutation that does not grow the trace (
new_size <= representative_size) can never exceed a cap, so we accept in O(1) without touching any size; - otherwise we only look at the affected steps (those containing a target) — never all steps
— recomputing each such step’s recipe size once, and derive the new whole-trace size as
old_trace_size + n_targets * delta.old_trace_sizeis read from the (already bounded, `<= already-bounded) trace, so it is cheap.