Module Stateful.Pool

type 'a t

A pool of previously generated values. They are populated with the results of rules and may be used as arguments to later rules. A pool lets data flow from one rule to another, so a rule can act on a handle or identifier that an earlier rule produced rather than on a freshly drawn value.

Create one with create and populate it with add. To draw from the pool, use the following generators:

  • values_reusable: drawing from it returns a value in the pool without removing it.
  • values_consumed: drawing from it removes a value from the pool and returns it.

Example: a resource allocator. The alloc rule creates a fresh handle and deposits it in the pool. The free rule draws one of those handles back out and releases it. Without a pool, free would have no way to name a handle that a previous alloc actually created. It could only draw an arbitrary integer, most of which name no live resource.

type state =
  { live : Int.Set.t
  ; handles : int Stateful.Pool.t
  }

let alloc =
  Stateful.Rule.create ~name:"alloc" ~step:(fun _tc state ->
      let h = fresh_handle () in
      Stateful.Pool.add state.handles h;
      { state with live = Set.add state.live h })

let free =
  Stateful.Rule.create ~name:"free" ~step:(fun tc state ->
      (* draws a handle a prior [alloc] put in the pool *)
      let h = draw_silent tc (Stateful.Pool.values_consumed state.handles) in
      release h;
      { state with live = Set.remove state.live h })
val create : test_case -> 'a t

Creates an empty Pool.t. Pools are tied to a test case; do not reuse one across test cases.

val add : 'a t -> 'a -> unit

Records value in variables for later draws.

let n = draw tc (Generators.integers ~min_value:0 ~max_value:100 ()) in
Stateful.Pool.add pool n
val size : _ t -> int

Returns the number of variables in the pool.

assume tc (Stateful.Pool.size pool > 0)
val values_reusable : 'a t -> ('a, Generators.unprintable) Generators.generator

Create an unprintable generator that returns a variable from the pool without removing it. Calls assume false if the pool is empty.

let existing = draw_silent tc (Stateful.Pool.values_reusable pool)
val values_consumed : 'a t -> ('a, Generators.unprintable) Generators.generator

Create an unprintable generator that removes and returns a variable from the pool. Calls assume false if the pool is empty.

let taken = draw_silent tc (Stateful.Pool.values_consumed pool)