feat(lsm): implement bt insert & search
							parent
							
								
									fd42b446a6
								
							
						
					
					
						commit
						13e42181a2
					
				|  | @ -8,7 +8,8 @@ | |||
| typedef enum lsm_error { | ||||
|    lsm_error_ok = 0, | ||||
|    lsm_error_failed_alloc = 1, | ||||
|    lsm_error_not_found = 2 | ||||
|    lsm_error_not_found = 2, | ||||
|    lsm_error_already_present = 3 | ||||
| } lsm_error; | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -0,0 +1,70 @@ | |||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "lsm.h" | ||||
| #include "lsm_bt.h" | ||||
| 
 | ||||
| lsm_error lsm_bt_node_init(lsm_bt_node **ptr, const char key, void *data) { | ||||
|   lsm_bt_node *node = calloc(1, sizeof(lsm_bt_node)); | ||||
| 
 | ||||
|   if (node == NULL) { | ||||
|     return lsm_error_failed_alloc; | ||||
|   } | ||||
| 
 | ||||
|   node->key = key; | ||||
|   node->data = data; | ||||
|   *ptr = node; | ||||
| 
 | ||||
|   return lsm_error_ok; | ||||
| } | ||||
| 
 | ||||
| lsm_error lsm_bt_init(lsm_bt **ptr) { | ||||
|   lsm_bt *bt = calloc(1, sizeof(lsm_bt)); | ||||
| 
 | ||||
|   if (bt == NULL) { | ||||
|     return lsm_error_failed_alloc; | ||||
|   } | ||||
| 
 | ||||
|   *ptr = bt; | ||||
| 
 | ||||
|   return lsm_error_ok; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     } | ||||
| 
 | ||||
|     dest = key < (*dest)->key ? &(*dest)->left : &(*dest)->right; | ||||
|   } | ||||
| 
 | ||||
|   lsm_bt_node *node; | ||||
| 
 | ||||
|   if (lsm_bt_node_init(&node, key, data) != lsm_error_ok) { | ||||
|     return lsm_error_failed_alloc; | ||||
|   } | ||||
| 
 | ||||
|   *dest = node; | ||||
|   bt->size++; | ||||
| 
 | ||||
|   return lsm_error_ok; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     } | ||||
| 
 | ||||
|     node = key < node->key ? node->left : node->right; | ||||
|   } | ||||
| 
 | ||||
|   return lsm_error_not_found; | ||||
| } | ||||
|  | @ -0,0 +1,78 @@ | |||
| #ifndef LSM_BT_INTERNAL | ||||
| #define LSM_BT_INTERNAL | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "lsm.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Node inside a binary tree | ||||
|  */ | ||||
| typedef struct lsm_bt_node { | ||||
|   struct lsm_bt_node *left; | ||||
|   struct lsm_bt_node *right; | ||||
|   void *data; | ||||
|   char key; | ||||
| } lsm_bt_node; | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize a new binary tree node | ||||
|  * | ||||
|  * @param ptr where to store newly allocated pointer | ||||
|  * @param key key for the node | ||||
|  * @param data data to store | ||||
|  */ | ||||
| lsm_error lsm_bt_node_init(lsm_bt_node **ptr, const char key, void *data); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deallocate a single binary tree node | ||||
|  */ | ||||
| void lsm_bt_node_free(lsm_bt_node *node); | ||||
| 
 | ||||
| /**
 | ||||
|  * A binary tree implementation using char values as keys | ||||
|  */ | ||||
| typedef struct lsm_bt { | ||||
|   lsm_bt_node *root; | ||||
|   uint8_t size; | ||||
| } lsm_bt; | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize a new binary tree | ||||
|  * | ||||
|  * @param ptr where to store newly allocated pointer | ||||
|  */ | ||||
| lsm_error lsm_bt_init(lsm_bt **ptr); | ||||
| 
 | ||||
| /**
 | ||||
|  * Deallocate an entire binary tree, including all its nodes | ||||
|  */ | ||||
| void lsm_bt_free(lsm_bt *bt); | ||||
| 
 | ||||
| /**
 | ||||
|  * Search for the data stored behind the given key. | ||||
|  * | ||||
|  * @param out pointer to store data pointer in | ||||
|  * @param bt binary tree to search | ||||
|  * @param key key to search | ||||
|  */ | ||||
| lsm_error lsm_bt_search(void **out, lsm_bt *bt, char key); | ||||
| 
 | ||||
| /**
 | ||||
|  * Insert a new data value into the tree with the given key. | ||||
|  * | ||||
|  * @param bt binary tree to insert into | ||||
|  * @param key key to insert | ||||
|  * @param data data to store | ||||
|  */ | ||||
| lsm_error lsm_bt_insert(lsm_bt *bt, char key, void *data); | ||||
| 
 | ||||
| /**
 | ||||
|  * Remove the given key from the binary tree. | ||||
|  * | ||||
|  * @param bt binary tree to remove from | ||||
|  * @param key key to remove | ||||
|  */ | ||||
| lsm_error lsm_bt_remove(lsm_bt *bt, char key); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,67 @@ | |||
| #include "test.h" | ||||
| #include "lsm.h" | ||||
| #include "lsm_bt.h" | ||||
| 
 | ||||
| #define BT_INIT() \ | ||||
|   lsm_bt *bt; \ | ||||
|   TEST_CHECK(lsm_bt_init(&bt) == lsm_error_ok); \ | ||||
|   TEST_CHECK(bt != NULL) | ||||
| 
 | ||||
| void test_init() { | ||||
|   BT_INIT(); | ||||
| } | ||||
| 
 | ||||
| void test_insert_first() { | ||||
|   BT_INIT(); | ||||
| 
 | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'a', (void *)1) == lsm_error_ok); | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'a', (void *)1) == lsm_error_already_present); | ||||
| 
 | ||||
|   void *data; | ||||
|   TEST_CHECK(lsm_bt_search(&data, bt, 'a') == lsm_error_ok); | ||||
|   TEST_CHECK(data == (void *)1); | ||||
| 
 | ||||
|   TEST_CHECK(lsm_bt_search(&data, bt, 'b') == lsm_error_not_found); | ||||
| } | ||||
| 
 | ||||
| void test_insert_two() { | ||||
|   BT_INIT(); | ||||
| 
 | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'a', (void *)1) == lsm_error_ok); | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'a', (void *)1) == lsm_error_already_present); | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'b', (void *)2) == lsm_error_ok); | ||||
|   TEST_CHECK(lsm_bt_insert(bt, 'b', (void *)2) == lsm_error_already_present); | ||||
| 
 | ||||
|   void *data; | ||||
|   TEST_CHECK(lsm_bt_search(&data, bt, 'a') == lsm_error_ok); | ||||
|   TEST_CHECK(data == (void *)1); | ||||
|   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); | ||||
| } | ||||
| 
 | ||||
| void test_insert_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; | ||||
|   for (size_t i = 0; i < char_count; i++) { | ||||
|     TEST_CHECK(lsm_bt_insert(bt, chars[i], (void *)(i + 1)) == lsm_error_already_present); | ||||
|     TEST_CHECK(lsm_bt_search(&data, bt, chars[i]) == lsm_error_ok); | ||||
|     TEST_CHECK(data == (void *)(i + 1)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_LIST = { | ||||
|   { "test init", test_init }, | ||||
|   { "test insert first", test_insert_first }, | ||||
|   { "test insert two", test_insert_two }, | ||||
|   { "test insert multiple", test_insert_multiple }, | ||||
|   { NULL, NULL } | ||||
| }; | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue