static int insert_ptr(NODE **rootaddr, NODE *node, int (*usrcmp)(void *, void *), int dup) { NODE *root = *rootaddr; int cmp; int ins; SET_PTRCMP(cmp, usrcmp, node->key.ptr, root->key.ptr) if (cmp < 0) { if (root->left) ins = insert_ptr(&root->left, node, usrcmp, dup); else { root->left = node; ins = DEEPER; } switch (ins) { CASE DEEPER : switch (root->bal) { CASE RIGHT : root->bal = BAL; return INS; CASE BAL : root->bal = LEFT; return DEEPER; CASE LEFT : root->bal = LEFTUNBAL; return rebalance(rootaddr) == LESS ? INS : DEEPER; } CASE INS : return INS; CASE NOTINS : return NOTINS; } } else if (cmp > 0 || dup) {
int MUTABOR_CLASS_FUNCTION(ptrlist,insert)(void * _self,const void * ptr) { MUT_CLASS(ptrlist) *self=_self; if (!self->root) { self->root=calloc(sizeof(struct mutabor_avl_node_ptr),1); self->root->data=ptr; return 1; } return insert_ptr(&self->root,ptr); }
static void move_item(struct btree_page *from, int from_pos, struct btree_page *to, int to_pos) { if (from->height) insert_ptr(to, to_pos, PAGE_KEY(from, from_pos), *PAGE_PTR(from, from_pos)); else insert_data(to, to_pos, PAGE_KEY(from, from_pos), PAGE_DATA(from, from_pos)); delete_item(from, from_pos); }
void objc_hashtable_set_ptr(struct objc_hashtable *h, const void *key, const void *obj) { int64_t idx = index_for_key_ptr(h, key); if (idx < 0) { insert_ptr(h, key, obj); return; } h->data[idx]->obj = obj; }
switch (ins) { CASE DEEPER : switch (root->bal) { CASE RIGHT : root->bal = BAL; return INS; CASE BAL : root->bal = LEFT; return DEEPER; CASE LEFT : root->bal = LEFTUNBAL; return rebalance(rootaddr) == LESS ? INS : DEEPER; } CASE INS : return INS; CASE NOTINS : return NOTINS; } } else if (cmp > 0 || dup) { if (root->right) ins = insert_ptr(&root->right, node, usrcmp, dup); else { root->right = node; ins = DEEPER; } switch (ins) { CASE DEEPER : switch (root->bal) { CASE LEFT : root->bal = BAL; return INS; CASE BAL : root->bal = RIGHT; return DEEPER; CASE RIGHT : root->bal = RIGHTUNBAL; return rebalance(rootaddr) == LESS ? INS : DEEPER; } CASE INS : return INS;
int btree_put(btree_t bt, const void *key, const void *data) { const struct btree_def *def = bt->def; struct btree_page *new_root = NULL; struct btree_page *path_new[MAX_HEIGHT] = {0}; struct btree_page *path_old[MAX_HEIGHT] = {0}; int slot_old[MAX_HEIGHT] = {0}; int h; check_btree(bt); /* Special case: cursor overwrite */ if (!key) { if (bt->slot[0] < 0) { fprintf(stderr, "btree: put at invalid cursor\n"); return -1; } memcpy(PAGE_DATA(bt->path[0], bt->slot[0]), data, def->data_size); return 1; } /* Find a path down the tree that leads to the page which should * contain this datum (though the page might be too big to hold it). */ if (trace_path(bt, key, path_old, slot_old)) { /* Special case: overwrite existing item */ memcpy(PAGE_DATA(path_old[0], slot_old[0]), data, def->data_size); return 1; } /* Trace from the leaf up. If the leaf is at its maximum size, it will * need to split, and cause a pointer to be added in the parent page * of the same node (which may in turn cause it to split). */ for (h = 0; h <= bt->root->height; h++) { if (path_old[h]->num_children < def->branches) break; path_new[h] = allocate_page(bt, h); if (!path_new[h]) goto fail; } /* If the split reaches the top (i.e. the root splits), then we need * to allocate a new root node. */ if (h > bt->root->height) { if (h >= MAX_HEIGHT) { fprintf(stderr, "btree: maximum height exceeded\n"); goto fail; } new_root = allocate_page(bt, h); if (!new_root) goto fail; } /* Trace up to one page above the split. At each page that needs * splitting, copy the top half of keys into the new page. Also, * insert a key into one of the pages at all pages from the leaf * to the page above the top of the split. */ for (h = 0; h <= bt->root->height; h++) { int s = slot_old[h] + 1; struct btree_page *p = path_old[h]; /* If there's a split at this level, copy the top half of * the keys from the old page to the new one. Check to see * if the position we were going to insert into is in the * old page or the new one. */ if (path_new[h]) { split_page(path_old[h], path_new[h]); if (s > p->num_children) { s -= p->num_children; p = path_new[h]; } } /* Insert the key in the appropriate page */ if (h) insert_ptr(p, s, PAGE_KEY(path_new[h - 1], 0), path_new[h - 1]); else insert_data(p, s, key, data); /* If there was no split at this level, there's nothing to * insert higher up, and we're all done. */ if (!path_new[h]) return 0; } /* If we made it this far, the split reached the top of the tree, and * we need to grow it using the extra page we allocated. */ assert (new_root); if (bt->slot[0] >= 0) { /* Fix up the cursor, if active */ bt->slot[new_root->height] = bt->path[bt->root->height] == new_root ? 1 : 0; bt->path[new_root->height] = new_root; } memcpy(PAGE_KEY(new_root, 0), def->zero, def->key_size); *PAGE_PTR(new_root, 0) = path_old[h - 1]; memcpy(PAGE_KEY(new_root, 1), PAGE_KEY(path_new[h - 1], 0), def->key_size); *PAGE_PTR(new_root, 1) = path_new[h - 1]; new_root->num_children = 2; bt->root = new_root; return 0; fail: for (h = 0; h <= bt->root->height; h++) if (path_new[h]) free(path_new[h]); return -1; }