replacement_within_caps

Function replacement_within_caps 

Source
fn replacement_within_caps<PT: ProtocolTypes>(
    trace: &Trace<PT>,
    targets: &[TracePath],
    representative_size: usize,
    new_size: usize,
    constraints: &TermConstraints,
) -> bool
Expand 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_size is read from the (already bounded, `<= already-bounded) trace, so it is cheap.