mirror of
https://github.com/git/git.git
synced 2024-11-05 00:37:55 +01:00
97a5e3453a
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>
109 lines
3.3 KiB
Text
109 lines
3.3 KiB
Text
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.
|