feat(lsm): iterator over items in trie

This commit is contained in:
Jef Roosens 2023-12-23 10:06:02 +01:00
parent 5564e23ceb
commit f4d711365d
Signed by: Jef Roosens
GPG key ID: B75D4F293C7052DB
9 changed files with 229 additions and 8 deletions

View file

@ -0,0 +1,117 @@
#include "lsm.h"
#include "lsm/trie_internal.h"
/**
* Advance the iterator so that `next` now points to a node containing data. If
* no more data nodes are found, `next` is set to NULL. The initial value of
* `next` is ignored.
*/
lsm_error lsm_trie_iter_next_data_node(lsm_trie_iterator *iter) {
do {
// Traverse back up the stack until we reach either the end of the subtree,
// or an iterator that hasn't been exhausted yet
while ((iter->stack.len > 0) &&
!lsm_bt_iter_next((void **)&iter->next, NULL,
&iter->stack.arr[iter->stack.len - 1])) {
iter->stack.len--;
}
if (iter->stack.len == 0) {
iter->next = NULL;
return lsm_error_ok;
}
// Add node's subtree to the stack
if (iter->stack.len == iter->stack.cap) {
lsm_bt_iterator *arr = realloc(
iter->stack.arr, iter->stack.cap * 2 * sizeof(lsm_bt_iterator));
if (arr == NULL) {
return lsm_error_failed_alloc;
}
iter->stack.arr = arr;
iter->stack.cap *= 2;
}
lsm_bt_iter(&iter->stack.arr[iter->stack.len], &iter->next->bt);
iter->stack.len++;
} while (iter->next->data == NULL);
return lsm_error_ok;
}
lsm_error lsm_trie_iter(lsm_trie_iterator **out, const lsm_trie *trie,
const lsm_str *prefix) {
uint64_t prefix_len = prefix == NULL ? 0 : lsm_str_len(prefix);
uint64_t index = 0;
lsm_trie_node *node = trie->root;
// Simplified traversal down the trie to find the root of the subtree
// contaiing all nodes with the given prefix
while ((index < prefix_len) && (node != NULL)) {
char c = lsm_str_char(prefix, index);
lsm_error res = lsm_bt_search((void **)&node, &node->bt, c);
switch (res) {
case lsm_error_ok:
index += 1 + lsm_str_len(&node->skip);
break;
case lsm_error_not_found:
node = NULL;
break;
default:
return res;
};
}
lsm_trie_iterator *iter = calloc(1, sizeof(lsm_trie_iterator));
if (iter == NULL) {
return lsm_error_failed_alloc;
}
iter->next = node;
if (node != NULL) {
lsm_bt_iterator *arr = malloc(sizeof(lsm_bt_iterator));
if (arr == NULL) {
free(iter);
return lsm_error_failed_alloc;
}
iter->stack.arr = arr;
iter->stack.cap = 1;
iter->stack.len = 1;
lsm_bt_iter(&iter->stack.arr[0], &node->bt);
if (node->data == NULL) {
LSM_RES(lsm_trie_iter_next_data_node(iter));
}
}
*out = iter;
return lsm_error_ok;
}
lsm_error lsm_trie_iter_next(void **out, lsm_trie_iterator *iter) {
if (iter->next == NULL) {
return lsm_error_done;
}
*out = iter->next->data;
return lsm_trie_iter_next_data_node(iter);
}
void lsm_trie_iter_free(lsm_trie_iterator *iter) {
free(iter->stack.arr);
free(iter);
}