rbtree-pure 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/rbtree-pure.gemspec +67 -0
- metadata +5 -7
- data/old_ext/dict.c +0 -1216
- data/old_ext/dict.h +0 -123
- data/old_ext/rbtree.c +0 -1706
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/rbtree-pure.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rbtree-pure}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{Victor Costan}]
|
12
|
+
s.date = %q{2011-07-27}
|
13
|
+
s.description = %q{This is a pure-ruby implementation of the rbtree gem.}
|
14
|
+
s.email = %q{victor@costan.us}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".project",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"lib/rbtree.rb",
|
29
|
+
"lib/rbtree/guard_node.rb",
|
30
|
+
"lib/rbtree/multi_rb_tree.rb",
|
31
|
+
"lib/rbtree/node.rb",
|
32
|
+
"lib/rbtree/rb_tree.rb",
|
33
|
+
"lib/rbtree/tree.rb",
|
34
|
+
"lib/rbtree/tree_cmp.rb",
|
35
|
+
"rbtree-pure.gemspec",
|
36
|
+
"test/helper.rb",
|
37
|
+
"test/multi_rbtree_test.rb",
|
38
|
+
"test/rbtree_test.rb"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/pwnall/rbtree-pure}
|
41
|
+
s.licenses = [%q{MIT}]
|
42
|
+
s.require_paths = [%q{lib}]
|
43
|
+
s.rubygems_version = %q{1.8.5}
|
44
|
+
s.summary = %q{Pure-ruby implementation of red-black trees.}
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
|
52
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
56
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
57
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
58
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
63
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbtree-pure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Victor Costan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-27 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
@@ -102,9 +102,7 @@ files:
|
|
102
102
|
- lib/rbtree/rb_tree.rb
|
103
103
|
- lib/rbtree/tree.rb
|
104
104
|
- lib/rbtree/tree_cmp.rb
|
105
|
-
-
|
106
|
-
- old_ext/dict.h
|
107
|
-
- old_ext/rbtree.c
|
105
|
+
- rbtree-pure.gemspec
|
108
106
|
- test/helper.rb
|
109
107
|
- test/multi_rbtree_test.rb
|
110
108
|
- test/rbtree_test.rb
|
data/old_ext/dict.c
DELETED
@@ -1,1216 +0,0 @@
|
|
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
|
-
}
|