static void delete_item(struct btree_page *p, int s) { const struct btree_def *def = p->def; btree_t bt = p->owner; int r = p->num_children - s - 1; assert (s >= 0 && s < p->num_children); memmove(PAGE_KEY(p, s), PAGE_KEY(p, s + 1), r * def->key_size); if (p->height) memmove(PAGE_PTR(p, s), PAGE_PTR(p, s + 1), r * sizeof(struct btree_page *)); else memmove(PAGE_DATA(p, s), PAGE_DATA(p, s + 1), r * def->data_size); p->num_children--; /* Fix up the cursor if we deleted before it */ if (bt->slot[0] >= 0 && bt->path[p->height] == p && s <= bt->slot[p->height]) bt->slot[p->height]--; }
static void merge_pages(struct btree_page *lower, struct btree_page *higher) { const struct btree_def *def = lower->def; btree_t bt = lower->owner; assert (lower->num_children + higher->num_children < def->branches); memcpy(PAGE_KEY(lower, lower->num_children), PAGE_KEY(higher, 0), higher->num_children * def->key_size); if (lower->height) memcpy(PAGE_PTR(lower, lower->num_children), PAGE_PTR(higher, 0), higher->num_children * sizeof(struct btree_page *)); else memcpy(PAGE_DATA(lower, lower->num_children), PAGE_DATA(higher, 0), higher->num_children * def->data_size); lower->num_children += higher->num_children; /* Fix up the cursor if we subsumed an active page */ if (bt->slot[0] >= 0) { if (bt->path[higher->height] == higher) { bt->path[higher->height] = lower; bt->slot[higher->height] += lower->num_children; } } }
static void insert_data(struct btree_page *p, int s, const void *key, const void *data) { const struct btree_def *def = p->def; btree_t bt = p->owner; int r = p->num_children - s; assert (!p->height); assert (p->num_children < def->branches); assert (s >= 0 && s <= p->num_children); memmove(PAGE_KEY(p, s + 1), PAGE_KEY(p, s), r * def->key_size); memmove(PAGE_DATA(p, s + 1), PAGE_DATA(p, s), r * def->data_size); memcpy(PAGE_KEY(p, s), key, def->key_size); memcpy(PAGE_DATA(p, s), data, def->data_size); p->num_children++; /* Fix up the cursor if we inserted before it, or if we're inserting * a pointer to the cursor data itself (as in a borrow). */ if (bt->slot[0] >= 0) { if (data == PAGE_DATA(bt->path[0], bt->slot[0])) { bt->path[0] = p; bt->slot[0] = s; } else if (bt->path[0] == p && s <= bt->slot[0]) { bt->slot[0]++; } } }
static void split_page(struct btree_page *op, struct btree_page *np) { const struct btree_def *def = op->def; btree_t bt = op->owner; const int halfsize = def->branches / 2; assert (op->num_children == def->branches); memcpy(PAGE_KEY(np, 0), PAGE_KEY(op, halfsize), halfsize * def->key_size); if (op->height) memcpy(PAGE_PTR(np, 0), PAGE_PTR(op, halfsize), halfsize * sizeof(struct btree_page *)); else memcpy(PAGE_DATA(np, 0), PAGE_DATA(op, halfsize), halfsize * def->data_size); op->num_children = halfsize; np->num_children = halfsize; /* Fix up the cursor if we split an active page */ if (bt->slot[0] >= 0 && bt->path[op->height] == op && bt->slot[op->height] > op->num_children) { bt->slot[op->height] -= op->num_children; bt->path[op->height] = np; } }
int btree_get(btree_t bt, const void *key, void *data) { const struct btree_def *def = bt->def; struct btree_page *p = bt->root; int h; check_btree(bt); if (!key) return btree_select(bt, NULL, BTREE_READ, NULL, data); for (h = bt->root->height; h >= 0; h--) { int s = find_key_le(p, key); if (h) { assert (s >= 0 && s < p->num_children); p = *PAGE_PTR(p, s); } else if (s >= 0 && !def->compare(key, PAGE_KEY(p, s))) { memcpy(data, PAGE_DATA(p, s), def->data_size); return 0; } } return 1; }
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); }
int btree_select(btree_t bt, const void *key, btree_selmode_t mode, void *key_ret, void *data_ret) { const struct btree_def *def = bt->def; check_btree(bt); switch (mode) { case BTREE_CLEAR: bt->slot[0] = -1; break; case BTREE_READ: break; case BTREE_EXACT: case BTREE_LE: if (!trace_path(bt, key, bt->path, bt->slot) && mode == BTREE_EXACT) bt->slot[0] = -1; break; case BTREE_FIRST: cursor_first(bt); break; case BTREE_NEXT: cursor_next(bt); break; } /* Return the data at the cursor */ if (bt->slot[0] >= 0) { if (key_ret) memcpy(key_ret, PAGE_KEY(bt->path[0], bt->slot[0]), def->key_size); if (data_ret) memcpy(data_ret, PAGE_DATA(bt->path[0], bt->slot[0]), def->data_size); return 0; } return 1; }
void abc1600_state::write_user_memory(offs_t offset, UINT8 data) { int segment = (offset >> 15) & 0x1f; int page = (offset >> 11) & 0x0f; UINT16 page_data = PAGE_DATA(segment, page); offs_t virtual_offset = ((page_data & 0x3ff) << 11) | (offset & 0x7ff); if (!PAGE_WP) return; //if (PAGE_NONX) BUS ERROR if (virtual_offset < 0x1fe000) { write_ram(virtual_offset, data); } else { write_io(virtual_offset, data); } }
UINT8 abc1600_state::read_user_memory(offs_t offset) { int segment = (offset >> 15) & 0x1f; int page = (offset >> 11) & 0x0f; UINT16 page_data = PAGE_DATA(segment, page); offs_t virtual_offset = ((page_data & 0x3ff) << 11) | (offset & 0x7ff); //if (PAGE_NONX) BUS ERROR UINT8 data = 0; if (virtual_offset < 0x1fe000) { data = read_ram(virtual_offset); } else { data = read_io(virtual_offset); } return data; }
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; }