feat(lsm): implement bt remove
parent
13e42181a2
commit
96fc645034
|
@ -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
|
||||||
|
|
|
@ -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,16 +43,24 @@ 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) {
|
dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right;
|
||||||
return lsm_error_already_present;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right;
|
if (*dest != NULL) {
|
||||||
|
return lsm_error_already_present;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsm_bt_node *node;
|
lsm_bt_node *node;
|
||||||
|
@ -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) {
|
node = key < node->key ? node->left : node->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
return lsm_error_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
*out = node->data;
|
*out = node->data;
|
||||||
|
|
||||||
return lsm_error_ok;
|
return lsm_error_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = key < node->key ? node->left : node->right;
|
lsm_error lsm_bt_remove(void **out, lsm_bt *bt, char key) {
|
||||||
}
|
if (bt->root == NULL) {
|
||||||
|
|
||||||
return lsm_error_not_found;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue