1 #include "internal/alloc.h"
3 #include "derp/treemap.h"
5 /* AA (Arne Andersson) Tree:
6 * Balanced Search Trees Made Simple
7 * https://user.it.uu.se/~arnea/ps/simp.pdf
9 * As fast as an RB-tree, but free of those
10 * ugly special cases. */
15 struct map_pair *pair;
16 struct tm_node *left, *right;
21 struct tm_node *root, *bottom;
22 struct tm_node *deleted, *last;
34 struct tm_node *n, *bottom;
38 tm_new(comparator *cmp, void *cmp_aux)
40 treemap *t = internal_malloc(sizeof *t);
41 struct tm_node *bottom = internal_malloc(sizeof *bottom);
45 internal_free(bottom);
48 /* sentinel living below all leaves */
49 *bottom = (struct tm_node){
50 .left = bottom, .right = bottom, .level = 0
69 internal_free(t->bottom);
74 tm_dtor(treemap *t, dtor *key_dtor, dtor *val_dtor, void *dtor_aux)
78 t->key_dtor = key_dtor;
79 t->val_dtor = val_dtor;
80 t->dtor_aux = dtor_aux;
84 internal_tm_length(const struct tm_node *n,
85 const struct tm_node *bottom)
90 internal_tm_length(n->left, bottom) +
91 internal_tm_length(n->right, bottom);
95 tm_length(const treemap *t)
97 return t ? internal_tm_length(t->root, t->bottom) : 0;
101 tm_is_empty(const treemap *t)
103 return tm_length(t) == 0;
107 internal_tm_at(const treemap *t, const struct tm_node *n,
112 int x = t->cmp(key, n->pair->k, t->cmp_aux);
116 return internal_tm_at(t, n->left, key);
117 return internal_tm_at(t, n->right, key);
121 tm_at(const treemap *t, const void *key)
123 return t ? internal_tm_at(t, t->root, key) : NULL;
126 static struct tm_node *
127 internal_tm_skew(struct tm_node *n) {
128 if (n->level != n->left->level)
130 struct tm_node *left = n->left;
131 n->left = left->right;
137 static struct tm_node *
138 internal_tm_split(struct tm_node *n) {
139 if(n->right->right->level != n->level)
141 struct tm_node *right = n->right;
142 n->right = right->left;
149 static struct tm_node *
150 internal_tm_insert(treemap *t, struct tm_node *n,
151 struct tm_node *prealloc)
155 int x = t->cmp(prealloc->pair->k, n->pair->k, t->cmp_aux);
157 n->left = internal_tm_insert(t, n->left, prealloc);
159 n->right = internal_tm_insert(t, n->right, prealloc);
162 /* prealloc was for naught, but we'll use its value */
163 if (n->pair->v != prealloc->pair->v && t->val_dtor)
164 t->val_dtor(n->pair->v, t->dtor_aux);
165 if (n->pair->k != prealloc->pair->k && t->key_dtor)
166 t->key_dtor(n->pair->k, t->dtor_aux);
167 *n->pair = *prealloc->pair;
168 internal_free(prealloc->pair);
169 internal_free(prealloc);
172 return internal_tm_split(internal_tm_skew(n));
176 tm_insert(treemap *t, void *key, void *val)
180 /* attempt the malloc before potentially splitting
181 * and skewing the tree, so the insertion can be a
182 * no-op on failure */
183 struct tm_node *prealloc = internal_malloc(sizeof *prealloc);
184 struct map_pair *p = internal_malloc(sizeof *p);
187 internal_free(prealloc);
191 *p = (struct map_pair){.k = key, .v = val};
192 *prealloc = (struct tm_node){
193 .level = 1, .pair = p, .left = t->bottom, .right = t->bottom
196 t->root = internal_tm_insert(t, t->root, prealloc);
200 static struct tm_node *
201 internal_tm_remove(treemap *t, struct tm_node *n, void *key)
206 /* 1: search down the tree and set pointers last and deleted */
209 if (t->cmp(key, n->pair->k, t->cmp_aux) < 0)
210 n->left = internal_tm_remove(t, n->left, key);
214 n->right = internal_tm_remove(t, n->right, key);
217 /* 2: At the bottom of the tree, remove element if present */
219 if (n == t->last && t->deleted != t->bottom &&
220 t->cmp(key, t->deleted->pair->k, t->cmp_aux) == 0)
223 t->key_dtor(t->deleted->pair->k, t->dtor_aux);
225 t->val_dtor(t->deleted->pair->v, t->dtor_aux);
227 *t->deleted->pair = *n->pair;
228 t->deleted = t->bottom;
231 internal_free(t->last->pair);
232 internal_free(t->last);
233 } /* 3: on the way back up, rebalance */
234 else if (n->left->level < n->level-1 ||
235 n->right->level < n->level-1) {
237 if (n->right->level > n->level)
238 n->right->level = n->level;
239 n = internal_tm_skew(n);
240 n->right = internal_tm_skew(n->right);
241 n->right->right = internal_tm_skew(n->right->right);
242 n = internal_tm_split(n);
243 n->right = internal_tm_split(n->right);
249 tm_remove(treemap *t, void *key)
253 t->root = internal_tm_remove(t, t->root, key);
254 return true; // TODO: return false if key wasn't found
258 internal_tm_clear(treemap *t, struct tm_node *n)
262 internal_tm_clear(t, n->left);
263 internal_tm_clear(t, n->right);
265 t->key_dtor(n->pair->k, t->dtor_aux);
267 t->val_dtor(n->pair->v, t->dtor_aux);
268 internal_free(n->pair);
277 internal_tm_clear(t, t->root);
278 t->root = t->deleted = t->last = t->bottom;
282 tm_iter_begin(treemap *t)
286 struct tm_iter *i = internal_malloc(sizeof *i);
294 *i = (struct tm_iter){
303 tm_iter_next(tm_iter *i)
307 if (l_is_empty(i->stack) && i->n == i->bottom)
308 return NULL; /* done */
309 if (i->n != i->bottom)
311 if (!l_append(i->stack, i->n))
312 return NULL; /* OOM */
314 return tm_iter_next(i);
316 struct tm_node *result = l_remove_last(i->stack);
317 i->n = result->right;
322 tm_iter_free(tm_iter *i)