From 96fc645034815fffbfac36e85f6a69546ee1d2bb Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Fri, 13 Oct 2023 11:56:50 +0200 Subject: [PATCH] feat(lsm): implement bt remove --- lsm/include/lsm.h | 12 +++--- lsm/src/bt/lsm_bt.c | 89 ++++++++++++++++++++++++++++++++++------ lsm/src/bt/lsm_bt.h | 6 ++- lsm/src/lsm_store.c | 3 +- lsm/src/lsm_store_node.c | 5 ++- lsm/src/lsm_store_node.h | 3 +- lsm/test/bt/bt.c | 43 +++++++++++++++++++ 7 files changed, 135 insertions(+), 26 deletions(-) diff --git a/lsm/include/lsm.h b/lsm/include/lsm.h index b216d71..2430091 100644 --- a/lsm/include/lsm.h +++ b/lsm/include/lsm.h @@ -6,10 +6,10 @@ #define LSM_MAX_SKIP_SIZE 8 typedef enum lsm_error { - lsm_error_ok = 0, - lsm_error_failed_alloc = 1, - lsm_error_not_found = 2, - lsm_error_already_present = 3 + lsm_error_ok = 0, + lsm_error_failed_alloc = 1, + lsm_error_not_found = 2, + lsm_error_already_present = 3 } 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 * 32-bit integer, so they can be easily combined into a bitmap. */ -typedef enum lsm_attr_type { - lsm_attr_type_entry_type = 1 << 0 -} lsm_attr_type; +typedef enum lsm_attr_type { lsm_attr_type_entry_type = 1 << 0 } lsm_attr_type; /** * A single attribute associated with an entry diff --git a/lsm/src/bt/lsm_bt.c b/lsm/src/bt/lsm_bt.c index 6b7b7bf..aadaaaf 100644 --- a/lsm/src/bt/lsm_bt.c +++ b/lsm/src/bt/lsm_bt.c @@ -17,6 +17,20 @@ lsm_error lsm_bt_node_init(lsm_bt_node **ptr, const char key, void *data) { 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_bt *bt = calloc(1, sizeof(lsm_bt)); @@ -29,18 +43,26 @@ lsm_error lsm_bt_init(lsm_bt **ptr) { 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_bt_node **dest = &bt->root; // Traverse down the tree until we reach the new point to insert our node - while (*dest != NULL) { - if ((*dest)->key == key) { - return lsm_error_already_present; - } - + while ((*dest != NULL) && ((*dest)->key != key)) { dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right; } + if (*dest != NULL) { + return lsm_error_already_present; + } + lsm_bt_node *node; 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_bt_node *node = bt->root; - while (node != NULL) { - if (node->key == key) { - *out = node->data; - - return lsm_error_ok; - } - + while ((node != NULL) && (node->key != key)) { 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; } diff --git a/lsm/src/bt/lsm_bt.h b/lsm/src/bt/lsm_bt.h index a886f68..60219d1 100644 --- a/lsm/src/bt/lsm_bt.h +++ b/lsm/src/bt/lsm_bt.h @@ -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); /** - * 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 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 diff --git a/lsm/src/lsm_store.c b/lsm/src/lsm_store.c index e167836..f3503bc 100644 --- a/lsm/src/lsm_store.c +++ b/lsm/src/lsm_store.c @@ -6,7 +6,8 @@ /** * 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 */ lsm_error lsm_store_init(lsm_store **ptr) { diff --git a/lsm/src/lsm_store_node.c b/lsm/src/lsm_store_node.c index 63bc238..b50f15e 100644 --- a/lsm/src/lsm_store_node.c +++ b/lsm/src/lsm_store_node.c @@ -1,7 +1,7 @@ #include -#include "lsm_store_node.h" #include "lsm.h" +#include "lsm_store_node.h" lsm_error lsm_store_inode_init(lsm_store_inode **ptr, const char c) { 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; } -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) { return lsm_error_not_found; } diff --git a/lsm/src/lsm_store_node.h b/lsm/src/lsm_store_node.h index 7fbcff3..548eb53 100644 --- a/lsm/src/lsm_store_node.h +++ b/lsm/src/lsm_store_node.h @@ -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. */ -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 diff --git a/lsm/test/bt/bt.c b/lsm/test/bt/bt.c index 152a6bc..21b4ed2 100644 --- a/lsm/test/bt/bt.c +++ b/lsm/test/bt/bt.c @@ -9,6 +9,7 @@ void test_init() { BT_INIT(); + lsm_bt_free(bt); } void test_insert_first() { @@ -22,6 +23,8 @@ void test_insert_first() { TEST_CHECK(data == (void *)1); TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_not_found); + + lsm_bt_free(bt); } 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(data == (void *)2); TEST_CHECK(lsm_bt_search(&data, bt, 'c') == lsm_error_not_found); + + lsm_bt_free(bt); } 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(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 = { @@ -63,5 +104,7 @@ TEST_LIST = { { "test insert first", test_insert_first }, { "test insert two", test_insert_two }, { "test insert multiple", test_insert_multiple }, + { "test remove root", test_remove_root }, + { "test remove multiple", test_remove_multiple }, { NULL, NULL } };