feat(lsm): implement bt remove

lsm
Jef Roosens 2023-10-13 11:56:50 +02:00
parent 13e42181a2
commit 96fc645034
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
7 changed files with 135 additions and 26 deletions

View File

@ -6,10 +6,10 @@
#define LSM_MAX_SKIP_SIZE 8 #define LSM_MAX_SKIP_SIZE 8
typedef enum lsm_error { typedef enum lsm_error {
lsm_error_ok = 0, lsm_error_ok = 0,
lsm_error_failed_alloc = 1, lsm_error_failed_alloc = 1,
lsm_error_not_found = 2, lsm_error_not_found = 2,
lsm_error_already_present = 3 lsm_error_already_present = 3
} lsm_error; } lsm_error;
/** /**
@ -29,9 +29,7 @@ typedef struct lsm_string {
* The type of an attribute. Each type is represented as a single bit of a * The type of an attribute. Each type is represented as a single bit of a
* 32-bit integer, so they can be easily combined into a bitmap. * 32-bit integer, so they can be easily combined into a bitmap.
*/ */
typedef enum lsm_attr_type { typedef enum lsm_attr_type { lsm_attr_type_entry_type = 1 << 0 } lsm_attr_type;
lsm_attr_type_entry_type = 1 << 0
} lsm_attr_type;
/** /**
* A single attribute associated with an entry * A single attribute associated with an entry

View File

@ -17,6 +17,20 @@ lsm_error lsm_bt_node_init(lsm_bt_node **ptr, const char key, void *data) {
return lsm_error_ok; return lsm_error_ok;
} }
void lsm_bt_node_free(lsm_bt_node *node) { free(node); }
void lsm_bt_node_free_recursive(lsm_bt_node *node) {
if (node->left != NULL) {
lsm_bt_node_free_recursive(node->left);
}
if (node->right != NULL) {
lsm_bt_node_free_recursive(node->right);
}
lsm_bt_node_free(node);
}
lsm_error lsm_bt_init(lsm_bt **ptr) { lsm_error lsm_bt_init(lsm_bt **ptr) {
lsm_bt *bt = calloc(1, sizeof(lsm_bt)); lsm_bt *bt = calloc(1, sizeof(lsm_bt));
@ -29,18 +43,26 @@ lsm_error lsm_bt_init(lsm_bt **ptr) {
return lsm_error_ok; return lsm_error_ok;
} }
void lsm_bt_free(lsm_bt *bt) {
if (bt->root != NULL) {
lsm_bt_node_free_recursive(bt->root);
}
free(bt);
}
lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data) { lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data) {
lsm_bt_node **dest = &bt->root; lsm_bt_node **dest = &bt->root;
// Traverse down the tree until we reach the new point to insert our node // Traverse down the tree until we reach the new point to insert our node
while (*dest != NULL) { while ((*dest != NULL) && ((*dest)->key != key)) {
if ((*dest)->key == key) {
return lsm_error_already_present;
}
dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right; dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right;
} }
if (*dest != NULL) {
return lsm_error_already_present;
}
lsm_bt_node *node; lsm_bt_node *node;
if (lsm_bt_node_init(&node, key, data) != lsm_error_ok) { if (lsm_bt_node_init(&node, key, data) != lsm_error_ok) {
@ -56,15 +78,56 @@ lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data) {
lsm_error lsm_bt_search(void **out, lsm_bt *bt, char key) { lsm_error lsm_bt_search(void **out, lsm_bt *bt, char key) {
lsm_bt_node *node = bt->root; lsm_bt_node *node = bt->root;
while (node != NULL) { while ((node != NULL) && (node->key != key)) {
if (node->key == key) {
*out = node->data;
return lsm_error_ok;
}
node = key < node->key ? node->left : node->right; node = key < node->key ? node->left : node->right;
} }
return lsm_error_not_found; if (node == NULL) {
return lsm_error_not_found;
}
*out = node->data;
return lsm_error_ok;
}
lsm_error lsm_bt_remove(void **out, lsm_bt *bt, char key) {
if (bt->root == NULL) {
return lsm_error_not_found;
}
lsm_bt_node **dest = &bt->root;
while ((*dest != NULL) && ((*dest)->key != key)) {
dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right;
}
if (*dest == NULL) {
return lsm_error_not_found;
}
*out = (*dest)->data;
bt->size--;
if (((*dest)->left != NULL) && ((*dest)->right != NULL)) {
lsm_bt_node **succ = &(*dest)->right;
while ((*succ)->left != NULL) {
succ = &(*succ)->left;
}
(*dest)->key = (*succ)->key;
(*dest)->data = (*succ)->data;
lsm_bt_node *succ_replacement = (*succ)->right;
lsm_bt_node_free(*succ);
*succ = succ_replacement;
} else {
lsm_bt_node *replacement =
(*dest)->left != NULL ? (*dest)->left : (*dest)->right;
lsm_bt_node_free(*dest);
*dest = replacement;
}
return lsm_error_ok;
} }

View File

@ -68,11 +68,13 @@ lsm_error lsm_bt_search(void **out, lsm_bt *bt, char key);
lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data); lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data);
/** /**
* Remove the given key from the binary tree. * Remove the given key from the binary tree. Ownership of the data pointer is
* returned to the caller.
* *
* @param out address to write data pointer to
* @param bt binary tree to remove from * @param bt binary tree to remove from
* @param key key to remove * @param key key to remove
*/ */
lsm_error lsm_bt_remove(lsm_bt *bt, char key); lsm_error lsm_bt_remove(void **out, lsm_bt *bt, char key);
#endif #endif

View File

@ -6,7 +6,8 @@
/** /**
* Initialize a new lsm_store struct. * Initialize a new lsm_store struct.
* *
* @param lsm_store pointer to where to store the newly allocated object's pointer * @param lsm_store pointer to where to store the newly allocated object's
* pointer
* @return success of the function * @return success of the function
*/ */
lsm_error lsm_store_init(lsm_store **ptr) { lsm_error lsm_store_init(lsm_store **ptr) {

View File

@ -1,7 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "lsm_store_node.h"
#include "lsm.h" #include "lsm.h"
#include "lsm_store_node.h"
lsm_error lsm_store_inode_init(lsm_store_inode **ptr, const char c) { lsm_error lsm_store_inode_init(lsm_store_inode **ptr, const char c) {
lsm_store_inode *node = calloc(1, sizeof(lsm_store_inode)); lsm_store_inode *node = calloc(1, sizeof(lsm_store_inode));
@ -28,7 +28,8 @@ lsm_error lsm_store_node_init(lsm_store_node **ptr) {
return lsm_error_ok; return lsm_error_ok;
} }
lsm_error lsm_store_node_search(lsm_store_node **out_ptr, lsm_store_node *node, const char c) { lsm_error lsm_store_node_search(lsm_store_node **out_ptr, lsm_store_node *node,
const char c) {
if (node->size == 0) { if (node->size == 0) {
return lsm_error_not_found; return lsm_error_not_found;
} }

View File

@ -37,6 +37,7 @@ lsm_error lsm_store_node_init(lsm_store_node **out);
/** /**
* Search for the next node following the given character, if present. * Search for the next node following the given character, if present.
*/ */
lsm_error lsm_store_node_search(lsm_store_node **out, lsm_store_node *node, const char c); lsm_error lsm_store_node_search(lsm_store_node **out, lsm_store_node *node,
const char c);
#endif #endif

View File

@ -9,6 +9,7 @@
void test_init() { void test_init() {
BT_INIT(); BT_INIT();
lsm_bt_free(bt);
} }
void test_insert_first() { void test_insert_first() {
@ -22,6 +23,8 @@ void test_insert_first() {
TEST_CHECK(data == (void *)1); TEST_CHECK(data == (void *)1);
TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_not_found); TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_not_found);
lsm_bt_free(bt);
} }
void test_insert_two() { void test_insert_two() {
@ -38,6 +41,8 @@ void test_insert_two() {
TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_ok); TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_ok);
TEST_CHECK(data == (void *)2); TEST_CHECK(data == (void *)2);
TEST_CHECK(lsm_bt_search(&data, bt, 'c') == lsm_error_not_found); TEST_CHECK(lsm_bt_search(&data, bt, 'c') == lsm_error_not_found);
lsm_bt_free(bt);
} }
void test_insert_multiple() { void test_insert_multiple() {
@ -56,6 +61,42 @@ void test_insert_multiple() {
TEST_CHECK(lsm_bt_search(&data, bt, chars[i]) == lsm_error_ok); TEST_CHECK(lsm_bt_search(&data, bt, chars[i]) == lsm_error_ok);
TEST_CHECK(data == (void *)(i + 1)); TEST_CHECK(data == (void *)(i + 1));
} }
lsm_bt_free(bt);
}
void test_remove_root() {
BT_INIT();
TEST_CHECK(lsm_bt_insert(bt, 'a', (void *)1) == lsm_error_ok);
void *data;
TEST_CHECK(lsm_bt_remove(&data, bt, 'a') == lsm_error_ok);
TEST_CHECK(data == (void *)1);
TEST_CHECK(bt->root == NULL);
lsm_bt_free(bt);
}
void test_remove_multiple() {
char chars[] = "falcoep";
size_t char_count = sizeof(chars) / sizeof(char);
BT_INIT();
for (size_t i = 0; i < char_count; i++) {
TEST_CHECK(lsm_bt_insert(bt, chars[i], (void *)(i + 1)) == lsm_error_ok);
}
void *data;
TEST_CHECK(lsm_bt_remove(&data, bt, 'l') == lsm_error_ok);
TEST_CHECK(data == (void *)3);
TEST_CHECK(lsm_bt_remove(&data, bt, 'l') == lsm_error_not_found);
TEST_CHECK(lsm_bt_remove(&data, bt, 'e') == lsm_error_ok);
TEST_CHECK(data == (void *)6);
TEST_CHECK(lsm_bt_remove(&data, bt, 'e') == lsm_error_not_found);
lsm_bt_free(bt);
} }
TEST_LIST = { TEST_LIST = {
@ -63,5 +104,7 @@ TEST_LIST = {
{ "test insert first", test_insert_first }, { "test insert first", test_insert_first },
{ "test insert two", test_insert_two }, { "test insert two", test_insert_two },
{ "test insert multiple", test_insert_multiple }, { "test insert multiple", test_insert_multiple },
{ "test remove root", test_remove_root },
{ "test remove multiple", test_remove_multiple },
{ NULL, NULL } { NULL, NULL }
}; };