1 // -*- mode: c; coding: utf-8 -*- */
3 // Copyright 2010, 2011, Matthias Andreas Benkard.
5 //-----------------------------------------------------------------------------
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //-----------------------------------------------------------------------------
21 // An implementation of a bitmapped Patricia tree.
25 // The idea is to use a locally mutable, bitmapped Patricia tree as a
26 // variable binding store (i.e. environment) in compiled code. In this
27 // way, there is no need for excessive copying when an independent
28 // environment must be set up (such as when initiating the processing of
29 // a new node in the search space). Instead, significant amounts of
30 // structure can be shared between child and parent environments.
34 // 1. Patricia trees are very amenable to structure sharing.
36 // 2. Furthermore, big-endian Patricia trees are especially efficient
37 // when indices are allocated sequentially, as is the case for
38 // variables in code emitted by our compiler.
40 // 3. Finally, bitmapping improves the performance of copying because
41 // copying an array is much cheaper than copying an equivalent branch
42 // in a tree. As we need to shallow-copy the tree at potentially
43 // each choice point, copying needs to be fast.
50 #include "bitmapped_patricia_tree.h"
52 typedef struct bpt_nonempty *bpt_nonempty_t;
53 typedef struct bpt_node *bpt_node_t;
54 typedef struct bpt_leaf *bpt_leaf_t;
64 struct bpt bpt; // poor man's inheritance
66 #ifdef BPT_ENABLE_DEALLOC_HOOKS
67 void (*dealloc_hook)(bpt_key_t, void *); // not actually used anywhere in client code
72 struct bpt bpt; // poor man's inheritance
73 unsigned int branching_chunk;
74 bpt_key_bitmask_t bitmask;
79 void init_bpt_leaf(bpt_t a_leaf, bpt_key_t key, void *value) {
80 bpt_leaf_t leaf = (bpt_leaf_t)a_leaf;
81 leaf->bpt.tag = BPT_LEAF;
82 leaf->bpt.mutable = true;
83 leaf->bpt.prefix = key;
85 #ifdef BPT_ENABLE_DEALLOC_HOOKS
86 leaf->dealloc_hook = NULL;
88 leaf->bpt.refcount = 1;
91 void init_bpt_node(bpt_node_t node, bpt_key_t prefix, unsigned int branching_chunk) {
92 node->bpt.tag = BPT_INNER_NODE;
93 node->bpt.mutable = true;
94 node->bpt.prefix = prefix;
95 node->branching_chunk = branching_chunk;
97 node->children = NULL;
98 node->bpt.refcount = 1;
102 bpt_t bpt_make_leaf(bpt_key_t key, void *value) {
103 bpt_leaf_t leaf = malloc(sizeof *leaf);
104 init_bpt_leaf((bpt_t)leaf, key, value);
108 bpt_node_t bpt_make_node(bpt_key_t prefix, unsigned int branching_chunk) {
109 bpt_node_t node = malloc(sizeof *node);
110 init_bpt_node(node, prefix, branching_chunk);
115 static inline unsigned int bpt_number_of_leading_zeros(bpt_key_t x);
116 static inline unsigned int bpt_number_of_trailing_zeros(bpt_key_t x);
117 static inline unsigned int bpt_popcount(bpt_key_bitmask_t key);
118 static unsigned int bpt_compute_child_index(bpt_key_bitmask_t bitmask, unsigned int child_number);
119 static inline uint_fast8_t bpt_offset_of_key(bpt_key_t key, unsigned int branching_chunk);
120 static bpt_key_t bpt_prefix_of_key(bpt_key_t key, unsigned int branching_chunk);
121 static inline unsigned int bpt_branching_chunk(bpt_t bpt);
122 static unsigned int bpt_find_diverging_chunk(bpt_key_t key1, bpt_key_t key2);
123 static void bpt_for_children(bpt_t bpt, void (*thunk)(bpt_t));
126 static void bpt_for_children(bpt_t bpt, void (*thunk)(bpt_t)) {
127 if (bpt && bpt->tag == BPT_INNER_NODE) {
128 bpt_node_t b = (bpt_node_t)bpt;
129 bpt_t *iter = b->children;
130 bpt_t *children_end = b->children + bpt_popcount(b->bitmask);
131 while (iter < children_end) {
138 void *bpt_get(bpt_t bpt, bpt_key_t key) {
139 void **pointer = bpt_get_pointer(bpt, key);
147 bpt_leaf_t bpt_get_leaf(bpt_t bpt, bpt_key_t key)
151 } else if (bpt->tag == BPT_LEAF) {
152 bpt_leaf_t b = (bpt_leaf_t)bpt;
153 if (bpt->prefix == key) {
159 bpt_node_t b = (bpt_node_t)bpt;
160 int child_number = bpt_offset_of_key(key, b->branching_chunk);
161 if ((1 << child_number) & b->bitmask) {
162 int child_index = bpt_compute_child_index(b->bitmask, child_number);
163 return bpt_get_leaf(b->children[child_index], key);
170 void **bpt_get_pointer(bpt_t bpt, bpt_key_t key)
172 bpt_leaf_t leaf = bpt_get_leaf(bpt, key);
180 bool bpt_has_key(bpt_t bpt, bpt_key_t key) {
181 return (bpt_get_leaf(bpt, key) != NULL);
184 bpt_t bpt_assoc(bpt_t bpt, bpt_key_t key, void *value) {
186 return (bpt_t)bpt_make_leaf(key, value);
188 bpt_key_t prefix = bpt->prefix;
189 if (bpt_prefix_of_key(key, bpt_branching_chunk(bpt)) != prefix) {
190 unsigned int diverging_chunk = bpt_find_diverging_chunk(key, prefix);
191 bpt_key_t my_number_in_parent = bpt_offset_of_key(prefix, diverging_chunk);
192 bpt_key_t their_number_in_parent = bpt_offset_of_key(key, diverging_chunk);
193 bpt_node_t new_node = bpt_make_node(bpt_prefix_of_key(prefix, diverging_chunk), diverging_chunk);
194 new_node->bitmask = (1 << my_number_in_parent) | (1 << their_number_in_parent);
195 new_node->children = malloc(sizeof (*new_node->children) * 2);
196 if (my_number_in_parent < their_number_in_parent) {
197 new_node->children[0] = bpt;
198 new_node->children[1] = bpt_make_leaf(key, value);
200 new_node->children[0] = bpt_make_leaf(key, value);
201 new_node->children[1] = bpt;
204 return (bpt_t)new_node;
206 if (bpt->tag == BPT_LEAF) {
207 bpt_leaf_t b = (bpt_leaf_t)bpt;
213 return (bpt_t)bpt_make_leaf(key, value);
216 bpt_node_t b = (bpt_node_t)bpt;
217 uint_fast8_t child_number = bpt_offset_of_key(key, b->branching_chunk);
218 unsigned int child_index = bpt_compute_child_index(b->bitmask, child_number);
219 if ((1 << child_number) & b->bitmask) {
220 // We already have a child to pass the value to. Do that.
221 bpt_t child = b->children[child_index];
222 bpt_t new_child = bpt_assoc(child, key, value);
223 if (new_child == child) {
230 b->children[child_index] = new_child;
234 bpt_node_t new_node = malloc(sizeof *new_node);
236 new_node->bpt.refcount = 1;
237 new_node->bpt.mutable = true;
238 unsigned int number_of_children = bpt_popcount(b->bitmask);
239 size_t size_of_child_array = sizeof (*new_node->children) * number_of_children;
240 new_node->children = malloc(size_of_child_array);
241 memcpy(new_node->children, b->children, size_of_child_array);
242 new_node->children[child_index] = new_child;
243 // Retain the children copied into the new node.
244 bpt_for_children((bpt_t)new_node, bpt_retain);
245 bpt_release(new_child);
246 return (bpt_t)new_node;
250 // Create a new child.
251 unsigned int number_of_children = bpt_popcount(b->bitmask);
252 size_t new_size_of_child_array = sizeof (*b->children) * (number_of_children + 1);
254 b->children = realloc(b->children, new_size_of_child_array);
255 memmove(b->children + child_index + 1, b->children + child_index, sizeof (*b->children) * (number_of_children - child_index));
256 b->children[child_index] = bpt_make_leaf(key, value);
257 b->bitmask |= 1 << child_number;
261 bpt_t *new_children = malloc(new_size_of_child_array);
262 memcpy(new_children, b->children, sizeof (*b->children) * child_index);
263 memcpy(new_children + child_index + 1,
264 b->children + child_index,
265 sizeof (*b->children) * (number_of_children - child_index));
266 new_children[child_index] = bpt_make_leaf(key, value);
267 bpt_node_t new_node = bpt_make_node(b->bpt.prefix, b->branching_chunk);
268 new_node->children = new_children;
269 new_node->bitmask = b->bitmask | (1 << child_number);
270 // Retain the children copied into the new node.
271 bpt_for_children(bpt, bpt_retain);
272 return (bpt_t)new_node;
281 bpt_t bpt_dissoc(bpt_t bpt, bpt_key_t key) {
282 if (!bpt || (bpt_prefix_of_key(key, bpt_branching_chunk(bpt)) != bpt->prefix)) {
285 } else if (bpt->tag == BPT_LEAF) {
290 bpt_node_t b = (bpt_node_t)bpt;
291 uint_fast8_t child_number = bpt_offset_of_key(key, b->branching_chunk);
292 if ((1 << child_number) & b->bitmask) {
293 unsigned int child_index = bpt_compute_child_index(b->bitmask, child_number);
294 bpt_t child = b->children[child_index];
295 bpt_t new_child = bpt_dissoc(child, key);
296 if (new_child == child) {
301 unsigned int number_of_children = bpt_popcount(b->bitmask);
302 if (!new_child && number_of_children == 2) {
303 // When there is only a single child left, we replace ourselves
305 bpt_t remaining_child = b->children[1-child_index];
306 bpt_retain(remaining_child);
307 return remaining_child;
308 } else if (bpt->mutable) {
311 // We don't reallocate the array because it wouldn't really
312 // gain us anything (except maybe non-confusion of a
314 memmove(b->children + child_index, b->children + child_index + 1, sizeof(*b->children) * (number_of_children - child_index - 1));
315 b->bitmask &= ~(1 << child_number);
319 b->children[child_index] = new_child;
324 // If all else fails, allocate a new node.
326 bpt_key_bitmask_t bitmask;
328 new_children = malloc((sizeof *new_children) * (number_of_children - 1));
329 memcpy(new_children, b->children, sizeof (*b->children) * child_index);
330 memcpy(new_children + child_index,
331 b->children + child_index + 1,
332 sizeof (*b->children) * (number_of_children - child_index - 1));
333 bitmask = b->bitmask & ~(1 << child_number);
335 new_children = malloc((sizeof *new_children) * number_of_children);
336 memcpy(new_children, b->children, sizeof (*b->children) * number_of_children);
337 new_children[child_index] = new_child;
338 bitmask = b->bitmask;
340 bpt_node_t new_node = bpt_make_node(b->bpt.prefix, b->branching_chunk);
341 new_node->children = new_children;
342 new_node->bitmask = bitmask;
343 // Retain the children copied into the new node.
344 bpt_for_children((bpt_t)new_node, bpt_retain);
345 bpt_release(new_child);
346 return (bpt_t)new_node;
357 void bpt_seal(bpt_t bpt) {
360 bpt->mutable = false;
361 if (bpt->tag == BPT_INNER_NODE) {
362 bpt_for_children(bpt, bpt_seal);
369 /////////////// Helper functions ///////////////
370 static unsigned int bpt_compute_child_index(bpt_key_bitmask_t bitmask, unsigned int child_number) {
371 // Compute the sparse array index given a flat array index.
372 return bpt_popcount(bitmask & ((1 << child_number) - 1));
375 static inline uint_fast8_t bpt_offset_of_key(bpt_key_t key, unsigned int chunk_number) {
377 //return (key >> (chunk_number * CHUNK_LENGTH)) & OFFSET_MASK;
380 if (chunk_number <= MAX_CHUNKS - 2) {
381 shift += LAST_CHUNK_LENGTH;
383 if (chunk_number <= MAX_CHUNKS - 3) {
384 shift += ((MAX_CHUNKS - 2 - chunk_number) * CHUNK_LENGTH);
386 return (key >> shift) & (chunk_number == MAX_CHUNKS - 1 ? ((1 << LAST_CHUNK_LENGTH) - 1) : OFFSET_MASK);
389 static bpt_key_t bpt_prefix_of_key(bpt_key_t key, unsigned int chunk_number) {
390 if (chunk_number == MAX_CHUNKS) {
394 //return key & ((1 << (chunk_number * CHUNK_LENGTH)) - 1)
396 return key & (((1 << (chunk_number * CHUNK_LENGTH)) - 1) << (KEY_LENGTH - (chunk_number * CHUNK_LENGTH)));
400 static inline unsigned int bpt_branching_chunk(bpt_t bpt) {
402 if (bpt->tag == BPT_LEAF) {
405 return ((bpt_node_t)bpt)->branching_chunk;
409 static inline unsigned int bpt_popcount(bpt_key_bitmask_t x) {
410 return __builtin_popcountll(x);
413 static inline unsigned int bpt_number_of_leading_zeros(bpt_key_t x) {
414 return __builtin_clzll(x);
417 static inline unsigned int bpt_number_of_trailing_zeros(bpt_key_t x) {
418 return __builtin_ctzll(x);
421 static unsigned int bpt_find_diverging_chunk(bpt_key_t a, bpt_key_t b) {
423 //return bpt_number_of_trailing_zeros(a ^ b) / CHUNK_LENGTH;
425 return bpt_number_of_leading_zeros(a ^ b) / CHUNK_LENGTH;
428 void bpt_retain(bpt_t bpt) {
430 __sync_fetch_and_add(&bpt->refcount, 1);
434 void bpt_release(bpt_t bpt) {
436 if (__sync_sub_and_fetch(&bpt->refcount, 1) == 0) {
442 void bpt_dealloc(bpt_t bpt) {
444 if (bpt->tag == BPT_LEAF) {
445 bpt_leaf_t b = (bpt_leaf_t)bpt;
446 #ifdef BPT_ENABLE_DEALLOC_HOOKS
447 if (b->dealloc_hook) {
448 b->dealloc_hook(b->bpt.prefix, b->value);
453 bpt_node_t b = (bpt_node_t)bpt;
454 bpt_for_children(bpt, bpt_release);
461 #ifdef BPT_ENABLE_DEALLOC_HOOKS
462 void bpt_leaf_set_dealloc_hook(bpt_leaf_t bpt, void (*hook)(bpt_key_t, void*)) {
464 bpt->dealloc_hook = hook;
468 void bpt_set_dealloc_hook(bpt_t bpt, bpt_key_t key, void (*hook)(bpt_key_t, void*)) {
469 bpt_leaf_set_dealloc_hook(bpt_get_leaf(bpt, key), hook);