File: rbtree.h

package info (click to toggle)
pike8.0 8.0.702-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 79,608 kB
  • sloc: ansic: 266,508; xml: 186,324; makefile: 3,537; sh: 1,731; cpp: 1,328; lisp: 655; awk: 441; asm: 242; objc: 240; pascal: 157; perl: 34; sed: 34
file content (235 lines) | stat: -rw-r--r-- 8,974 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
|| 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.
*/

/* An implementation of a threaded red/black balanced binary tree.
 *
 * Created 2001-04-27 by Martin Stjernholm
 */

#ifndef RBTREE_H
#define RBTREE_H

/* #define RB_STATS */

#include "array.h"

/* 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.
 * o  The root node is always black (by convention).
 *
 * The longest possible path in a given tree thus has alternating red
 * and black nodes, and the shortest possible path in it has only
 * black nodes. Therefore it's guaranteed that the longest path is at
 * 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.
 */

struct rb_node_hdr
{
  struct rb_node_hdr *prev, *next;
  unsigned INT16 flags;		/* Only the top three bits are used;
				 * may be overlaid. */
};

#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
 * 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:
 *
 * 		 p <.                                  .> p
 * 		/    .                                .    \
 * 	       /      .                              .      \
 * 	      a        .                            .        a
 * 	     / \        .                          .        / \
 * 		\        .                        .        /
 * 		 b        .                      .        b
 * 		/ \       . <- next      prev -> .       / \
 * 		  ...     .    thread pointer    .     ...
 * 		    \     .                      .     /
 * 		     c   .                        .   c
 * 		    / \..                          ../ \
 */

#define keep_flags(node, code) do {					\
    int kept_flags_ = (node)->flags;					\
    {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))

#ifdef PIKE_DEBUG
/* To get good type checking. */
static INLINE struct rb_node_hdr ATTRIBUTE((unused)) *rb_node_check (struct rb_node_hdr *node)
  {return node;}
#else
#define rb_node_check(node) ((struct rb_node_hdr *) (node))
#endif

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);

/* Operations:
 *
 * insert:
 *     Adds a new entry only if one with the same index doesn't exist
 *     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.
 *
 * add:
 *     Adds a new entry, even if one with the same index already
 *     exists. The entry is added after all other entries with the
 *     same index. Returns the newly created node.
 *
 * add_after:
 *     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.
 *
 * delete:
 *     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.
 *
 * 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
 *     right entry among several with the same index.
 *
 * find_eq:
 *     Returns the last entry which has the given index, or zero if
 *     none exists.
 *
 * 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.
 *
 * get_nth:
 *     Returns the nth entry, counting from the beginning. Note that
 *     this is a linear operation.
 *
 * All destructive operations might change the tree root.
 */

struct rb_node_hdr *rb_insert (struct rb_node_hdr **root,
			       rb_find_fn *find_fn, void *key,
			       struct rb_node_hdr *new_node);
void rb_add (struct rb_node_hdr **root,
	     rb_find_fn *find_fn, void *key,
	     struct rb_node_hdr *new_node);
void rb_add_after (struct rb_node_hdr **root,
		   rb_find_fn *find_fn, void *key,
		   struct rb_node_hdr *new_node,
		   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);
void print_rb_stats (int reset);
#define DO_IF_RB_STATS(X) X
#else
#define DO_IF_RB_STATS(X)
#endif

#endif	/* RBTREE_H */