@matheusbsbs / matheus-bagliano / commits / 951f316470
Fork 0

Add treap implementation

Provide macros to generate a type-specific treap implementation and various functions to operate on it. It uses obj_pool.h to store memory nodes in a treap. Previously committed nodes are never removed from the pool; after any *_commit operation, it is assumed (correctly, in the case of svn-fast-export) that someone else must care about them. 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. >From http://www.canonware.com/download/trp/trp_hash/trp.h [db: Altered to reference nodes by offset from a common base pointer] [db: Bob Jenkins' hashing implementation dropped for Knuth's] [db: Methods unnecessary for search and insert dropped] [rr: Squelched compiler warnings] [db: Added support for immutable treap nodes] [jn: Reintroduced treap_nsearch(); with tests] Signed-off-by: David Barr <david.barr@cordelta.com> Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jason Evans committed Aug 9, 2010 at 17:17 UTC 951f316470acc7c785c460a4e40735b22822349f
7 files changed +432 -1
.gitignore
+1
@@ -173,6 +173,7 @@
173 /test-run-command
174 /test-sha1
175 /test-sigchain
176 +/test-treap
177 /common-cmds.h
178 *.tar.gz
179 *.dsc
Makefile
+2 -1
@@ -415,6 +415,7 @@ TEST_PROGRAMS_NEED_X += test-path-utils
415 TEST_PROGRAMS_NEED_X += test-run-command
416 TEST_PROGRAMS_NEED_X += test-sha1
417 TEST_PROGRAMS_NEED_X += test-sigchain
418 +TEST_PROGRAMS_NEED_X += test-treap
419 TEST_PROGRAMS_NEED_X += test-index-version
420
421 TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
@@ -1866,7 +1867,7 @@ xdiff-interface.o $(XDIFF_OBJS): \
1867 xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
1868
1869 $(VCSSVN_OBJS): \
1869 - vcs-svn/obj_pool.h
1870 + vcs-svn/obj_pool.h vcs-svn/trp.h
1871 endif
1872
1873 exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
t/t0080-vcs-svn.sh
+22
@@ -76,4 +76,26 @@ test_expect_success 'obj pool: high-water mark' '
76 test_cmp expected actual
77 '
78
79 +test_expect_success 'treap sort' '
80 + cat <<-\EOF >unsorted &&
81 + 68
82 + 12
83 + 13
84 + 13
85 + 68
86 + 13
87 + 13
88 + 21
89 + 10
90 + 11
91 + 12
92 + 13
93 + 13
94 + EOF
95 + sort unsorted >expected &&
96 +
97 + test-treap <unsorted >actual &&
98 + test_cmp expected actual
99 +'
100 +
101 test_done
test-treap.c new
+65
@@ -0,0 +1,65 @@
1 +/*
2 + * test-treap.c: code to exercise the svn importer's treap structure
3 + */
4 +
5 +#include "cache.h"
6 +#include "vcs-svn/obj_pool.h"
7 +#include "vcs-svn/trp.h"
8 +
9 +struct int_node {
10 + uintmax_t n;
11 + struct trp_node children;
12 +};
13 +
14 +obj_pool_gen(node, struct int_node, 3)
15 +
16 +static int node_cmp(struct int_node *a, struct int_node *b)
17 +{
18 + return (a->n > b->n) - (a->n < b->n);
19 +}
20 +
21 +trp_gen(static, treap_, struct int_node, children, node, node_cmp)
22 +
23 +static void strtonode(struct int_node *item, const char *s)
24 +{
25 + char *end;
26 + item->n = strtoumax(s, &end, 10);
27 + if (*s == '\0' || (*end != '\n' && *end != '\0'))
28 + die("invalid integer: %s", s);
29 +}
30 +
31 +int main(int argc, char *argv[])
32 +{
33 + struct strbuf sb = STRBUF_INIT;
34 + struct trp_root root = { ~0 };
35 + uint32_t item;
36 +
37 + if (argc != 1)
38 + usage("test-treap < ints");
39 +
40 + while (strbuf_getline(&sb, stdin, '\n') != EOF) {
41 + item = node_alloc(1);
42 + strtonode(node_pointer(item), sb.buf);
43 + treap_insert(&root, node_pointer(item));
44 + }
45 +
46 + item = node_offset(treap_first(&root));
47 + while (~item) {
48 + uint32_t next;
49 + struct int_node *tmp = node_pointer(node_alloc(1));
50 +
51 + tmp->n = node_pointer(item)->n;
52 + next = node_offset(treap_next(&root, node_pointer(item)));
53 +
54 + treap_remove(&root, node_pointer(item));
55 + item = node_offset(treap_nsearch(&root, tmp));
56 +
57 + if (item != next && (!~item || node_pointer(item)->n != tmp->n))
58 + die("found %"PRIuMAX" in place of %"PRIuMAX"",
59 + ~item ? node_pointer(item)->n : ~(uintmax_t) 0,
60 + ~next ? node_pointer(next)->n : ~(uintmax_t) 0);
61 + printf("%"PRIuMAX"\n", tmp->n);
62 + }
63 + node_reset();
64 + return 0;
65 +}
vcs-svn/LICENSE
+3
@@ -1,6 +1,9 @@
1 Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
2 All rights reserved.
3
4 +Copyright (C) 2008 Jason Evans <jasone@canonware.com>.
5 +All rights reserved.
6 +
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
vcs-svn/trp.h new
+236
@@ -0,0 +1,236 @@
1 +/*
2 + * C macro implementation of treaps.
3 + *
4 + * Usage:
5 + * #include <stdint.h>
6 + * #include "trp.h"
7 + * trp_gen(...)
8 + *
9 + * Licensed under a two-clause BSD-style license.
10 + * See LICENSE for details.
11 + */
12 +
13 +#ifndef TRP_H_
14 +#define TRP_H_
15 +
16 +#define MAYBE_UNUSED __attribute__((__unused__))
17 +
18 +/* Node structure. */
19 +struct trp_node {
20 + uint32_t trpn_left;
21 + uint32_t trpn_right;
22 +};
23 +
24 +/* Root structure. */
25 +struct trp_root {
26 + uint32_t trp_root;
27 +};
28 +
29 +/* Pointer/Offset conversion. */
30 +#define trpn_pointer(a_base, a_offset) (a_base##_pointer(a_offset))
31 +#define trpn_offset(a_base, a_pointer) (a_base##_offset(a_pointer))
32 +#define trpn_modify(a_base, a_offset) \
33 + do { \
34 + if ((a_offset) < a_base##_pool.committed) { \
35 + uint32_t old_offset = (a_offset);\
36 + (a_offset) = a_base##_alloc(1); \
37 + *trpn_pointer(a_base, a_offset) = \
38 + *trpn_pointer(a_base, old_offset); \
39 + } \
40 + } while (0);
41 +
42 +/* Left accessors. */
43 +#define trp_left_get(a_base, a_field, a_node) \
44 + (trpn_pointer(a_base, a_node)->a_field.trpn_left)
45 +#define trp_left_set(a_base, a_field, a_node, a_left) \
46 + do { \
47 + trpn_modify(a_base, a_node); \
48 + trp_left_get(a_base, a_field, a_node) = (a_left); \
49 + } while(0)
50 +
51 +/* Right accessors. */
52 +#define trp_right_get(a_base, a_field, a_node) \
53 + (trpn_pointer(a_base, a_node)->a_field.trpn_right)
54 +#define trp_right_set(a_base, a_field, a_node, a_right) \
55 + do { \
56 + trpn_modify(a_base, a_node); \
57 + trp_right_get(a_base, a_field, a_node) = (a_right); \
58 + } while(0)
59 +
60 +/*
61 + * Fibonacci hash function.
62 + * The multiplier is the nearest prime to (2^32 times (√5 - 1)/2).
63 + * See Knuth §6.4: volume 3, 3rd ed, p518.
64 + */
65 +#define trpn_hash(a_node) (uint32_t) (2654435761u * (a_node))
66 +
67 +/* Priority accessors. */
68 +#define trp_prio_get(a_node) trpn_hash(a_node)
69 +
70 +/* Node initializer. */
71 +#define trp_node_new(a_base, a_field, a_node) \
72 + do { \
73 + trp_left_set(a_base, a_field, (a_node), ~0); \
74 + trp_right_set(a_base, a_field, (a_node), ~0); \
75 + } while(0)
76 +
77 +/* Internal utility macros. */
78 +#define trpn_first(a_base, a_field, a_root, r_node) \
79 + do { \
80 + (r_node) = (a_root); \
81 + if ((r_node) == ~0) \
82 + return NULL; \
83 + while (~trp_left_get(a_base, a_field, (r_node))) \
84 + (r_node) = trp_left_get(a_base, a_field, (r_node)); \
85 + } while (0)
86 +
87 +#define trpn_rotate_left(a_base, a_field, a_node, r_node) \
88 + do { \
89 + (r_node) = trp_right_get(a_base, a_field, (a_node)); \
90 + trp_right_set(a_base, a_field, (a_node), \
91 + trp_left_get(a_base, a_field, (r_node))); \
92 + trp_left_set(a_base, a_field, (r_node), (a_node)); \
93 + } while(0)
94 +
95 +#define trpn_rotate_right(a_base, a_field, a_node, r_node) \
96 + do { \
97 + (r_node) = trp_left_get(a_base, a_field, (a_node)); \
98 + trp_left_set(a_base, a_field, (a_node), \
99 + trp_right_get(a_base, a_field, (r_node))); \
100 + trp_right_set(a_base, a_field, (r_node), (a_node)); \
101 + } while(0)
102 +
103 +#define trp_gen(a_attr, a_pre, a_type, a_field, a_base, a_cmp) \
104 +a_attr a_type MAYBE_UNUSED *a_pre##first(struct trp_root *treap) \
105 +{ \
106 + uint32_t ret; \
107 + trpn_first(a_base, a_field, treap->trp_root, ret); \
108 + return trpn_pointer(a_base, ret); \
109 +} \
110 +a_attr a_type MAYBE_UNUSED *a_pre##next(struct trp_root *treap, a_type *node) \
111 +{ \
112 + uint32_t ret; \
113 + uint32_t offset = trpn_offset(a_base, node); \
114 + if (~trp_right_get(a_base, a_field, offset)) { \
115 + trpn_first(a_base, a_field, \
116 + trp_right_get(a_base, a_field, offset), ret); \
117 + } else { \
118 + uint32_t tnode = treap->trp_root; \
119 + ret = ~0; \
120 + while (1) { \
121 + int cmp = (a_cmp)(trpn_pointer(a_base, offset), \
122 + trpn_pointer(a_base, tnode)); \
123 + if (cmp < 0) { \
124 + ret = tnode; \
125 + tnode = trp_left_get(a_base, a_field, tnode); \
126 + } else if (cmp > 0) { \
127 + tnode = trp_right_get(a_base, a_field, tnode); \
128 + } else { \
129 + break; \
130 + } \
131 + } \
132 + } \
133 + return trpn_pointer(a_base, ret); \
134 +} \
135 +a_attr a_type MAYBE_UNUSED *a_pre##search(struct trp_root *treap, a_type *key) \
136 +{ \
137 + int cmp; \
138 + uint32_t ret = treap->trp_root; \
139 + while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base,ret)))) { \
140 + if (cmp < 0) { \
141 + ret = trp_left_get(a_base, a_field, ret); \
142 + } else { \
143 + ret = trp_right_get(a_base, a_field, ret); \
144 + } \
145 + } \
146 + return trpn_pointer(a_base, ret); \
147 +} \
148 +a_attr a_type MAYBE_UNUSED *a_pre##nsearch(struct trp_root *treap, a_type *key) \
149 +{ \
150 + int cmp; \
151 + uint32_t ret = treap->trp_root; \
152 + while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base,ret)))) { \
153 + if (cmp < 0) { \
154 + if (!~trp_left_get(a_base, a_field, ret)) \
155 + break; \
156 + ret = trp_left_get(a_base, a_field, ret); \
157 + } else { \
158 + ret = trp_right_get(a_base, a_field, ret); \
159 + } \
160 + } \
161 + return trpn_pointer(a_base, ret); \
162 +} \
163 +a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t ins_node) \
164 +{ \
165 + if (cur_node == ~0) { \
166 + return (ins_node); \
167 + } else { \
168 + uint32_t ret; \
169 + int cmp = (a_cmp)(trpn_pointer(a_base, ins_node), \
170 + trpn_pointer(a_base, cur_node)); \
171 + if (cmp < 0) { \
172 + uint32_t left = a_pre##insert_recurse( \
173 + trp_left_get(a_base, a_field, cur_node), ins_node); \
174 + trp_left_set(a_base, a_field, cur_node, left); \
175 + if (trp_prio_get(left) < trp_prio_get(cur_node)) \
176 + trpn_rotate_right(a_base, a_field, cur_node, ret); \
177 + else \
178 + ret = cur_node; \
179 + } else { \
180 + uint32_t right = a_pre##insert_recurse( \
181 + trp_right_get(a_base, a_field, cur_node), ins_node); \
182 + trp_right_set(a_base, a_field, cur_node, right); \
183 + if (trp_prio_get(right) < trp_prio_get(cur_node)) \
184 + trpn_rotate_left(a_base, a_field, cur_node, ret); \
185 + else \
186 + ret = cur_node; \
187 + } \
188 + return (ret); \
189 + } \
190 +} \
191 +a_attr void MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
192 +{ \
193 + uint32_t offset = trpn_offset(a_base, node); \
194 + trp_node_new(a_base, a_field, offset); \
195 + treap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \
196 +} \
197 +a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \
198 +{ \
199 + int cmp = a_cmp(trpn_pointer(a_base, rem_node), \
200 + trpn_pointer(a_base, cur_node)); \
201 + if (cmp == 0) { \
202 + uint32_t ret; \
203 + uint32_t left = trp_left_get(a_base, a_field, cur_node); \
204 + uint32_t right = trp_right_get(a_base, a_field, cur_node); \
205 + if (left == ~0) { \
206 + if (right == ~0) \
207 + return (~0); \
208 + } else if (right == ~0 || trp_prio_get(left) < trp_prio_get(right)) { \
209 + trpn_rotate_right(a_base, a_field, cur_node, ret); \
210 + right = a_pre##remove_recurse(cur_node, rem_node); \
211 + trp_right_set(a_base, a_field, ret, right); \
212 + return (ret); \
213 + } \
214 + trpn_rotate_left(a_base, a_field, cur_node, ret); \
215 + left = a_pre##remove_recurse(cur_node, rem_node); \
216 + trp_left_set(a_base, a_field, ret, left); \
217 + return (ret); \
218 + } else if (cmp < 0) { \
219 + uint32_t left = a_pre##remove_recurse( \
220 + trp_left_get(a_base, a_field, cur_node), rem_node); \
221 + trp_left_set(a_base, a_field, cur_node, left); \
222 + return (cur_node); \
223 + } else { \
224 + uint32_t right = a_pre##remove_recurse( \
225 + trp_right_get(a_base, a_field, cur_node), rem_node); \
226 + trp_right_set(a_base, a_field, cur_node, right); \
227 + return (cur_node); \
228 + } \
229 +} \
230 +a_attr void MAYBE_UNUSED a_pre##remove(struct trp_root *treap, a_type *node) \
231 +{ \
232 + treap->trp_root = a_pre##remove_recurse(treap->trp_root, \
233 + trpn_offset(a_base, node)); \
234 +} \
235 +
236 +#endif
vcs-svn/trp.txt new
+103
@@ -0,0 +1,103 @@
1 +Motivation
2 +==========
3 +
4 +Treaps provide a memory-efficient binary search tree structure.
5 +Insertion/deletion/search are about as about as fast in the average
6 +case as red-black trees and the chances of worst-case behavior are
7 +vanishingly small, thanks to (pseudo-)randomness. The bad worst-case
8 +behavior is a small price to pay, given that treaps are much simpler
9 +to implement.
10 +
11 +API
12 +===
13 +
14 +The trp API generates a data structure and functions to handle a
15 +large growing set of objects stored in a pool.
16 +
17 +The caller:
18 +
19 +. Specifies parameters for the generated functions with the
20 + trp_gen(static, foo_, ...) macro.
21 +
22 +. Allocates a `struct trp_root` variable and sets it to {~0}.
23 +
24 +. Adds new nodes to the set using `foo_insert`.
25 +
26 +. Can find a specific item in the set using `foo_search`.
27 +
28 +. Can iterate over items in the set using `foo_first` and `foo_next`.
29 +
30 +. Can remove an item from the set using `foo_remove`.
31 +
32 +Example:
33 +
34 +----
35 +struct ex_node {
36 + const char *s;
37 + struct trp_node ex_link;
38 +};
39 +static struct trp_root ex_base = {~0};
40 +obj_pool_gen(ex, struct ex_node, 4096);
41 +trp_gen(static, ex_, struct ex_node, ex_link, ex, strcmp)
42 +struct ex_node *item;
43 +
44 +item = ex_pointer(ex_alloc(1));
45 +item->s = "hello";
46 +ex_insert(&ex_base, item);
47 +item = ex_pointer(ex_alloc(1));
48 +item->s = "goodbye";
49 +ex_insert(&ex_base, item);
50 +for (item = ex_first(&ex_base); item; item = ex_next(&ex_base, item))
51 + printf("%s\n", item->s);
52 +----
53 +
54 +Functions
55 +---------
56 +
57 +trp_gen(attr, foo_, node_type, link_field, pool, cmp)::
58 +
59 + Generate a type-specific treap implementation.
60 ++
61 +. The storage class for generated functions will be 'attr' (e.g., `static`).
62 +. Generated function names are prefixed with 'foo_' (e.g., `treap_`).
63 +. Treap nodes will be of type 'node_type' (e.g., `struct treap_node`).
64 + This type must be a struct with at least one `struct trp_node` field
65 + to point to its children.
66 +. The field used to access child nodes will be 'link_field'.
67 +. All treap nodes must lie in the 'pool' object pool.
68 +. Treap nodes must be totally ordered by the 'cmp' relation, with the
69 + following prototype:
70 ++
71 +int (*cmp)(node_type \*a, node_type \*b)
72 ++
73 +and returning a value less than, equal to, or greater than zero
74 +according to the result of comparison.
75 +
76 +void foo_insert(struct trp_root *treap, node_type \*node)::
77 +
78 + Insert node into treap. If inserted multiple times,
79 + a node will appear in the treap multiple times.
80 +
81 +void foo_remove(struct trp_root *treap, node_type \*node)::
82 +
83 + Remove node from treap. Caller must ensure node is
84 + present in treap before using this function.
85 +
86 +node_type *foo_search(struct trp_root \*treap, node_type \*key)::
87 +
88 + Search for a node that matches key. If no match is found,
89 + result is NULL.
90 +
91 +node_type *foo_nsearch(struct trp_root \*treap, node_type \*key)::
92 +
93 + Like `foo_search`, but if if the key is missing return what
94 + would be key's successor, were key in treap (NULL if no
95 + successor).
96 +
97 +node_type *foo_first(struct trp_root \*treap)::
98 +
99 + Find the first item from the treap, in sorted order.
100 +
101 +node_type *foo_next(struct trp_root \*treap, node_type \*node)::
102 +
103 + Find the next item.