@matheusbsbs / matheus-bagliano / commits / 97a5e3453a
Fork 0

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>

Jonathan Nieder committed Dec 5, 2010 at 03:35 UTC 97a5e3453abf63bbf5926979fcd89efb4388e937
3 files changed +18 -6
test-treap.c
+8 -3
@@ -38,9 +38,14 @@ int main(int argc, char *argv[])
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));
41 + struct int_node *node = node_pointer(node_alloc(1));
42 +
43 + item = node_offset(node);
44 + strtonode(node, sb.buf);
45 + node = treap_insert(&root, node_pointer(item));
46 + if (node_offset(node) != item)
47 + die("inserted %"PRIu32" in place of %"PRIu32"",
48 + node_offset(node), item);
49 }
50
51 item = node_offset(treap_first(&root));
vcs-svn/trp.h
+2 -1
@@ -188,11 +188,12 @@ a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t i
188 return ret; \
189 } \
190 } \
191 -a_attr void MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
191 +a_attr a_type *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 + return trpn_pointer(a_base, offset); \
197 } \
198 a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \
199 { \
vcs-svn/trp.txt
+8 -2
@@ -21,7 +21,9 @@ The caller:
21
22 . Allocates a `struct trp_root` variable and sets it to {~0}.
23
24 -. Adds new nodes to the set using `foo_insert`.
24 +. Adds new nodes to the set using `foo_insert`. Any pointers
25 + to existing nodes cannot be relied upon any more, so the caller
26 + might retrieve them anew with `foo_pointer`.
27
28 . Can find a specific item in the set using `foo_search`.
29
@@ -73,10 +75,14 @@ int (*cmp)(node_type \*a, node_type \*b)
75 and returning a value less than, equal to, or greater than zero
76 according to the result of comparison.
77
76 -void foo_insert(struct trp_root *treap, node_type \*node)::
78 +node_type {asterisk}foo_insert(struct trp_root *treap, node_type \*node)::
79
80 Insert node into treap. If inserted multiple times,
81 a node will appear in the treap multiple times.
82 ++
83 +The return value is the address of the node within the treap,
84 +which might differ from `node` if `pool_alloc` had to call
85 +`realloc` to expand the pool.
86
87 void foo_remove(struct trp_root *treap, node_type \*node)::
88