#include #include /** * Helper accessors to safely locate key and value buffers within a generic node allocation block. */ C_STATIC_FORCE_INLINE void* c_BST_NodeKey(c_BSTNode_t* node) { return (void*)((char*)node + sizeof(c_BSTNode_t)); } C_STATIC_FORCE_INLINE void* c_BST_NodeVal(c_BSTNode_t* node, c_size_t key_size) { return (void*)((char*)node + sizeof(c_BSTNode_t) + key_size); } /** * Creates and initializes a standalone tree node layout. */ C_STATIC_FORCE_INLINE c_BSTNode_t* c_BST_CreateNode(const void* key, const void* val, c_size_t ks, c_size_t vs) { c_BSTNode_t* node = (c_BSTNode_t*)C_ALLOC(sizeof(c_BSTNode_t) + ks + vs); if (node == NULL) return NULL; node->left = NULL; node->right = NULL; memcpy(c_BST_NodeKey(node), key, ks); memcpy(c_BST_NodeVal(node, ks), val, vs); return node; } /** * Internal recursive post-order destructor helper. */ static void c_BST_DestroyNodes(c_BSTNode_t* node) { if (node == NULL) return; c_BST_DestroyNodes(node->left); c_BST_DestroyNodes(node->right); C_FREE(node); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_err_t c_BST_Init(c_BST_t* tree, c_size_t key_size, c_size_t val_size, int (*compar)(const void*, const void*)) { if (tree == NULL || key_size == 0 || val_size == 0 || compar == NULL) return C_ERR_PARAM; tree->root = NULL; tree->key_size = key_size; tree->val_size = val_size; tree->size = 0; tree->compar = compar; return C_ERR_OK; } void c_BST_Destroy(c_BST_t* tree) { if (tree) { c_BST_DestroyNodes(tree->root); tree->root = NULL; tree->size = 0; } } c_err_t c_BST_Clear(c_BST_t* tree) { if (tree == NULL) return C_ERR_PARAM; c_BST_DestroyNodes(tree->root); tree->root = NULL; tree->size = 0; return C_ERR_OK; } c_bool_t c_BST_Contains(const c_BST_t* tree, const void* key) { if (tree == NULL || key == NULL) return C_FALSE; c_BSTNode_t* curr = tree->root; while (curr != NULL) { int cmp = tree->compar(key, c_BST_NodeKey(curr)); if (cmp == 0) return C_TRUE; curr = (cmp < 0) ? curr->left : curr->right; } return C_FALSE; } c_err_t c_BST_Put(c_BST_t* tree, const void* key, const void* val) { if (tree == NULL || key == NULL || val == NULL) return C_ERR_PARAM; c_BSTNode_t** link = &tree->root; c_BSTNode_t* curr = tree->root; while (curr != NULL) { int cmp = tree->compar(key, c_BST_NodeKey(curr)); if (cmp == 0) { // Overwrite existing value for matching symbol key memcpy(c_BST_NodeVal(curr, tree->key_size), val, tree->val_size); return C_ERR_OK; } link = (cmp < 0) ? &curr->left : &curr->right; curr = *link; } // Key is unique, construct a new node configuration structure c_BSTNode_t* new_node = c_BST_CreateNode(key, val, tree->key_size, tree->val_size); if (new_node == NULL) return C_ERR_NOMEM; *link = new_node; tree->size++; return C_ERR_OK; } void* c_BST_Get(const c_BST_t* tree, const void* key) { if (tree == NULL || key == NULL) return NULL; c_BSTNode_t* curr = tree->root; while (curr != NULL) { int cmp = tree->compar(key, c_BST_NodeKey(curr)); if (cmp == 0) return c_BST_NodeVal(curr, tree->key_size); curr = (cmp < 0) ? curr->left : curr->right; } return NULL; } c_err_t c_BST_Delete(c_BST_t* tree, const void* key) { if (tree == NULL || key == NULL) return C_ERR_PARAM; c_BSTNode_t** link = &tree->root; c_BSTNode_t* curr = tree->root; while (curr != NULL) { int cmp = tree->compar(key, c_BST_NodeKey(curr)); if (cmp == 0) break; link = (cmp < 0) ? &curr->left : &curr->right; curr = *link; } if (curr == NULL) return C_ERR_NOT_FOUND; // Standard Hibbard deletion implementation sequence matching tree boundaries if (curr->left == NULL) { *link = curr->right; } else if (curr->right == NULL) { *link = curr->left; } else { // Node has two children; locate the successor node (smallest node in the right sub-tree) c_BSTNode_t** succ_link = &curr->right; c_BSTNode_t* succ = curr->right; while (succ->left != NULL) { succ_link = &succ->left; succ = succ->left; } // Delink the successor node from its previous position *succ_link = succ->right; // Route child structures of the node being deleted into the successor succ->left = curr->left; succ->right = curr->right; *link = succ; } C_FREE(curr); tree->size--; return C_ERR_OK; }