Module Tuple_pool

module Tuple_type : sig ... end
module type S = sig ... end

This uses a Uniform_array.t to implement the pool. We expose that Pointer.t is an int so that OCaml can avoid the write barrier, due to knowing that Pointer.t isn't an OCaml pointer.

Slots has types t1, ..., t12 of arities 1 to 12 that are isomorphic to tuple types of the corresponding arities. Type ('a0, ..., 'a<N-1>) t<N> corresponds to 'a0 * ... * 'a<N-1>.

module Pointer : sig ... end
type 'slots t

A pool. 'slots will look like ('a1, ..., 'an) Slots.tn, and the pool holds tuples of type 'a1 * ... * 'an.

val sexp_of_t : ('slots -> Ppx_sexp_conv_lib.Sexp.t) -> 'slots t -> Ppx_sexp_conv_lib.Sexp.t
include Core_kernel.Invariant.S1 with type 'a t := 'a t
val invariant : ('a -> unit) -> 'a t -> unit
val pointer_is_valid : 'slots t -> 'slots Pointer.t -> bool

pointer_is_valid t pointer returns true iff pointer points to a live tuple in t, i.e. pointer is not null, not free, and is in the range of t.

A pointer might not be in the range of a pool if it comes from another pool for example. In this case unsafe_get/set functions would cause a segfault.

val id_of_pointer : 'slots t -> 'slots Pointer.t -> Pointer.Id.t

id_of_pointer t pointer returns an id that is unique for the lifetime of pointer's tuple. When the tuple is freed, the id is no longer valid, and pointer_of_id_exn will fail on it. Pointer.null () has a distinct id from all non-null pointers.

val pointer_of_id_exn : 'slots t -> Pointer.Id.t -> 'slots Pointer.t

pointer_of_id_exn t id returns the pointer corresponding to id. It fails if the tuple corresponding to id was already freed.

val create : ('tuple_) Slots.t as 'slots -> capacity:int -> dummy:'tuple -> 'slots t

create slots ~capacity ~dummy creates an empty pool that can hold up to capacity N-tuples. The slots of dummy are stored in free tuples. create raises if capacity < 0 || capacity > max_capacity ~slots_per_tuple.

val max_capacity : slots_per_tuple:int -> int

max_capacity returns the maximum capacity allowed when creating a pool.

val capacity : _ t -> int

capacity returns the maximum number of tuples that the pool can hold.

val length : _ t -> int

length returns the number of tuples currently in the pool.

0 <= length t <= capacity t
val grow : ?capacity:int -> 'a t -> 'a t

grow t ~capacity returns a new pool t' with the supplied capacity. The new pool is to be used as a replacement for t. All live tuples in t are now live in t', and valid pointers to tuples in t are now valid pointers to the identical tuple in t'. It is an error to use t after calling grow t.

grow raises if the supplied capacity isn't larger than capacity t.

val is_full : _ t -> bool

is_full t returns true if no more tuples can be allocated in t.

val free : 'slots t -> 'slots Pointer.t -> unit

free t pointer frees the tuple pointed to by pointer from t.

val unsafe_free : 'slots t -> 'slots Pointer.t -> unit

unsafe_free t pointer frees the tuple pointed to by pointer without checking pointer_is_valid

val new1 : 'a0 Slots.t1 as 'slots t -> 'a0 -> 'slots Pointer.t

new<N> t a0 ... a<N-1> returns a new tuple from the pool, with the tuple's slots initialized to a0 ... a<N-1>. new raises if is_full t.

val new2 : ('a0'a1) Slots.t2 as 'slots t -> 'a0 -> 'a1 -> 'slots Pointer.t
val new3 : ('a0'a1'a2) Slots.t3 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'slots Pointer.t
val new4 : ('a0'a1'a2'a3) Slots.t4 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'slots Pointer.t
val new5 : ('a0'a1'a2'a3'a4) Slots.t5 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'slots Pointer.t
val new6 : ('a0'a1'a2'a3'a4'a5) Slots.t6 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'slots Pointer.t
val new7 : ('a0'a1'a2'a3'a4'a5'a6) Slots.t7 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'slots Pointer.t
val new8 : ('a0'a1'a2'a3'a4'a5'a6'a7) Slots.t8 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'slots Pointer.t
val new9 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8) Slots.t9 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'slots Pointer.t
val new10 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8'a9) Slots.t10 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'a9 -> 'slots Pointer.t
val new11 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8'a9'a10) Slots.t11 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'a9 -> 'a10 -> 'slots Pointer.t
val new12 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8'a9'a10'a11) Slots.t12 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'a9 -> 'a10 -> 'a11 -> 'slots Pointer.t
val new13 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8'a9'a10'a11'a12) Slots.t13 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'a9 -> 'a10 -> 'a11 -> 'a12 -> 'slots Pointer.t
val new14 : ('a0'a1'a2'a3'a4'a5'a6'a7'a8'a9'a10'a11'a12'a13) Slots.t14 as 'slots t -> 'a0 -> 'a1 -> 'a2 -> 'a3 -> 'a4 -> 'a5 -> 'a6 -> 'a7 -> 'a8 -> 'a9 -> 'a10 -> 'a11 -> 'a12 -> 'a13 -> 'slots Pointer.t
val get_tuple : ('tuple_) Slots.t as 'slots t -> 'slots Pointer.t -> 'tuple

get_tuple t pointer allocates an OCaml tuple isomorphic to the pool t's tuple pointed to by pointer. The tuple gets copied, but its slots do not.

val get : (_'variant) Slots.t as 'slots t -> 'slots Pointer.t -> ('variant'slot) Slot.t -> 'slot

get t pointer slot gets slot of the tuple pointed to by pointer in pool t.

set t pointer slot a sets to a the slot of the tuple pointed to by pointer in pool t.

In get and set, it is an error to refer to a pointer that has been freed. It is also an error to use a pointer with any pool other than the one the pointer was new'd from or grown to. These errors will lead to undefined behavior, but will not segfault.

unsafe_get is comparable in speed to get for immediate values, and 5%-10% faster for pointers.

unsafe_get and unsafe_set skip bounds checking, and can thus segfault.

val unsafe_get : (_'variant) Slots.t as 'slots t -> 'slots Pointer.t -> ('variant'slot) Slot.t -> 'slot
val set : (_'variant) Slots.t as 'slots t -> 'slots Pointer.t -> ('variant'slot) Slot.t -> 'slot -> unit
val unsafe_set : (_'variant) Slots.t as 'slots t -> 'slots Pointer.t -> ('variant'slot) Slot.t -> 'slot -> unit
module Unsafe : sig ... end

An Unsafe pool is like an ordinary pool, except that the create function does not require an initial element. The pool stores a dummy value for each slot. Such a pool is only safe if one never accesses a slot from a freed tuple.

module Debug (Tuple_pool : S) : sig ... end

Debug builds a pool in which every function can run invariant on its pool argument(s) and/or print a debug message to stderr, as determined by !check_invariant and !show_messages, which are initially both true.

module Error_check (Tuple_pool : S) : S

Error_check builds a pool that has additional error checking for pointers, in particular to detect using a freed pointer or multiply freeing a pointer.