git-commit-vandalism/vcs-svn/trp.txt
Jonathan Nieder 97a5e3453a treap: make treap_insert return inserted node
Suppose I try the following:

	struct int_node *node = node_pointer(node_alloc(1));
	node->n = 5;
	treap_insert(&root, node);
	printf("%d\n", node->n);

Usually the result will be 5.  But since treap_insert draws memory
from the node pool, if the caller is unlucky then (1) the node pool
will be full and (2) realloc will be forced to move the node pool to
find room, so the node address becomes invalid and the result of
dereferencing it is undefined.

So we ought to use offsets in preference to pointers for references
that would remain valid after a call to treap_insert.  Tweak the
signature to hint at a certain special case: since the inserted node
can change address (though not offset), as a convenience teach
treap_insert to return its new address.

So the motivational example could be fixed by adding "node =".

	struct int_node *node = node_pointer(node_alloc(1));
	node->n = 5;
	node = treap_insert(&root, node);
	printf("%d\n", node->n);

Based on a true story.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-12-07 16:03:55 -08:00

110 lines
3.3 KiB
Plaintext

Motivation
==========
Treaps provide a memory-efficient binary search tree structure.
Insertion/deletion/search are about as about as fast in the average
case as red-black trees and the chances of worst-case behavior are
vanishingly small, thanks to (pseudo-)randomness. The bad worst-case
behavior is a small price to pay, given that treaps are much simpler
to implement.
API
===
The trp API generates a data structure and functions to handle a
large growing set of objects stored in a pool.
The caller:
. Specifies parameters for the generated functions with the
trp_gen(static, foo_, ...) macro.
. Allocates a `struct trp_root` variable and sets it to {~0}.
. Adds new nodes to the set using `foo_insert`. Any pointers
to existing nodes cannot be relied upon any more, so the caller
might retrieve them anew with `foo_pointer`.
. Can find a specific item in the set using `foo_search`.
. Can iterate over items in the set using `foo_first` and `foo_next`.
. Can remove an item from the set using `foo_remove`.
Example:
----
struct ex_node {
const char *s;
struct trp_node ex_link;
};
static struct trp_root ex_base = {~0};
obj_pool_gen(ex, struct ex_node, 4096);
trp_gen(static, ex_, struct ex_node, ex_link, ex, strcmp)
struct ex_node *item;
item = ex_pointer(ex_alloc(1));
item->s = "hello";
ex_insert(&ex_base, item);
item = ex_pointer(ex_alloc(1));
item->s = "goodbye";
ex_insert(&ex_base, item);
for (item = ex_first(&ex_base); item; item = ex_next(&ex_base, item))
printf("%s\n", item->s);
----
Functions
---------
trp_gen(attr, foo_, node_type, link_field, pool, cmp)::
Generate a type-specific treap implementation.
+
. The storage class for generated functions will be 'attr' (e.g., `static`).
. Generated function names are prefixed with 'foo_' (e.g., `treap_`).
. Treap nodes will be of type 'node_type' (e.g., `struct treap_node`).
This type must be a struct with at least one `struct trp_node` field
to point to its children.
. The field used to access child nodes will be 'link_field'.
. All treap nodes must lie in the 'pool' object pool.
. Treap nodes must be totally ordered by the 'cmp' relation, with the
following prototype:
+
int (*cmp)(node_type \*a, node_type \*b)
+
and returning a value less than, equal to, or greater than zero
according to the result of comparison.
node_type {asterisk}foo_insert(struct trp_root *treap, node_type \*node)::
Insert node into treap. If inserted multiple times,
a node will appear in the treap multiple times.
+
The return value is the address of the node within the treap,
which might differ from `node` if `pool_alloc` had to call
`realloc` to expand the pool.
void foo_remove(struct trp_root *treap, node_type \*node)::
Remove node from treap. Caller must ensure node is
present in treap before using this function.
node_type *foo_search(struct trp_root \*treap, node_type \*key)::
Search for a node that matches key. If no match is found,
result is NULL.
node_type *foo_nsearch(struct trp_root \*treap, node_type \*key)::
Like `foo_search`, but if if the key is missing return what
would be key's successor, were key in treap (NULL if no
successor).
node_type *foo_first(struct trp_root \*treap)::
Find the first item from the treap, in sorted order.
node_type *foo_next(struct trp_root \*treap, node_type \*node)::
Find the next item.