This module assumes that hits in the scan process are at random, and are very unlikely.
machine.h
which optionally defines:
sp_init
function calls to calloc
(3) into larger cached
slabs. Since we never free the memory we allocate for the space this
saves a lot of malloc headers and such. Suggested value of 4096 for
a medium application hit rate, smaller for very rare hit rates.
By default no cache is enabled.
sp_walk
, rather than
the iterative one when set to non-zero.
The recursive one is more complex and slower, as far as I can tell.
#include "machine.h" #include "sparse.h"
This structure provides a cheap way to record which integer values a program has "seen" or "visited". That is to say we build a list of the values we've been presented, and bind a (void *) to each. This is useful for mapping inodes to uids, or dates to events, or any integer domain to any range you can represent with a pointer to some data structure.
These functions are limited to construction of
a sparse space: no mechanism (short of exit
(3)) is
provided to remove any allocated space. This is fine for the use intended.
An alternative implementation via
AVL trees would trivially
provide a "clean" version.
More modern allocation system may eliminate this issue.
Most of the configuration is done at run-time. The compile-time options are limited at present.
extern sp_key sp_fibs[];
extern size_t sp_unfib(sp_key wN);
sp_key
array which contains the
Fibonacci that is closest the wN
without
going over.
extern void **sp_init(sp_key wRange);
(void **)
which can represent unsigned
integers up to and including wRange
(starting
at zero). This is the only way to build an empty sparse space, do
not try to make your own.
extern void **sp_index(void **ppvFrom, sp_key wFind);
(void **)
which is bound to
the integer wFind
in the sparse space ppcFrom
. To mark the value as
used set the (void *) indexed by the return value to a non-NULL
value (any one works).
Later, when sp_walk
ing the space this
(void *)
is the second parameter passed to
the Map
function.
extern int sp_walk(void **ppvFrom, sp_key wLow, sp_key wHi, int (*pfiMap)(sp_key, void *));
Walk the sparse space given by From
from wLow
to
wHi
calling Map
on each integer that
has a non-NULL (void *)
bound to it.
(sp_key wN, void *pvData) { ... }
The declaration of the function that Map
expects
for sp_walk
.
extern int sp_exists(void **ppvFrom, sp_key wTest);
Test fot the existence of Test
in the sparse space
given by From
. Return zero for "not in the space"
and non-zero for "included".
This test driver inserts a few (unsigned long) integers into a sparse space instance with alternating colors ("red" and "blue"), then walks the space to output each integer and the color it was recorded with.
The integers in the test data were selected to test the corner cases in the walk and index functions.
(void *)
with a CPP macro or
typedef
to make this more MICE-like
really wouldn't gain much, because the internal code that builds
the sparse space needs the pointer type, so we'd have to
union
it in, anyway.
It is possible to expand the range of the sparse space by representing many integers in the (void *) returned, for example each sub-space could represent 2^64-1 integers to allow a space of 2^128-1 integers by the application of 2 layers, any number of layers could be applied to get any range required with very little memory for truly sparse applications.
$Id: sparse.html,v 1.13 2012/03/21 16:15:05 ksb Exp $