#ifndef BLUELIB_CORE_BTREE_H_ #define BLUELIB_CORE_BTREE_H_ #include #include #include #include #include #define B_BTREE_INIT \ { \ 0 \ } #ifdef __cplusplus extern "C" { #endif /* defines a simple node insertion function. this function assumes that your nodes have simple integer keys that can be compared with the usual operators. EXAMPLE: if you have a tree node type like this: struct my_tree_node { int key; b_btree_node base; } You would use the following call to generate an insert function for a tree with this node type: BTREE_DEFINE_SIMPLE_INSERT( struct my_tree_node, base, key, my_tree_node_insert); Which would emit a function defined like: static void my_tree_node_insert(b_btree *tree, struct my_tree_node *node); @param node_type your custom tree node type. usually a structure that contains a b_btree_node member. @param container_node_member the name of the b_btree_node member variable within your custom type. @param container_key_member the name of the key member variable within your custom type. @param function_name the name of the function to generate. */ #define B_BTREE_DEFINE_SIMPLE_INSERT( \ node_type, container_node_member, container_key_member, function_name) \ void function_name(b_btree *tree, node_type *node) \ { \ if (!tree->b_root) { \ tree->b_root = &node->container_node_member; \ b_btree_insert_fixup(tree, &node->container_node_member); \ return; \ } \ \ b_btree_node *cur = tree->b_root; \ while (1) { \ node_type *cur_node = b_unbox( \ node_type, cur, container_node_member); \ b_btree_node *next = NULL; \ \ if (node->container_key_member \ >= cur_node->container_key_member) { \ next = b_btree_right(cur); \ \ if (!next) { \ b_btree_put_right( \ cur, \ &node->container_node_member); \ break; \ } \ } else if ( \ node->container_key_member \ < cur_node->container_key_member) { \ next = b_btree_left(cur); \ \ if (!next) { \ b_btree_put_left( \ cur, \ &node->container_node_member); \ break; \ } \ } \ \ cur = next; \ } \ \ b_btree_insert_fixup(tree, &node->container_node_member); \ } /* defines a node insertion function. this function should be used for trees with complex node keys that cannot be directly compared. a comparator for your keys must be supplied. EXAMPLE: if you have a tree node type like this: struct my_tree_node { complex_key_t key; b_btree_node base; } You would need to define a comparator function or macro with the following signature: int my_comparator(struct my_tree_node *a, struct my_tree_node *b); Which implements the following: return -1 if a < b return 0 if a == b return 1 if a > b You would use the following call to generate an insert function for a tree with this node type: BTREE_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert, my_comparator); Which would emit a function defined like: static void my_tree_node_insert(b_btree *tree, struct my_tree_node *node); @param node_type your custom tree node type. usually a structure that contains a b_btree_node member. @param container_node_member the name of the b_btree_node member variable within your custom type. @param container_key_member the name of the key member variable within your custom type. @param function_name the name of the function to generate. @param comparator the name of a comparator function or functional-macro that conforms to the requirements listed above. */ #define B_BTREE_DEFINE_INSERT( \ node_type, container_node_member, container_key_member, function_name, \ comparator) \ void function_name(b_btree *tree, node_type *node) \ { \ if (!tree->b_root) { \ tree->b_root = &node->container_node_member; \ b_btree_insert_fixup(tree, &node->container_node_member); \ return; \ } \ \ b_btree_node *cur = tree->b_root; \ while (1) { \ node_type *cur_node = b_unbox( \ node_type, cur, container_node_member); \ b_btree_node *next = NULL; \ int cmp = comparator(node, cur_node); \ \ if (cmp >= 0) { \ next = b_btree_right(cur); \ \ if (!next) { \ b_btree_put_right( \ cur, \ &node->container_node_member); \ break; \ } \ } else if (cmp < 0) { \ next = b_btree_left(cur); \ \ if (!next) { \ b_btree_put_left( \ cur, \ &node->container_node_member); \ break; \ } \ } else { \ return; \ } \ \ cur = next; \ } \ \ b_btree_insert_fixup(tree, &node->container_node_member); \ } /* defines a simple tree search function. this function assumes that your nodes have simple integer keys that can be compared with the usual operators. EXAMPLE: if you have a tree node type like this: struct my_tree_node { int key; b_btree_node base; } You would use the following call to generate a search function for a tree with this node type: BTREE_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key, my_tree_node_get); Which would emit a function defined like: static struct my_tree_node *my_tree_node_get(b_btree *tree, int key); @param node_type your custom tree node type. usually a structure that contains a b_btree_node member. @param key_type the type name of the key embedded in your custom tree node type. this type must be compatible with the builtin comparison operators. @param container_node_member the name of the b_btree_node member variable within your custom type. @param container_key_member the name of the key member variable within your custom type. @param function_name the name of the function to generate. */ #define B_BTREE_DEFINE_SIMPLE_GET( \ node_type, key_type, container_node_member, container_key_member, \ function_name) \ node_type *function_name(const b_btree *tree, key_type key) \ { \ b_btree_node *cur = tree->b_root; \ while (cur) { \ node_type *cur_node = b_unbox( \ node_type, cur, container_node_member); \ if (key > cur_node->container_key_member) { \ cur = b_btree_right(cur); \ } else if (key < cur_node->container_key_member) { \ cur = b_btree_left(cur); \ } else { \ return cur_node; \ } \ } \ \ return NULL; \ } #define b_btree_foreach(it, btree) \ for (int z__b_unique_name() = b_btree_iterator_begin(btree, it); \ (it)->node != NULL; b_btree_iterator_next(it)) /* binary tree nodes. this *cannot* be used directly. you need to define a custom node type that contains a member variable of type b_btree_node. you would then use the supplied macros to define functions to manipulate your custom binary tree. */ typedef struct b_btree_node { struct b_btree_node *b_parent, *b_left, *b_right; unsigned short b_height; } b_btree_node; /* binary tree. unlike b_btree_node, you can define variables of type b_btree. */ typedef struct b_btree { b_btree_node *b_root; } b_btree; typedef struct b_btree_iterator { b_iterator _base; size_t i, depth; b_btree_node *node; b_btree *_b; } b_btree_iterator; /* re-balance a binary tree after an insertion operation. NOTE that, if you define an insertion function using BTREE_DEFINE_INSERT or similar, this function will automatically called for you. @param tree the tree to re-balance. @param node the node that was just inserted into the tree. */ BLUE_API void b_btree_insert_fixup(b_btree *tree, b_btree_node *node); /* delete a node from a binary tree and re-balance the tree afterwards. @param tree the tree to delete from @param node the node to delete. */ BLUE_API void b_btree_delete(b_btree *tree, b_btree_node *node); /* get the first node in a binary tree. this will be the node with the smallest key (i.e. the node that is furthest-left from the root) */ BLUE_API b_btree_node *b_btree_first(const b_btree *tree); /* get the last node in a binary tree. this will be the node with the largest key (i.e. the node that is furthest-right from the root) */ BLUE_API b_btree_node *b_btree_last(const b_btree *tree); /* for any binary tree node, this function returns the node with the * next-largest key value */ BLUE_API b_btree_node *b_btree_next(const b_btree_node *node); /* for any binary tree node, this function returns the node with the * next-smallest key value */ BLUE_API b_btree_node *b_btree_prev(const b_btree_node *node); /* return true if the btree is empty, false otherwise */ static inline bool b_btree_empty(const b_btree *tree) { return tree->b_root == NULL; } /* sets `child` as the immediate left-child of `parent` */ static inline void b_btree_put_left(b_btree_node *parent, b_btree_node *child) { parent->b_left = child; child->b_parent = parent; } /* sets `child` as the immediate right-child of `parent` */ static inline void b_btree_put_right(b_btree_node *parent, b_btree_node *child) { parent->b_right = child; child->b_parent = parent; } /* get the immediate left-child of `node` */ static inline b_btree_node *b_btree_left(b_btree_node *node) { return node->b_left; } /* get the immediate right-child of `node` */ static inline b_btree_node *b_btree_right(b_btree_node *node) { return node->b_right; } /* get the immediate parent of `node` */ static inline b_btree_node *b_btree_parent(b_btree_node *node) { return node->b_parent; } /* get the height of `node`. the height of a node is defined as the length of the longest path between the node and a leaf node. this count includes the node itself, so the height of a leaf node will be 1. */ static inline unsigned short b_btree_height(b_btree_node *node) { return node->b_height; } BLUE_API int b_btree_iterator_begin(const b_btree *tree, b_btree_iterator *it); BLUE_API bool b_btree_iterator_next(b_btree_iterator *it); BLUE_API b_status b_btree_iterator_erase(b_btree_iterator *it); BLUE_API bool b_btree_iterator_is_valid(const b_btree_iterator *it); #ifdef __cplusplus } #endif #endif