module Pool_intf:sig
..end
A pool stores a bounded-size set of tuples, where client code is responsible for
explicitly controlling when the pool allocates and frees tuples. One create
s a pool
of a certain capacity, which returns an empty pool that can hold that many tuples.
One then uses new
to allocate a tuple, which returns a Pointer.t
to the tuple.
One then uses get
and set
along with the pointer to get and set slots of the
tuple. Finally, one free
's a pointer to the pool's memory for tuple, making the
memory available for subsequent reuse.
The point of Pool
is to allocate a single long-lived block of memory (the pool) that
lives in the OCaml major heap, and then to reuse the block, rather than continually
allocating blocks on the minor heap.
In typical usage, one wraps up a pool with an abstract interface, giving nice names to the tuple slots, and only exposing mutation where desired.
All the usual problems with manual memory allocation are present with pools:
Pool.Debug
and Pool.Error_check
, that are useful for
building pools to help debug incorrect pointer usage.val __pa_ounit_275876e34cf609db118f3d84b799a790 : string
A pool stores a bounded-size set of tuples, where client code is responsible for
explicitly controlling when the pool allocates and frees tuples. One create
s a pool
of a certain capacity, which returns an empty pool that can hold that many tuples.
One then uses new
to allocate a tuple, which returns a Pointer.t
to the tuple.
One then uses get
and set
along with the pointer to get and set slots of the
tuple. Finally, one free
's a pointer to the pool's memory for tuple, making the
memory available for subsequent reuse.
The point of Pool
is to allocate a single long-lived block of memory (the pool) that
lives in the OCaml major heap, and then to reuse the block, rather than continually
allocating blocks on the minor heap.
In typical usage, one wraps up a pool with an abstract interface, giving nice names to the tuple slots, and only exposing mutation where desired.
All the usual problems with manual memory allocation are present with pools:
Pool.Debug
and Pool.Error_check
, that are useful for
building pools to help debug incorrect pointer usage.module type S =sig
..end
S
is the module type for a pool.
module type Pool =sig
..end
A pool stores a bounded-size set of tuples, where client code is responsible for
explicitly controlling when the pool allocates and frees tuples. One create
s a pool
of a certain capacity, which returns an empty pool that can hold that many tuples.
One then uses new
to allocate a tuple, which returns a Pointer.t
to the tuple.
One then uses get
and set
along with the pointer to get and set slots of the
tuple. Finally, one free
's a pointer to the pool's memory for tuple, making the
memory available for subsequent reuse.
The point of Pool
is to allocate a single long-lived block of memory (the pool) that
lives in the OCaml major heap, and then to reuse the block, rather than continually
allocating blocks on the minor heap.
In typical usage, one wraps up a pool with an abstract interface, giving nice names to the tuple slots, and only exposing mutation where desired.
All the usual problems with manual memory allocation are present with pools:
Pool.Debug
and Pool.Error_check
, that are useful for
building pools to help debug incorrect pointer usage.S
is the module type for a pool.'slots
will look like ('a1, ...,
'an) Slots.tn
, and the tuples have type 'a1 * ... * 'an
.null
pointer is a distinct pointer that does not correspond to a tuple in
the pool. It is a function to prevent problems due to the value restriction.'slots
will look like ('a1, ..., 'an) Slots.tn
, and the
pool holds tuples of type 'a1 * ... * 'an
.pointer_is_valid t pointer
returns true
iff pointer
points to a 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.
id_of_pointer t pointer
is an integer which is unique for the lifetime of a tuple
in the pool. When the tuple is freed, the identifier may be reused for another
pointer.
pointer_of_id t pointer
returns the pointer with this identifier. It returns
Error _
if id
does not correspond to any pointer in this pool. pointer_of_id
does not guarantee that the resulting pointer satisfies pointer_is_valid
because
the tuple may not be in use.
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.
capacity
returns the maximum number of tuples that the pool can hold.
length
returns the number of tuples currently in the pool.
0 <= length t <= capacity 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
.
default is 2 * capacity t
is_full t
returns true
if no more tuples can be allocated in t
.
free t pointer
frees the tuple pointed to by pointer
from 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
.
get_tuple t pointer
allocates an OCaml tuple isomorphic to the pool t
's tuple
pointed to by pointer
.
get t pointer slot
gets slot
of the tuple pointed to by pointer
in
pool t
. In the usual way with manual memory management, it is an error to refer
to a pointer that has been free
d. It is also an error to use a pointer with any
pool other than the one the pointer was new
'd from or grow
n to.
unsafe_get
is like get
, but skips bounds checking, and can thus segfault.
unsafe_get
is comparable in speed to get
for immediate values, and 5%-10% faster
for pointers. Since the difference is so small, one should as usual be very
convinced of the speed benefit before using these and introducing the possibility of
segfaults.
set t pointer slot a
sets to a
the slot
of the tuple pointed to by pointer
in pool t
. In the usual way with manual memory management, it is an error to
refer to a pointer that has been free
d. It is also an error to use a pointer with
any pool other than the one the pointer was new
'd from or grow
n to.
unsafe_set
is like set
, but skips bounds checking, and can thus segfault.
Obj_array
is an efficient implementation of pools that uses a single chunk of
memory, and is what an application should ultimately use. 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.
None
is an inefficient implementation of pools that uses OCaml's memory allocator
to allocate each object. It is useful for debugging Obj_array
, as well as
debugging client code that may be misusing pointers.
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
.
The performance of the pool resulting from Debug
is much worse than that of the
input Pool
, even with all the controls set to false
.
Error_check
builds a pool that has additional error checking for pointers, in
particular to catch using a freed pointer or multiply freeing a pointer.
Error_check
has a significant performance cost, but less than that of Debug
.
One can compose Debug
and Error_check
, e.g:
module M = Debug (Error_check (Obj_array))