rbtree3 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +492 -0
- data/LICENSE +22 -0
- data/README +106 -0
- data/dict.c +1216 -0
- data/dict.h +123 -0
- data/extconf.rb +13 -0
- data/rbtree.c +1701 -0
- data/test.rb +950 -0
- metadata +64 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2002-2004, 2007, 2009 OZAWA Takuma
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= Ruby/RBTree
|
4
|
+
|
5
|
+
RBTree is a sorted associative collection that is implemented with
|
6
|
+
Red-Black Tree. The elements of RBTree are ordered and its interface
|
7
|
+
is the almost same as Hash, so simply you can consider RBTree sorted
|
8
|
+
Hash.
|
9
|
+
|
10
|
+
Red-Black Tree is a kind of binary tree that automatically balances
|
11
|
+
by itself when a node is inserted or deleted. Thus the complexity
|
12
|
+
for insert, search and delete is O(log N) in expected and worst
|
13
|
+
case. On the other hand the complexity of Hash is O(1). Because
|
14
|
+
Hash is unordered the data structure is more effective than
|
15
|
+
Red-Black Tree as an associative collection.
|
16
|
+
|
17
|
+
The elements of RBTree are sorted with natural ordering (by <=>
|
18
|
+
method) of its keys or by a comparator(Proc) set by readjust
|
19
|
+
method. It means all keys in RBTree should be comparable with each
|
20
|
+
other. Or a comparator that takes two arguments of a key should return
|
21
|
+
negative, 0, or positive depending on the first argument is less than,
|
22
|
+
equal to, or greater than the second one.
|
23
|
+
|
24
|
+
The interface of RBTree is the almost same as Hash and there are a
|
25
|
+
few methods to take advantage of the ordering:
|
26
|
+
|
27
|
+
* lower_bound, upper_bound, bound
|
28
|
+
* first, last
|
29
|
+
* shift, pop
|
30
|
+
* reverse_each
|
31
|
+
|
32
|
+
Note: while iterating RBTree (e.g. in a block of each method), it is
|
33
|
+
not modifiable, or TypeError is thrown.
|
34
|
+
|
35
|
+
RBTree supoorts pretty printing using pp.
|
36
|
+
|
37
|
+
This library contains two classes. One is RBTree and the other is
|
38
|
+
MultiRBTree that is a parent class of RBTree. RBTree does not allow
|
39
|
+
duplications of keys but MultiRBTree does.
|
40
|
+
|
41
|
+
require "rbtree"
|
42
|
+
|
43
|
+
rbtree = RBTree["c", 10, "a", 20]
|
44
|
+
rbtree["b"] = 30
|
45
|
+
p rbtree["b"] # => 30
|
46
|
+
rbtree.each do |k, v|
|
47
|
+
p [k, v]
|
48
|
+
end # => ["a", 20] ["b", 30] ["c", 10]
|
49
|
+
|
50
|
+
mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40]
|
51
|
+
p mrbtree.lower_bound("b") # => ["c", 10]
|
52
|
+
mrbtree.bound("a", "d") do |k, v|
|
53
|
+
p [k, v]
|
54
|
+
end # => ["a", 20] ["a", 40] ["c", 10]
|
55
|
+
|
56
|
+
== Requirement
|
57
|
+
|
58
|
+
* Ruby 1.8.x
|
59
|
+
|
60
|
+
== Install
|
61
|
+
|
62
|
+
$ sudo gem install rbtree
|
63
|
+
|
64
|
+
or download a tarball from the link below
|
65
|
+
|
66
|
+
* ((<"Ruby/RBTree 0.2.1"|URL:rbtree-0.2.1.tar.gz>))
|
67
|
+
|
68
|
+
and then
|
69
|
+
|
70
|
+
$ tar xzf rbtree-x.x.x.tar.gz
|
71
|
+
$ cd rbtree-x.x.x.tar.gz
|
72
|
+
$ ruby extconf.rb
|
73
|
+
$ make
|
74
|
+
$ sudo make site-install
|
75
|
+
|
76
|
+
== Test
|
77
|
+
|
78
|
+
$ ruby test.rb
|
79
|
+
|
80
|
+
== Incomplete Documents
|
81
|
+
|
82
|
+
$ rdoc rbtree.c
|
83
|
+
|
84
|
+
or online documents at ((<URL:http://rbtree.rubyforge.org/>)).
|
85
|
+
|
86
|
+
== License
|
87
|
+
|
88
|
+
MIT License. Copyright (c) 2002-2004, 2007, 2009 OZAWA Takuma.
|
89
|
+
|
90
|
+
dict.c and dict.h are modified copies that are originally in Kazlib
|
91
|
+
written by Kaz Kylheku. Copyright is held by Kaz Kylheku, see dict.c
|
92
|
+
and dict.h for the license. The web page of Kazlib is at
|
93
|
+
((<URL:http://users.footprints.net/~kaz/kazlib.html>)).
|
94
|
+
|
95
|
+
== Support
|
96
|
+
|
97
|
+
Bug fixes, suggestions and other feedbacks are welcomed. Please mail
|
98
|
+
me at burningdowntheopera at yahoo dot co dot jp.
|
99
|
+
|
100
|
+
== Links
|
101
|
+
|
102
|
+
* ((<RAA - ruby-rbtree|URL:http://raa.ruby-lang.org/project/ruby-rbtree/>))
|
103
|
+
* ((<RubyForge: rbtree: Project Info|URL:http://rubyforge.org/projects/rbtree/>))
|
104
|
+
* ((<URL:http://www.geocities.co.jp/SiliconValley-PaloAlto/3388/rbtree/README.html>))
|
105
|
+
|
106
|
+
=end
|
data/dict.c
ADDED
@@ -0,0 +1,1216 @@
|
|
1
|
+
/*
|
2
|
+
* Dictionary Abstract Data Type
|
3
|
+
* Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
|
4
|
+
*
|
5
|
+
* Free Software License:
|
6
|
+
*
|
7
|
+
* All rights are reserved by the author, with the following exceptions:
|
8
|
+
* Permission is granted to freely reproduce and distribute this software,
|
9
|
+
* possibly in exchange for a fee, provided that this copyright notice appears
|
10
|
+
* intact. Permission is also granted to adapt this software to produce
|
11
|
+
* derivative works, as long as the modified versions carry this copyright
|
12
|
+
* notice and additional notices stating that the work has been modified.
|
13
|
+
* This source code may be translated into executable form and incorporated
|
14
|
+
* into proprietary software; there is no requirement for such software to
|
15
|
+
* contain a copyright notice related to this source.
|
16
|
+
*
|
17
|
+
* $Id: dict.c,v 1.15 2005/10/06 05:16:35 kuma Exp $
|
18
|
+
* $Name: $
|
19
|
+
*/
|
20
|
+
|
21
|
+
/*
|
22
|
+
* Modified for Ruby/RBTree by OZAWA Takuma.
|
23
|
+
*/
|
24
|
+
|
25
|
+
#include <stdlib.h>
|
26
|
+
#include <stddef.h>
|
27
|
+
#include <assert.h>
|
28
|
+
#include "dict.h"
|
29
|
+
|
30
|
+
#include <ruby.h>
|
31
|
+
|
32
|
+
#ifdef KAZLIB_RCSID
|
33
|
+
static const char rcsid[] = "$Id: dict.c,v 1.15 2005/10/06 05:16:35 kuma Exp $";
|
34
|
+
#endif
|
35
|
+
|
36
|
+
/*
|
37
|
+
* These macros provide short convenient names for structure members,
|
38
|
+
* which are embellished with dict_ prefixes so that they are
|
39
|
+
* properly confined to the documented namespace. It's legal for a
|
40
|
+
* program which uses dict to define, for instance, a macro called ``parent''.
|
41
|
+
* Such a macro would interfere with the dnode_t struct definition.
|
42
|
+
* In general, highly portable and reusable C modules which expose their
|
43
|
+
* structures need to confine structure member names to well-defined spaces.
|
44
|
+
* The resulting identifiers aren't necessarily convenient to use, nor
|
45
|
+
* readable, in the implementation, however!
|
46
|
+
*/
|
47
|
+
|
48
|
+
#define left dict_left
|
49
|
+
#define right dict_right
|
50
|
+
#define parent dict_parent
|
51
|
+
#define color dict_color
|
52
|
+
#define key dict_key
|
53
|
+
#define data dict_data
|
54
|
+
|
55
|
+
#define nilnode dict_nilnode
|
56
|
+
#define nodecount dict_nodecount
|
57
|
+
#define compare dict_compare
|
58
|
+
#define allocnode dict_allocnode
|
59
|
+
#define freenode dict_freenode
|
60
|
+
#define context dict_context
|
61
|
+
#define dupes dict_dupes
|
62
|
+
|
63
|
+
#define dictptr dict_dictptr
|
64
|
+
|
65
|
+
#define dict_root(D) ((D)->nilnode.left)
|
66
|
+
#define dict_nil(D) (&(D)->nilnode)
|
67
|
+
#define DICT_DEPTH_MAX 64
|
68
|
+
|
69
|
+
#define COMPARE(dict, key1, key2) dict->compare(key1, key2, dict->context)
|
70
|
+
|
71
|
+
static dnode_t *dnode_alloc(void *context);
|
72
|
+
static void dnode_free(dnode_t *node, void *context);
|
73
|
+
|
74
|
+
/*
|
75
|
+
* Perform a ``left rotation'' adjustment on the tree. The given node P and
|
76
|
+
* its right child C are rearranged so that the P instead becomes the left
|
77
|
+
* child of C. The left subtree of C is inherited as the new right subtree
|
78
|
+
* for P. The ordering of the keys within the tree is thus preserved.
|
79
|
+
*/
|
80
|
+
|
81
|
+
static void rotate_left(dnode_t *upper)
|
82
|
+
{
|
83
|
+
dnode_t *lower, *lowleft, *upparent;
|
84
|
+
|
85
|
+
lower = upper->right;
|
86
|
+
upper->right = lowleft = lower->left;
|
87
|
+
lowleft->parent = upper;
|
88
|
+
|
89
|
+
lower->parent = upparent = upper->parent;
|
90
|
+
|
91
|
+
/* don't need to check for root node here because root->parent is
|
92
|
+
the sentinel nil node, and root->parent->left points back to root */
|
93
|
+
|
94
|
+
if (upper == upparent->left) {
|
95
|
+
upparent->left = lower;
|
96
|
+
} else {
|
97
|
+
assert (upper == upparent->right);
|
98
|
+
upparent->right = lower;
|
99
|
+
}
|
100
|
+
|
101
|
+
lower->left = upper;
|
102
|
+
upper->parent = lower;
|
103
|
+
}
|
104
|
+
|
105
|
+
/*
|
106
|
+
* This operation is the ``mirror'' image of rotate_left. It is
|
107
|
+
* the same procedure, but with left and right interchanged.
|
108
|
+
*/
|
109
|
+
|
110
|
+
static void rotate_right(dnode_t *upper)
|
111
|
+
{
|
112
|
+
dnode_t *lower, *lowright, *upparent;
|
113
|
+
|
114
|
+
lower = upper->left;
|
115
|
+
upper->left = lowright = lower->right;
|
116
|
+
lowright->parent = upper;
|
117
|
+
|
118
|
+
lower->parent = upparent = upper->parent;
|
119
|
+
|
120
|
+
if (upper == upparent->right) {
|
121
|
+
upparent->right = lower;
|
122
|
+
} else {
|
123
|
+
assert (upper == upparent->left);
|
124
|
+
upparent->left = lower;
|
125
|
+
}
|
126
|
+
|
127
|
+
lower->right = upper;
|
128
|
+
upper->parent = lower;
|
129
|
+
}
|
130
|
+
|
131
|
+
/*
|
132
|
+
* Do a postorder traversal of the tree rooted at the specified
|
133
|
+
* node and free everything under it. Used by dict_free().
|
134
|
+
*/
|
135
|
+
|
136
|
+
static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
|
137
|
+
{
|
138
|
+
if (node == nil)
|
139
|
+
return;
|
140
|
+
free_nodes(dict, node->left, nil);
|
141
|
+
free_nodes(dict, node->right, nil);
|
142
|
+
dict->freenode(node, dict->context);
|
143
|
+
}
|
144
|
+
|
145
|
+
/*
|
146
|
+
* This procedure performs a verification that the given subtree is a binary
|
147
|
+
* search tree. It performs an inorder traversal of the tree using the
|
148
|
+
* dict_next() successor function, verifying that the key of each node is
|
149
|
+
* strictly lower than that of its successor, if duplicates are not allowed,
|
150
|
+
* or lower or equal if duplicates are allowed. This function is used for
|
151
|
+
* debugging purposes.
|
152
|
+
*/
|
153
|
+
|
154
|
+
static int verify_bintree(dict_t *dict)
|
155
|
+
{
|
156
|
+
dnode_t *first, *next;
|
157
|
+
|
158
|
+
first = dict_first(dict);
|
159
|
+
|
160
|
+
if (dict->dupes) {
|
161
|
+
while (first && (next = dict_next(dict, first))) {
|
162
|
+
if (COMPARE(dict, first->key, next->key) > 0)
|
163
|
+
return 0;
|
164
|
+
first = next;
|
165
|
+
}
|
166
|
+
} else {
|
167
|
+
while (first && (next = dict_next(dict, first))) {
|
168
|
+
if (COMPARE(dict, first->key, next->key) >= 0)
|
169
|
+
return 0;
|
170
|
+
first = next;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
return 1;
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
/*
|
178
|
+
* This function recursively verifies that the given binary subtree satisfies
|
179
|
+
* three of the red black properties. It checks that every red node has only
|
180
|
+
* black children. It makes sure that each node is either red or black. And it
|
181
|
+
* checks that every path has the same count of black nodes from root to leaf.
|
182
|
+
* It returns the blackheight of the given subtree; this allows blackheights to
|
183
|
+
* be computed recursively and compared for left and right siblings for
|
184
|
+
* mismatches. It does not check for every nil node being black, because there
|
185
|
+
* is only one sentinel nil node. The return value of this function is the
|
186
|
+
* black height of the subtree rooted at the node ``root'', or zero if the
|
187
|
+
* subtree is not red-black.
|
188
|
+
*/
|
189
|
+
|
190
|
+
static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
|
191
|
+
{
|
192
|
+
unsigned height_left, height_right;
|
193
|
+
|
194
|
+
if (root != nil) {
|
195
|
+
height_left = verify_redblack(nil, root->left);
|
196
|
+
height_right = verify_redblack(nil, root->right);
|
197
|
+
if (height_left == 0 || height_right == 0)
|
198
|
+
return 0;
|
199
|
+
if (height_left != height_right)
|
200
|
+
return 0;
|
201
|
+
if (root->color == dnode_red) {
|
202
|
+
if (root->left->color != dnode_black)
|
203
|
+
return 0;
|
204
|
+
if (root->right->color != dnode_black)
|
205
|
+
return 0;
|
206
|
+
return height_left;
|
207
|
+
}
|
208
|
+
if (root->color != dnode_black)
|
209
|
+
return 0;
|
210
|
+
return height_left + 1;
|
211
|
+
}
|
212
|
+
return 1;
|
213
|
+
}
|
214
|
+
|
215
|
+
/*
|
216
|
+
* Compute the actual count of nodes by traversing the tree and
|
217
|
+
* return it. This could be compared against the stored count to
|
218
|
+
* detect a mismatch.
|
219
|
+
*/
|
220
|
+
|
221
|
+
static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
|
222
|
+
{
|
223
|
+
if (root == nil)
|
224
|
+
return 0;
|
225
|
+
else
|
226
|
+
return 1 + verify_node_count(nil, root->left)
|
227
|
+
+ verify_node_count(nil, root->right);
|
228
|
+
}
|
229
|
+
|
230
|
+
/*
|
231
|
+
* Verify that the tree contains the given node. This is done by
|
232
|
+
* traversing all of the nodes and comparing their pointers to the
|
233
|
+
* given pointer. Returns 1 if the node is found, otherwise
|
234
|
+
* returns zero. It is intended for debugging purposes.
|
235
|
+
*/
|
236
|
+
|
237
|
+
static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
|
238
|
+
{
|
239
|
+
if (root != nil) {
|
240
|
+
return root == node
|
241
|
+
|| verify_dict_has_node(nil, root->left, node)
|
242
|
+
|| verify_dict_has_node(nil, root->right, node);
|
243
|
+
}
|
244
|
+
return 0;
|
245
|
+
}
|
246
|
+
|
247
|
+
|
248
|
+
/*
|
249
|
+
* Dynamically allocate and initialize a dictionary object.
|
250
|
+
*/
|
251
|
+
|
252
|
+
dict_t *dict_create(dict_comp_t comp)
|
253
|
+
{
|
254
|
+
dict_t* new = ALLOC(dict_t);
|
255
|
+
|
256
|
+
if (new) {
|
257
|
+
new->compare = comp;
|
258
|
+
new->allocnode = dnode_alloc;
|
259
|
+
new->freenode = dnode_free;
|
260
|
+
new->context = NULL;
|
261
|
+
new->nodecount = 0;
|
262
|
+
new->nilnode.left = &new->nilnode;
|
263
|
+
new->nilnode.right = &new->nilnode;
|
264
|
+
new->nilnode.parent = &new->nilnode;
|
265
|
+
new->nilnode.color = dnode_black;
|
266
|
+
new->dupes = 0;
|
267
|
+
}
|
268
|
+
return new;
|
269
|
+
}
|
270
|
+
|
271
|
+
/*
|
272
|
+
* Select a different set of node allocator routines.
|
273
|
+
*/
|
274
|
+
|
275
|
+
void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
|
276
|
+
dnode_free_t fr, void *context)
|
277
|
+
{
|
278
|
+
assert (dict_count(dict) == 0);
|
279
|
+
assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
|
280
|
+
|
281
|
+
dict->allocnode = al ? al : dnode_alloc;
|
282
|
+
dict->freenode = fr ? fr : dnode_free;
|
283
|
+
dict->context = context;
|
284
|
+
}
|
285
|
+
|
286
|
+
/*
|
287
|
+
* Free a dynamically allocated dictionary object. Removing the nodes
|
288
|
+
* from the tree before deleting it is required.
|
289
|
+
*/
|
290
|
+
|
291
|
+
void dict_destroy(dict_t *dict)
|
292
|
+
{
|
293
|
+
assert (dict_isempty(dict));
|
294
|
+
xfree(dict);
|
295
|
+
}
|
296
|
+
|
297
|
+
/*
|
298
|
+
* Free all the nodes in the dictionary by using the dictionary's
|
299
|
+
* installed free routine. The dictionary is emptied.
|
300
|
+
*/
|
301
|
+
|
302
|
+
void dict_free_nodes(dict_t *dict)
|
303
|
+
{
|
304
|
+
dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
|
305
|
+
free_nodes(dict, root, nil);
|
306
|
+
dict->nodecount = 0;
|
307
|
+
dict->nilnode.left = &dict->nilnode;
|
308
|
+
dict->nilnode.right = &dict->nilnode;
|
309
|
+
dict->nilnode.parent = &dict->nilnode;
|
310
|
+
}
|
311
|
+
|
312
|
+
/*
|
313
|
+
* Obsolescent function, equivalent to dict_free_nodes
|
314
|
+
*/
|
315
|
+
|
316
|
+
void dict_free(dict_t *dict)
|
317
|
+
{
|
318
|
+
#ifdef KAZLIB_OBSOLESCENT_DEBUG
|
319
|
+
assert ("call to obsolescent function dict_free()" && 0);
|
320
|
+
#endif
|
321
|
+
dict_free_nodes(dict);
|
322
|
+
}
|
323
|
+
|
324
|
+
/*
|
325
|
+
* Initialize a user-supplied dictionary object.
|
326
|
+
*/
|
327
|
+
|
328
|
+
dict_t *dict_init(dict_t *dict, dict_comp_t comp)
|
329
|
+
{
|
330
|
+
dict->compare = comp;
|
331
|
+
dict->allocnode = dnode_alloc;
|
332
|
+
dict->freenode = dnode_free;
|
333
|
+
dict->context = NULL;
|
334
|
+
dict->nodecount = 0;
|
335
|
+
dict->nilnode.left = &dict->nilnode;
|
336
|
+
dict->nilnode.right = &dict->nilnode;
|
337
|
+
dict->nilnode.parent = &dict->nilnode;
|
338
|
+
dict->nilnode.color = dnode_black;
|
339
|
+
dict->dupes = 0;
|
340
|
+
return dict;
|
341
|
+
}
|
342
|
+
|
343
|
+
/*
|
344
|
+
* Initialize a dictionary in the likeness of another dictionary
|
345
|
+
*/
|
346
|
+
|
347
|
+
void dict_init_like(dict_t *dict, const dict_t *template)
|
348
|
+
{
|
349
|
+
dict->compare = template->compare;
|
350
|
+
dict->allocnode = template->allocnode;
|
351
|
+
dict->freenode = template->freenode;
|
352
|
+
dict->context = template->context;
|
353
|
+
dict->nodecount = 0;
|
354
|
+
dict->nilnode.left = &dict->nilnode;
|
355
|
+
dict->nilnode.right = &dict->nilnode;
|
356
|
+
dict->nilnode.parent = &dict->nilnode;
|
357
|
+
dict->nilnode.color = dnode_black;
|
358
|
+
dict->dupes = template->dupes;
|
359
|
+
|
360
|
+
assert (dict_similar(dict, template));
|
361
|
+
}
|
362
|
+
|
363
|
+
/*
|
364
|
+
* Remove all nodes from the dictionary (without freeing them in any way).
|
365
|
+
*/
|
366
|
+
|
367
|
+
static void dict_clear(dict_t *dict)
|
368
|
+
{
|
369
|
+
dict->nodecount = 0;
|
370
|
+
dict->nilnode.left = &dict->nilnode;
|
371
|
+
dict->nilnode.right = &dict->nilnode;
|
372
|
+
dict->nilnode.parent = &dict->nilnode;
|
373
|
+
assert (dict->nilnode.color == dnode_black);
|
374
|
+
}
|
375
|
+
|
376
|
+
/*
|
377
|
+
* Verify the integrity of the dictionary structure. This is provided for
|
378
|
+
* debugging purposes, and should be placed in assert statements. Just because
|
379
|
+
* this function succeeds doesn't mean that the tree is not corrupt. Certain
|
380
|
+
* corruptions in the tree may simply cause undefined behavior.
|
381
|
+
*/
|
382
|
+
|
383
|
+
int dict_verify(dict_t *dict)
|
384
|
+
{
|
385
|
+
dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
|
386
|
+
|
387
|
+
/* check that the sentinel node and root node are black */
|
388
|
+
if (root->color != dnode_black)
|
389
|
+
return 0;
|
390
|
+
if (nil->color != dnode_black)
|
391
|
+
return 0;
|
392
|
+
if (nil->right != nil)
|
393
|
+
return 0;
|
394
|
+
/* nil->left is the root node; check that its parent pointer is nil */
|
395
|
+
if (nil->left->parent != nil)
|
396
|
+
return 0;
|
397
|
+
/* perform a weak test that the tree is a binary search tree */
|
398
|
+
if (!verify_bintree(dict))
|
399
|
+
return 0;
|
400
|
+
/* verify that the tree is a red-black tree */
|
401
|
+
if (!verify_redblack(nil, root))
|
402
|
+
return 0;
|
403
|
+
if (verify_node_count(nil, root) != dict_count(dict))
|
404
|
+
return 0;
|
405
|
+
return 1;
|
406
|
+
}
|
407
|
+
|
408
|
+
/*
|
409
|
+
* Determine whether two dictionaries are similar: have the same comparison and
|
410
|
+
* allocator functions, and same status as to whether duplicates are allowed.
|
411
|
+
*/
|
412
|
+
|
413
|
+
int dict_similar(const dict_t *left, const dict_t *right)
|
414
|
+
{
|
415
|
+
if (left->compare != right->compare)
|
416
|
+
return 0;
|
417
|
+
|
418
|
+
if (left->allocnode != right->allocnode)
|
419
|
+
return 0;
|
420
|
+
|
421
|
+
if (left->freenode != right->freenode)
|
422
|
+
return 0;
|
423
|
+
|
424
|
+
if (left->context != right->context)
|
425
|
+
return 0;
|
426
|
+
|
427
|
+
/* if (left->dupes != right->dupes) */
|
428
|
+
/* return 0; */
|
429
|
+
|
430
|
+
return 1;
|
431
|
+
}
|
432
|
+
|
433
|
+
/*
|
434
|
+
* Locate a node in the dictionary having the given key.
|
435
|
+
* If the node is not found, a null a pointer is returned (rather than
|
436
|
+
* a pointer that dictionary's nil sentinel node), otherwise a pointer to the
|
437
|
+
* located node is returned.
|
438
|
+
*/
|
439
|
+
|
440
|
+
dnode_t *dict_lookup(dict_t *dict, const void *key)
|
441
|
+
{
|
442
|
+
dnode_t *root = dict_root(dict);
|
443
|
+
dnode_t *nil = dict_nil(dict);
|
444
|
+
dnode_t *saved;
|
445
|
+
int result;
|
446
|
+
|
447
|
+
/* simple binary search adapted for trees that contain duplicate keys */
|
448
|
+
|
449
|
+
while (root != nil) {
|
450
|
+
result = COMPARE(dict, key, root->key);
|
451
|
+
if (result < 0)
|
452
|
+
root = root->left;
|
453
|
+
else if (result > 0)
|
454
|
+
root = root->right;
|
455
|
+
else {
|
456
|
+
if (!dict->dupes) { /* no duplicates, return match */
|
457
|
+
return root;
|
458
|
+
} else { /* could be dupes, find leftmost one */
|
459
|
+
do {
|
460
|
+
saved = root;
|
461
|
+
root = root->left;
|
462
|
+
while (root != nil && COMPARE(dict, key, root->key))
|
463
|
+
root = root->right;
|
464
|
+
} while (root != nil);
|
465
|
+
return saved;
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
470
|
+
return NULL;
|
471
|
+
}
|
472
|
+
|
473
|
+
/*
|
474
|
+
* Look for the node corresponding to the lowest key that is equal to or
|
475
|
+
* greater than the given key. If there is no such node, return null.
|
476
|
+
*/
|
477
|
+
|
478
|
+
dnode_t *dict_lower_bound(dict_t *dict, const void *key)
|
479
|
+
{
|
480
|
+
dnode_t *root = dict_root(dict);
|
481
|
+
dnode_t *nil = dict_nil(dict);
|
482
|
+
dnode_t *tentative = 0;
|
483
|
+
|
484
|
+
while (root != nil) {
|
485
|
+
int result = COMPARE(dict, key, root->key);
|
486
|
+
|
487
|
+
if (result > 0) {
|
488
|
+
root = root->right;
|
489
|
+
} else if (result < 0) {
|
490
|
+
tentative = root;
|
491
|
+
root = root->left;
|
492
|
+
} else {
|
493
|
+
if (!dict->dupes) {
|
494
|
+
return root;
|
495
|
+
} else {
|
496
|
+
tentative = root;
|
497
|
+
root = root->left;
|
498
|
+
}
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
return tentative;
|
503
|
+
}
|
504
|
+
|
505
|
+
/*
|
506
|
+
* Look for the node corresponding to the greatest key that is equal to or
|
507
|
+
* lower than the given key. If there is no such node, return null.
|
508
|
+
*/
|
509
|
+
|
510
|
+
dnode_t *dict_upper_bound(dict_t *dict, const void *key)
|
511
|
+
{
|
512
|
+
dnode_t *root = dict_root(dict);
|
513
|
+
dnode_t *nil = dict_nil(dict);
|
514
|
+
dnode_t *tentative = 0;
|
515
|
+
|
516
|
+
while (root != nil) {
|
517
|
+
int result = COMPARE(dict, key, root->key);
|
518
|
+
|
519
|
+
if (result < 0) {
|
520
|
+
root = root->left;
|
521
|
+
} else if (result > 0) {
|
522
|
+
tentative = root;
|
523
|
+
root = root->right;
|
524
|
+
} else {
|
525
|
+
if (!dict->dupes) {
|
526
|
+
return root;
|
527
|
+
} else {
|
528
|
+
tentative = root;
|
529
|
+
root = root->right;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
return tentative;
|
535
|
+
}
|
536
|
+
|
537
|
+
/*
|
538
|
+
* Insert a node into the dictionary. The node should have been
|
539
|
+
* initialized with a data field. All other fields are ignored.
|
540
|
+
* The behavior is undefined if the user attempts to insert into
|
541
|
+
* a dictionary that is already full (for which the dict_isfull()
|
542
|
+
* function returns true).
|
543
|
+
*/
|
544
|
+
|
545
|
+
int dict_insert(dict_t *dict, dnode_t *node, const void *key)
|
546
|
+
{
|
547
|
+
dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
|
548
|
+
dnode_t *parent = nil, *uncle, *grandpa;
|
549
|
+
int result = -1;
|
550
|
+
|
551
|
+
node->key = key;
|
552
|
+
|
553
|
+
assert (!dict_isfull(dict));
|
554
|
+
assert (!dict_contains(dict, node));
|
555
|
+
assert (!dnode_is_in_a_dict(node));
|
556
|
+
|
557
|
+
/* basic binary tree insert */
|
558
|
+
|
559
|
+
while (where != nil) {
|
560
|
+
parent = where;
|
561
|
+
result = COMPARE(dict, key, where->key);
|
562
|
+
/* trap attempts at duplicate key insertion unless it's explicitly allowed */
|
563
|
+
|
564
|
+
if (!dict->dupes && result == 0) {
|
565
|
+
where->data = node->data;
|
566
|
+
return 0;
|
567
|
+
} else if (result < 0) {
|
568
|
+
where = where->left;
|
569
|
+
} else {
|
570
|
+
where = where->right;
|
571
|
+
}
|
572
|
+
}
|
573
|
+
|
574
|
+
assert (where == nil);
|
575
|
+
|
576
|
+
if (result < 0)
|
577
|
+
parent->left = node;
|
578
|
+
else
|
579
|
+
parent->right = node;
|
580
|
+
|
581
|
+
node->parent = parent;
|
582
|
+
node->left = nil;
|
583
|
+
node->right = nil;
|
584
|
+
|
585
|
+
dict->nodecount++;
|
586
|
+
|
587
|
+
/* red black adjustments */
|
588
|
+
|
589
|
+
node->color = dnode_red;
|
590
|
+
|
591
|
+
while (parent->color == dnode_red) {
|
592
|
+
grandpa = parent->parent;
|
593
|
+
if (parent == grandpa->left) {
|
594
|
+
uncle = grandpa->right;
|
595
|
+
if (uncle->color == dnode_red) { /* red parent, red uncle */
|
596
|
+
parent->color = dnode_black;
|
597
|
+
uncle->color = dnode_black;
|
598
|
+
grandpa->color = dnode_red;
|
599
|
+
node = grandpa;
|
600
|
+
parent = grandpa->parent;
|
601
|
+
} else { /* red parent, black uncle */
|
602
|
+
if (node == parent->right) {
|
603
|
+
rotate_left(parent);
|
604
|
+
parent = node;
|
605
|
+
assert (grandpa == parent->parent);
|
606
|
+
/* rotation between parent and child preserves grandpa */
|
607
|
+
}
|
608
|
+
parent->color = dnode_black;
|
609
|
+
grandpa->color = dnode_red;
|
610
|
+
rotate_right(grandpa);
|
611
|
+
break;
|
612
|
+
}
|
613
|
+
} else { /* symmetric cases: parent == parent->parent->right */
|
614
|
+
uncle = grandpa->left;
|
615
|
+
if (uncle->color == dnode_red) {
|
616
|
+
parent->color = dnode_black;
|
617
|
+
uncle->color = dnode_black;
|
618
|
+
grandpa->color = dnode_red;
|
619
|
+
node = grandpa;
|
620
|
+
parent = grandpa->parent;
|
621
|
+
} else {
|
622
|
+
if (node == parent->left) {
|
623
|
+
rotate_right(parent);
|
624
|
+
parent = node;
|
625
|
+
assert (grandpa == parent->parent);
|
626
|
+
}
|
627
|
+
parent->color = dnode_black;
|
628
|
+
grandpa->color = dnode_red;
|
629
|
+
rotate_left(grandpa);
|
630
|
+
break;
|
631
|
+
}
|
632
|
+
}
|
633
|
+
}
|
634
|
+
|
635
|
+
dict_root(dict)->color = dnode_black;
|
636
|
+
|
637
|
+
assert (dict_verify(dict));
|
638
|
+
return 1;
|
639
|
+
}
|
640
|
+
|
641
|
+
/*
|
642
|
+
* Delete the given node from the dictionary. If the given node does not belong
|
643
|
+
* to the given dictionary, undefined behavior results. A pointer to the
|
644
|
+
* deleted node is returned.
|
645
|
+
*/
|
646
|
+
|
647
|
+
dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
|
648
|
+
{
|
649
|
+
dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
|
650
|
+
|
651
|
+
/* basic deletion */
|
652
|
+
|
653
|
+
assert (!dict_isempty(dict));
|
654
|
+
assert (dict_contains(dict, delete));
|
655
|
+
|
656
|
+
/*
|
657
|
+
* If the node being deleted has two children, then we replace it with its
|
658
|
+
* successor (i.e. the leftmost node in the right subtree.) By doing this,
|
659
|
+
* we avoid the traditional algorithm under which the successor's key and
|
660
|
+
* value *only* move to the deleted node and the successor is spliced out
|
661
|
+
* from the tree. We cannot use this approach because the user may hold
|
662
|
+
* pointers to the successor, or nodes may be inextricably tied to some
|
663
|
+
* other structures by way of embedding, etc. So we must splice out the
|
664
|
+
* node we are given, not some other node, and must not move contents from
|
665
|
+
* one node to another behind the user's back.
|
666
|
+
*/
|
667
|
+
|
668
|
+
if (delete->left != nil && delete->right != nil) {
|
669
|
+
dnode_t *next = dict_next(dict, delete);
|
670
|
+
dnode_t *nextparent = next->parent;
|
671
|
+
dnode_color_t nextcolor = next->color;
|
672
|
+
|
673
|
+
assert (next != nil);
|
674
|
+
assert (next->parent != nil);
|
675
|
+
assert (next->left == nil);
|
676
|
+
|
677
|
+
/*
|
678
|
+
* First, splice out the successor from the tree completely, by
|
679
|
+
* moving up its right child into its place.
|
680
|
+
*/
|
681
|
+
|
682
|
+
child = next->right;
|
683
|
+
child->parent = nextparent;
|
684
|
+
|
685
|
+
if (nextparent->left == next) {
|
686
|
+
nextparent->left = child;
|
687
|
+
} else {
|
688
|
+
assert (nextparent->right == next);
|
689
|
+
nextparent->right = child;
|
690
|
+
}
|
691
|
+
|
692
|
+
/*
|
693
|
+
* Now that the successor has been extricated from the tree, install it
|
694
|
+
* in place of the node that we want deleted.
|
695
|
+
*/
|
696
|
+
|
697
|
+
next->parent = delparent;
|
698
|
+
next->left = delete->left;
|
699
|
+
next->right = delete->right;
|
700
|
+
next->left->parent = next;
|
701
|
+
next->right->parent = next;
|
702
|
+
next->color = delete->color;
|
703
|
+
delete->color = nextcolor;
|
704
|
+
|
705
|
+
if (delparent->left == delete) {
|
706
|
+
delparent->left = next;
|
707
|
+
} else {
|
708
|
+
assert (delparent->right == delete);
|
709
|
+
delparent->right = next;
|
710
|
+
}
|
711
|
+
|
712
|
+
} else {
|
713
|
+
assert (delete != nil);
|
714
|
+
assert (delete->left == nil || delete->right == nil);
|
715
|
+
|
716
|
+
child = (delete->left != nil) ? delete->left : delete->right;
|
717
|
+
|
718
|
+
child->parent = delparent = delete->parent;
|
719
|
+
|
720
|
+
if (delete == delparent->left) {
|
721
|
+
delparent->left = child;
|
722
|
+
} else {
|
723
|
+
assert (delete == delparent->right);
|
724
|
+
delparent->right = child;
|
725
|
+
}
|
726
|
+
}
|
727
|
+
|
728
|
+
delete->parent = NULL;
|
729
|
+
delete->right = NULL;
|
730
|
+
delete->left = NULL;
|
731
|
+
|
732
|
+
dict->nodecount--;
|
733
|
+
|
734
|
+
assert (verify_bintree(dict));
|
735
|
+
|
736
|
+
/* red-black adjustments */
|
737
|
+
|
738
|
+
if (delete->color == dnode_black) {
|
739
|
+
dnode_t *parent, *sister;
|
740
|
+
|
741
|
+
dict_root(dict)->color = dnode_red;
|
742
|
+
|
743
|
+
while (child->color == dnode_black) {
|
744
|
+
parent = child->parent;
|
745
|
+
if (child == parent->left) {
|
746
|
+
sister = parent->right;
|
747
|
+
assert (sister != nil);
|
748
|
+
if (sister->color == dnode_red) {
|
749
|
+
sister->color = dnode_black;
|
750
|
+
parent->color = dnode_red;
|
751
|
+
rotate_left(parent);
|
752
|
+
sister = parent->right;
|
753
|
+
assert (sister != nil);
|
754
|
+
}
|
755
|
+
if (sister->left->color == dnode_black
|
756
|
+
&& sister->right->color == dnode_black) {
|
757
|
+
sister->color = dnode_red;
|
758
|
+
child = parent;
|
759
|
+
} else {
|
760
|
+
if (sister->right->color == dnode_black) {
|
761
|
+
assert (sister->left->color == dnode_red);
|
762
|
+
sister->left->color = dnode_black;
|
763
|
+
sister->color = dnode_red;
|
764
|
+
rotate_right(sister);
|
765
|
+
sister = parent->right;
|
766
|
+
assert (sister != nil);
|
767
|
+
}
|
768
|
+
sister->color = parent->color;
|
769
|
+
sister->right->color = dnode_black;
|
770
|
+
parent->color = dnode_black;
|
771
|
+
rotate_left(parent);
|
772
|
+
break;
|
773
|
+
}
|
774
|
+
} else { /* symmetric case: child == child->parent->right */
|
775
|
+
assert (child == parent->right);
|
776
|
+
sister = parent->left;
|
777
|
+
assert (sister != nil);
|
778
|
+
if (sister->color == dnode_red) {
|
779
|
+
sister->color = dnode_black;
|
780
|
+
parent->color = dnode_red;
|
781
|
+
rotate_right(parent);
|
782
|
+
sister = parent->left;
|
783
|
+
assert (sister != nil);
|
784
|
+
}
|
785
|
+
if (sister->right->color == dnode_black
|
786
|
+
&& sister->left->color == dnode_black) {
|
787
|
+
sister->color = dnode_red;
|
788
|
+
child = parent;
|
789
|
+
} else {
|
790
|
+
if (sister->left->color == dnode_black) {
|
791
|
+
assert (sister->right->color == dnode_red);
|
792
|
+
sister->right->color = dnode_black;
|
793
|
+
sister->color = dnode_red;
|
794
|
+
rotate_left(sister);
|
795
|
+
sister = parent->left;
|
796
|
+
assert (sister != nil);
|
797
|
+
}
|
798
|
+
sister->color = parent->color;
|
799
|
+
sister->left->color = dnode_black;
|
800
|
+
parent->color = dnode_black;
|
801
|
+
rotate_right(parent);
|
802
|
+
break;
|
803
|
+
}
|
804
|
+
}
|
805
|
+
}
|
806
|
+
|
807
|
+
child->color = dnode_black;
|
808
|
+
dict_root(dict)->color = dnode_black;
|
809
|
+
}
|
810
|
+
|
811
|
+
assert (dict_verify(dict));
|
812
|
+
|
813
|
+
return delete;
|
814
|
+
}
|
815
|
+
|
816
|
+
/*
|
817
|
+
* Allocate a node using the dictionary's allocator routine, give it
|
818
|
+
* the data item.
|
819
|
+
*/
|
820
|
+
|
821
|
+
int dict_alloc_insert(dict_t *dict, const void *key, void *data)
|
822
|
+
{
|
823
|
+
dnode_t *node = dict->allocnode(dict->context);
|
824
|
+
|
825
|
+
if (node) {
|
826
|
+
dnode_init(node, data);
|
827
|
+
if (!dict_insert(dict, node, key))
|
828
|
+
dict->freenode(node, dict->context);
|
829
|
+
return 1;
|
830
|
+
}
|
831
|
+
return 0;
|
832
|
+
}
|
833
|
+
|
834
|
+
void dict_delete_free(dict_t *dict, dnode_t *node)
|
835
|
+
{
|
836
|
+
dict_delete(dict, node);
|
837
|
+
dict->freenode(node, dict->context);
|
838
|
+
}
|
839
|
+
|
840
|
+
/*
|
841
|
+
* Return the node with the lowest (leftmost) key. If the dictionary is empty
|
842
|
+
* (that is, dict_isempty(dict) returns 1) a null pointer is returned.
|
843
|
+
*/
|
844
|
+
|
845
|
+
dnode_t *dict_first(dict_t *dict)
|
846
|
+
{
|
847
|
+
dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
|
848
|
+
|
849
|
+
if (root != nil)
|
850
|
+
while ((left = root->left) != nil)
|
851
|
+
root = left;
|
852
|
+
|
853
|
+
return (root == nil) ? NULL : root;
|
854
|
+
}
|
855
|
+
|
856
|
+
/*
|
857
|
+
* Return the node with the highest (rightmost) key. If the dictionary is empty
|
858
|
+
* (that is, dict_isempty(dict) returns 1) a null pointer is returned.
|
859
|
+
*/
|
860
|
+
|
861
|
+
dnode_t *dict_last(dict_t *dict)
|
862
|
+
{
|
863
|
+
dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
|
864
|
+
|
865
|
+
if (root != nil)
|
866
|
+
while ((right = root->right) != nil)
|
867
|
+
root = right;
|
868
|
+
|
869
|
+
return (root == nil) ? NULL : root;
|
870
|
+
}
|
871
|
+
|
872
|
+
/*
|
873
|
+
* Return the given node's successor node---the node which has the
|
874
|
+
* next key in the the left to right ordering. If the node has
|
875
|
+
* no successor, a null pointer is returned rather than a pointer to
|
876
|
+
* the nil node.
|
877
|
+
*/
|
878
|
+
|
879
|
+
dnode_t *dict_next(dict_t *dict, dnode_t *curr)
|
880
|
+
{
|
881
|
+
dnode_t *nil = dict_nil(dict), *parent, *left;
|
882
|
+
|
883
|
+
if (curr->right != nil) {
|
884
|
+
curr = curr->right;
|
885
|
+
while ((left = curr->left) != nil)
|
886
|
+
curr = left;
|
887
|
+
return curr;
|
888
|
+
}
|
889
|
+
|
890
|
+
parent = curr->parent;
|
891
|
+
|
892
|
+
while (parent != nil && curr == parent->right) {
|
893
|
+
curr = parent;
|
894
|
+
parent = curr->parent;
|
895
|
+
}
|
896
|
+
|
897
|
+
return (parent == nil) ? NULL : parent;
|
898
|
+
}
|
899
|
+
|
900
|
+
/*
|
901
|
+
* Return the given node's predecessor, in the key order.
|
902
|
+
* The nil sentinel node is returned if there is no predecessor.
|
903
|
+
*/
|
904
|
+
|
905
|
+
dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
|
906
|
+
{
|
907
|
+
dnode_t *nil = dict_nil(dict), *parent, *right;
|
908
|
+
|
909
|
+
if (curr->left != nil) {
|
910
|
+
curr = curr->left;
|
911
|
+
while ((right = curr->right) != nil)
|
912
|
+
curr = right;
|
913
|
+
return curr;
|
914
|
+
}
|
915
|
+
|
916
|
+
parent = curr->parent;
|
917
|
+
|
918
|
+
while (parent != nil && curr == parent->left) {
|
919
|
+
curr = parent;
|
920
|
+
parent = curr->parent;
|
921
|
+
}
|
922
|
+
|
923
|
+
return (parent == nil) ? NULL : parent;
|
924
|
+
}
|
925
|
+
|
926
|
+
void dict_allow_dupes(dict_t *dict)
|
927
|
+
{
|
928
|
+
dict->dupes = 1;
|
929
|
+
}
|
930
|
+
|
931
|
+
dictcount_t dict_count(dict_t *dict)
|
932
|
+
{
|
933
|
+
return dict->nodecount;
|
934
|
+
}
|
935
|
+
|
936
|
+
int dict_isempty(dict_t *dict)
|
937
|
+
{
|
938
|
+
return dict->nodecount == 0;
|
939
|
+
}
|
940
|
+
|
941
|
+
int dict_isfull(dict_t *dict)
|
942
|
+
{
|
943
|
+
return dict->nodecount == DICTCOUNT_T_MAX;
|
944
|
+
}
|
945
|
+
|
946
|
+
int dict_contains(dict_t *dict, dnode_t *node)
|
947
|
+
{
|
948
|
+
return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
|
949
|
+
}
|
950
|
+
|
951
|
+
static dnode_t *dnode_alloc(void *context)
|
952
|
+
{
|
953
|
+
return malloc(sizeof *dnode_alloc(NULL));
|
954
|
+
}
|
955
|
+
|
956
|
+
static void dnode_free(dnode_t *node, void *context)
|
957
|
+
{
|
958
|
+
free(node);
|
959
|
+
}
|
960
|
+
|
961
|
+
dnode_t *dnode_create(void *data)
|
962
|
+
{
|
963
|
+
dnode_t *new = malloc(sizeof *new);
|
964
|
+
if (new) {
|
965
|
+
new->data = data;
|
966
|
+
new->parent = NULL;
|
967
|
+
new->left = NULL;
|
968
|
+
new->right = NULL;
|
969
|
+
}
|
970
|
+
return new;
|
971
|
+
}
|
972
|
+
|
973
|
+
dnode_t *dnode_init(dnode_t *dnode, void *data)
|
974
|
+
{
|
975
|
+
dnode->data = data;
|
976
|
+
dnode->parent = NULL;
|
977
|
+
dnode->left = NULL;
|
978
|
+
dnode->right = NULL;
|
979
|
+
return dnode;
|
980
|
+
}
|
981
|
+
|
982
|
+
void dnode_destroy(dnode_t *dnode)
|
983
|
+
{
|
984
|
+
assert (!dnode_is_in_a_dict(dnode));
|
985
|
+
free(dnode);
|
986
|
+
}
|
987
|
+
|
988
|
+
void *dnode_get(dnode_t *dnode)
|
989
|
+
{
|
990
|
+
return dnode->data;
|
991
|
+
}
|
992
|
+
|
993
|
+
const void *dnode_getkey(dnode_t *dnode)
|
994
|
+
{
|
995
|
+
return dnode->key;
|
996
|
+
}
|
997
|
+
|
998
|
+
void dnode_put(dnode_t *dnode, void *data)
|
999
|
+
{
|
1000
|
+
dnode->data = data;
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
int dnode_is_in_a_dict(dnode_t *dnode)
|
1004
|
+
{
|
1005
|
+
return (dnode->parent && dnode->left && dnode->right);
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
void dict_process(dict_t *dict, void *context, dnode_process_t function)
|
1009
|
+
{
|
1010
|
+
dnode_t *node = dict_first(dict), *next;
|
1011
|
+
|
1012
|
+
while (node != NULL) {
|
1013
|
+
/* check for callback function deleting */
|
1014
|
+
/* the next node from under us */
|
1015
|
+
assert (dict_contains(dict, node));
|
1016
|
+
next = dict_next(dict, node);
|
1017
|
+
function(dict, node, context);
|
1018
|
+
node = next;
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
static void load_begin_internal(dict_load_t *load, dict_t *dict)
|
1023
|
+
{
|
1024
|
+
load->dictptr = dict;
|
1025
|
+
load->nilnode.left = &load->nilnode;
|
1026
|
+
load->nilnode.right = &load->nilnode;
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
void dict_load_begin(dict_load_t *load, dict_t *dict)
|
1030
|
+
{
|
1031
|
+
assert (dict_isempty(dict));
|
1032
|
+
load_begin_internal(load, dict);
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
|
1036
|
+
{
|
1037
|
+
dict_t *dict = load->dictptr;
|
1038
|
+
dnode_t *nil = &load->nilnode;
|
1039
|
+
|
1040
|
+
assert (!dnode_is_in_a_dict(newnode));
|
1041
|
+
assert (dict->nodecount < DICTCOUNT_T_MAX);
|
1042
|
+
|
1043
|
+
#ifndef NDEBUG
|
1044
|
+
if (dict->nodecount > 0) {
|
1045
|
+
if (dict->dupes)
|
1046
|
+
assert (COMPARE(dict, nil->left->key, key) <= 0);
|
1047
|
+
else
|
1048
|
+
assert (COMPARE(dict, nil->left->key, key) < 0);
|
1049
|
+
}
|
1050
|
+
#endif
|
1051
|
+
|
1052
|
+
newnode->key = key;
|
1053
|
+
nil->right->left = newnode;
|
1054
|
+
nil->right = newnode;
|
1055
|
+
newnode->left = nil;
|
1056
|
+
dict->nodecount++;
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
void dict_load_end(dict_load_t *load)
|
1060
|
+
{
|
1061
|
+
dict_t *dict = load->dictptr;
|
1062
|
+
dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
|
1063
|
+
dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
|
1064
|
+
dnode_t *complete = 0;
|
1065
|
+
dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
|
1066
|
+
dictcount_t botrowcount;
|
1067
|
+
unsigned baselevel = 0, level = 0, i;
|
1068
|
+
|
1069
|
+
assert (dnode_red == 0 && dnode_black == 1);
|
1070
|
+
|
1071
|
+
while (fullcount >= nodecount && fullcount)
|
1072
|
+
fullcount >>= 1;
|
1073
|
+
|
1074
|
+
botrowcount = nodecount - fullcount;
|
1075
|
+
|
1076
|
+
for (curr = loadnil->left; curr != loadnil; curr = next) {
|
1077
|
+
next = curr->left;
|
1078
|
+
|
1079
|
+
if (complete == NULL && botrowcount-- == 0) {
|
1080
|
+
assert (baselevel == 0);
|
1081
|
+
assert (level == 0);
|
1082
|
+
baselevel = level = 1;
|
1083
|
+
complete = tree[0];
|
1084
|
+
|
1085
|
+
if (complete != 0) {
|
1086
|
+
tree[0] = 0;
|
1087
|
+
complete->right = dictnil;
|
1088
|
+
while (tree[level] != 0) {
|
1089
|
+
tree[level]->right = complete;
|
1090
|
+
complete->parent = tree[level];
|
1091
|
+
complete = tree[level];
|
1092
|
+
tree[level++] = 0;
|
1093
|
+
}
|
1094
|
+
}
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
if (complete == NULL) {
|
1098
|
+
curr->left = dictnil;
|
1099
|
+
curr->right = dictnil;
|
1100
|
+
curr->color = level % 2;
|
1101
|
+
complete = curr;
|
1102
|
+
|
1103
|
+
assert (level == baselevel);
|
1104
|
+
while (tree[level] != 0) {
|
1105
|
+
tree[level]->right = complete;
|
1106
|
+
complete->parent = tree[level];
|
1107
|
+
complete = tree[level];
|
1108
|
+
tree[level++] = 0;
|
1109
|
+
}
|
1110
|
+
} else {
|
1111
|
+
curr->left = complete;
|
1112
|
+
curr->color = (level + 1) % 2;
|
1113
|
+
complete->parent = curr;
|
1114
|
+
tree[level] = curr;
|
1115
|
+
complete = 0;
|
1116
|
+
level = baselevel;
|
1117
|
+
}
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
if (complete == NULL)
|
1121
|
+
complete = dictnil;
|
1122
|
+
|
1123
|
+
for (i = 0; i < DICT_DEPTH_MAX; i++) {
|
1124
|
+
if (tree[i] != 0) {
|
1125
|
+
tree[i]->right = complete;
|
1126
|
+
complete->parent = tree[i];
|
1127
|
+
complete = tree[i];
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
dictnil->color = dnode_black;
|
1132
|
+
dictnil->right = dictnil;
|
1133
|
+
complete->parent = dictnil;
|
1134
|
+
complete->color = dnode_black;
|
1135
|
+
dict_root(dict) = complete;
|
1136
|
+
|
1137
|
+
assert (dict_verify(dict));
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
void dict_merge(dict_t *dest, dict_t *source)
|
1141
|
+
{
|
1142
|
+
dict_load_t load;
|
1143
|
+
dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
|
1144
|
+
|
1145
|
+
assert (dict_similar(dest, source));
|
1146
|
+
|
1147
|
+
if (source == dest)
|
1148
|
+
return;
|
1149
|
+
|
1150
|
+
dest->nodecount = 0;
|
1151
|
+
load_begin_internal(&load, dest);
|
1152
|
+
|
1153
|
+
for (;;) {
|
1154
|
+
if (leftnode != NULL && rightnode != NULL) {
|
1155
|
+
if (COMPARE(dest, leftnode->key, rightnode->key) < 0)
|
1156
|
+
goto copyleft;
|
1157
|
+
else
|
1158
|
+
goto copyright;
|
1159
|
+
} else if (leftnode != NULL) {
|
1160
|
+
goto copyleft;
|
1161
|
+
} else if (rightnode != NULL) {
|
1162
|
+
goto copyright;
|
1163
|
+
} else {
|
1164
|
+
assert (leftnode == NULL && rightnode == NULL);
|
1165
|
+
break;
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
copyleft:
|
1169
|
+
{
|
1170
|
+
dnode_t *next = dict_next(dest, leftnode);
|
1171
|
+
#ifndef NDEBUG
|
1172
|
+
leftnode->left = NULL; /* suppress assertion in dict_load_next */
|
1173
|
+
#endif
|
1174
|
+
dict_load_next(&load, leftnode, leftnode->key);
|
1175
|
+
leftnode = next;
|
1176
|
+
continue;
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
copyright:
|
1180
|
+
{
|
1181
|
+
dnode_t *next = dict_next(source, rightnode);
|
1182
|
+
#ifndef NDEBUG
|
1183
|
+
rightnode->left = NULL;
|
1184
|
+
#endif
|
1185
|
+
dict_load_next(&load, rightnode, rightnode->key);
|
1186
|
+
rightnode = next;
|
1187
|
+
continue;
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
dict_clear(source);
|
1192
|
+
dict_load_end(&load);
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
int dict_equal(dict_t* dict1, dict_t* dict2,
|
1196
|
+
dict_value_eql_t value_eql)
|
1197
|
+
{
|
1198
|
+
dnode_t* node1;
|
1199
|
+
dnode_t* node2;
|
1200
|
+
|
1201
|
+
if (dict_count(dict1) != dict_count(dict2))
|
1202
|
+
return 0;
|
1203
|
+
if (!dict_similar(dict1, dict2))
|
1204
|
+
return 0;
|
1205
|
+
|
1206
|
+
for (node1 = dict_first(dict1), node2 = dict_first(dict2);
|
1207
|
+
node1 != NULL && node2 != NULL;
|
1208
|
+
node1 = dict_next(dict1, node1), node2 = dict_next(dict2, node2)) {
|
1209
|
+
|
1210
|
+
if (COMPARE(dict1, node1->key, node2->key) != 0)
|
1211
|
+
return 0;
|
1212
|
+
if (!value_eql(node1->data, node2->data))
|
1213
|
+
return 0;
|
1214
|
+
}
|
1215
|
+
return 1;
|
1216
|
+
}
|