e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information.
fd37f52011-04-25Martin Stjernholm || $Id$
e576bb2002-10-11Martin Nilsson */
1b10db2002-10-08Martin Nilsson 
c550c22001-04-30Martin Stjernholm /* An implementation of a threaded red/black balanced binary tree. * * Created 2001-04-27 by Martin Stjernholm */ #ifndef RBTREE_H #define RBTREE_H
eed89d2001-12-10Martin Stjernholm /* #define RB_STATS */
8814842001-05-01Martin Stjernholm #include "array.h"
c550c22001-04-30Martin Stjernholm /* A red/black tree is a binary tree with one extra bit of info in * each node - the color of it. The following properties holds: * * o Every node is either red or black. * o A NULL leaf is considered black. * o If a node is red, its children must be black. * o Every path from a node down to all its leafs have the same * number of black nodes.
eed89d2001-12-10Martin Stjernholm  * o The root node is always black (by convention).
c550c22001-04-30Martin Stjernholm  *
eed89d2001-12-10Martin Stjernholm  * The longest possible path in a given tree thus has alternating red * and black nodes, and the shortest possible path in it has only
c550c22001-04-30Martin Stjernholm  * black nodes. Therefore it's guaranteed that the longest path is at
eed89d2001-12-10Martin Stjernholm  * most twice as long as the shortest one. That ensures O(log n) steps * to follow the path down to any node in any tree of size n.
c550c22001-04-30Martin Stjernholm  */
eed89d2001-12-10Martin Stjernholm struct rb_node_hdr {
c550c22001-04-30Martin Stjernholm  struct rb_node_hdr *prev, *next;
eed89d2001-12-10Martin Stjernholm  unsigned INT16 flags; /* Only the top three bits are used; * may be overlaid. */
c550c22001-04-30Martin Stjernholm }; #define RB_RED 0x2000 #define RB_THREAD_PREV 0x4000 #define RB_THREAD_NEXT 0x8000 #define RB_FLAG_MASK 0xe000 /* The thread flags indicate whether the prev/next pointers are thread * pointers. A thread pointer is used whenever the pointer would
eed89d2001-12-10Martin Stjernholm  * otherwise be NULL, and it points to the next smaller/bigger * element. More specifically, the next thread pointer points to the * closest parent node whose prev pointer subtree contains it, and * vice versa for the prev thread pointer:
c550c22001-04-30Martin Stjernholm  * * p <. .> p * / . . \ * / . . \ * a . . a * / \ . . / \ * \ . . / * b . . b * / \ . <- next prev -> . / \ * ... . thread pointer . ... * \ . . / * c . . c * / \.. ../ \ */
eed89d2001-12-10Martin Stjernholm #define keep_flags(node, code) do { \
7e877a2003-04-02Martin Stjernholm  int kept_flags_ = (node)->flags; \
eed89d2001-12-10Martin Stjernholm  {code;} \ (node)->flags = \ ((node)->flags & ~RB_FLAG_MASK) | (kept_flags_ & RB_FLAG_MASK); \ } while (0) PMOD_EXPORT struct rb_node_hdr *rb_first (struct rb_node_hdr *root); PMOD_EXPORT struct rb_node_hdr *rb_last (struct rb_node_hdr *root); PMOD_EXPORT struct rb_node_hdr *rb_link_prev (struct rb_node_hdr *node); PMOD_EXPORT struct rb_node_hdr *rb_link_next (struct rb_node_hdr *node); #define rb_prev(node) \ (DO_IF_RB_STATS (rb_num_sidesteps++ COMMA) \ (node)->flags & RB_THREAD_PREV ? \ DO_IF_RB_STATS (rb_num_sidestep_ops++ COMMA) (node)->prev : \ rb_link_prev (node)) #define rb_next(node) \ (DO_IF_RB_STATS (rb_num_sidesteps++ COMMA) \ (node)->flags & RB_THREAD_NEXT ? \ DO_IF_RB_STATS (rb_num_sidestep_ops++ COMMA) (node)->next : \ rb_link_next (node))
8814842001-05-01Martin Stjernholm  #ifdef PIKE_DEBUG /* To get good type checking. */
8cfc022002-12-22Martin Stjernholm static INLINE struct rb_node_hdr *rb_node_check (struct rb_node_hdr *node)
eed89d2001-12-10Martin Stjernholm  {return node;}
8814842001-05-01Martin Stjernholm #else
eed89d2001-12-10Martin Stjernholm #define rb_node_check(node) ((struct rb_node_hdr *) (node))
8814842001-05-01Martin Stjernholm #endif
eed89d2001-12-10Martin Stjernholm typedef int rb_find_fn (void *key, struct rb_node_hdr *node); typedef int rb_cmp_fn (struct rb_node_hdr *a, struct rb_node_hdr *b, void *extra); typedef int rb_equal_fn (struct rb_node_hdr *a, struct rb_node_hdr *b, void *extra); typedef struct rb_node_hdr *rb_copy_fn (struct rb_node_hdr *node, void *extra); typedef void rb_free_fn (struct rb_node_hdr *node, void *extra);
8814842001-05-01Martin Stjernholm 
c550c22001-04-30Martin Stjernholm /* Operations: * * insert: * Adds a new entry only if one with the same index doesn't exist
eed89d2001-12-10Martin Stjernholm  * already, replaces it otherwise. If there are several entries * with the same index, the last one of them is replaced. Returns * the added or replaced node.
c550c22001-04-30Martin Stjernholm  * * add: * Adds a new entry, even if one with the same index already
eed89d2001-12-10Martin Stjernholm  * exists. The entry is added after all other entries with the * same index. Returns the newly created node.
c550c22001-04-30Martin Stjernholm  * * add_after:
eed89d2001-12-10Martin Stjernholm  * Adds a new entry after the given one. Give NULL to add at * front. Returns the newly created node. Note that it's a linear * search to get the right entry among several with the same * index.
c550c22001-04-30Martin Stjernholm  * * delete:
eed89d2001-12-10Martin Stjernholm  * Deletes an entry with the specified index, if one exists. If * there are several entries with the specified index, the last * one is deleted. Returns nonzero if a node was deleted, zero * otherwise.
c550c22001-04-30Martin Stjernholm  * * delete_node: * Deletes the given node from the tree. Useful to get the right * entry when several have the same index. The node is assumed to * exist in the tree. Note that it's a linear search to get the
eed89d2001-12-10Martin Stjernholm  * right entry among several with the same index.
c550c22001-04-30Martin Stjernholm  * * find_eq:
eed89d2001-12-10Martin Stjernholm  * Returns the last entry which has the given index, or zero if * none exists.
c550c22001-04-30Martin Stjernholm  * * find_lt, find_gt, find_le, find_ge: * find_lt and find_le returns the biggest entry which satisfy the * condition, and vice versa for the other two. This means that * e.g. rb_next when used on the returned node from find_le never * returns an entry with the same index. *
eed89d2001-12-10Martin Stjernholm  * get_nth: * Returns the nth entry, counting from the beginning. Note that * this is a linear operation. *
c550c22001-04-30Martin Stjernholm  * All destructive operations might change the tree root. */
eed89d2001-12-10Martin Stjernholm struct rb_node_hdr *rb_insert (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key,
98945e2008-06-29Martin Nilsson  struct rb_node_hdr *new_node);
eed89d2001-12-10Martin Stjernholm void rb_add (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key,
98945e2008-06-29Martin Nilsson  struct rb_node_hdr *new_node);
eed89d2001-12-10Martin Stjernholm void rb_add_after (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key,
98945e2008-06-29Martin Nilsson  struct rb_node_hdr *new_node,
eed89d2001-12-10Martin Stjernholm  struct rb_node_hdr *existing); struct rb_node_hdr *rb_remove (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key); void rb_remove_node (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key, struct rb_node_hdr *node); struct rb_node_hdr *rb_remove_with_move (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key, size_t node_size, rb_free_fn *cleanup_fn, void *cleanup_fn_extra); struct rb_node_hdr *rb_remove_node_with_move (struct rb_node_hdr **root, rb_find_fn *find_fn, void *key, struct rb_node_hdr *node, size_t node_size); struct rb_node_hdr *rb_find_eq (struct rb_node_hdr *root, rb_find_fn *find_fn, void *key); struct rb_node_hdr *rb_find_lt (struct rb_node_hdr *root, rb_find_fn *find_fn, void *key); struct rb_node_hdr *rb_find_gt (struct rb_node_hdr *root, rb_find_fn *find_fn, void *key); struct rb_node_hdr *rb_find_le (struct rb_node_hdr *root, rb_find_fn *find_fn, void *key); struct rb_node_hdr *rb_find_ge (struct rb_node_hdr *root, rb_find_fn *find_fn, void *key); struct rb_node_hdr *rb_get_nth (struct rb_node_hdr *root, size_t n); size_t rb_sizeof (struct rb_node_hdr *root); void rb_free (struct rb_node_hdr *root, rb_free_fn *free_node_fn, void *extra); int rb_equal (struct rb_node_hdr *a, struct rb_node_hdr *b, rb_equal_fn *node_equal_fn, void *extra); struct rb_node_hdr *rb_copy (struct rb_node_hdr *source, rb_copy_fn *copy_node_fn, void *extra); struct rb_node_hdr *rb_make_list (struct rb_node_hdr *tree); struct rb_node_hdr *rb_make_tree (struct rb_node_hdr *list, size_t length); #define PIKE_MERGE_DESTR_A 0x2000 #define PIKE_MERGE_DESTR_B 0x1000 enum rb_merge_trees {MERGE_TREE_A, MERGE_TREE_B, MERGE_TREE_RES}; typedef struct rb_node_hdr *rb_merge_copy_fn (struct rb_node_hdr *node, void *extra, enum rb_merge_trees tree); typedef void rb_merge_free_fn (struct rb_node_hdr *node, void *extra, enum rb_merge_trees tree); struct rb_node_hdr *rb_linear_merge ( struct rb_node_hdr *a, struct rb_node_hdr *b, int operation, rb_cmp_fn *cmp_fn, void *cmp_fn_extra, rb_merge_copy_fn *copy_node_fn, void *copy_fn_extra, rb_merge_free_fn *free_node_fn, void *free_fn_extra, size_t *length); #ifdef RB_STATS extern size_t rb_num_sidesteps, rb_num_sidestep_ops; extern size_t rb_num_finds, rb_find_depth; extern size_t rb_num_tracks, rb_track_depth; extern size_t rb_num_sidetracks, rb_num_sidetrack_ops; extern size_t rb_max_depth; extern size_t rb_num_traverses, rb_num_traverse_ops; extern size_t rbstack_slice_allocs; extern size_t rb_num_adds, rb_add_rebalance_cnt; extern size_t rb_num_deletes, rb_del_rebalance_cnt; void reset_rb_stats(); void print_rb_stats (int reset); #define DO_IF_RB_STATS(X) X #else #define DO_IF_RB_STATS(X)
c550c22001-04-30Martin Stjernholm #endif
eed89d2001-12-10Martin Stjernholm #endif /* RBTREE_H */