rbtree 0.3.0 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/MANIFEST +0 -1
- data/README +38 -71
- data/dict.c +364 -83
- data/dict.h +30 -6
- data/extconf.rb +13 -2
- data/rbtree.c +772 -482
- data/test.rb +309 -182
- metadata +42 -45
- data/ChangeLog +0 -505
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '068088a72443fb756ebedf00226f9e628552528fdb6a02a904bd984a9ab961b5'
|
4
|
+
data.tar.gz: 58c816a9433efa6680e7469db60810b6c9754949463143787bcc0979ad54a86a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 562b5482ebab8b47f3357e01f76abaa2f480c76a0316033704e783441b90234b4bb0933165204f421592efcf9c0376255c33fb14ce31cb96e82cb61b045ecafd
|
7
|
+
data.tar.gz: 81ff68b66a15597981ffdcecab5b1c49db8f73aa8b93e8b5f354d0072bd28282a4bce7fd0cacc90649006c9cc41c800abc03131b60bdae5c3b5ab3f783ea620c
|
data/LICENSE
CHANGED
data/MANIFEST
CHANGED
data/README
CHANGED
@@ -1,42 +1,37 @@
|
|
1
|
-
=begin
|
2
|
-
|
3
1
|
= Ruby/RBTree
|
4
2
|
|
5
|
-
|
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.
|
3
|
+
== Description
|
9
4
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Hash is unordered the data structure is more effective than
|
15
|
-
Red-Black Tree as an associative collection.
|
5
|
+
A RBTree is a sorted associative collection that is implemented with a
|
6
|
+
Red-Black Tree. It maps keys to values like a Hash, but maintains its
|
7
|
+
elements in ascending key order. The interface is the almost identical
|
8
|
+
to that of Hash.
|
16
9
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
A Red-Black Tree is a kind of binary tree that automatically balances
|
11
|
+
by itself when a node is inserted or deleted. Lookup, insertion, and
|
12
|
+
deletion are performed in O(log N) time in the expected and worst
|
13
|
+
cases. On the other hand, the average case complexity of
|
14
|
+
lookup/insertion/deletion on a Hash is constant time. A Hash is
|
15
|
+
usually faster than a RBTree where ordering is unimportant.
|
23
16
|
|
24
|
-
The
|
25
|
-
|
17
|
+
The elements of a RBTree are sorted using the <=> method of their keys
|
18
|
+
or a Proc set by the readjust method. It means all keys should be
|
19
|
+
comparable with each other or a Proc that takes two keys should return
|
20
|
+
a negative integer, 0, or a positive integer as the first argument is
|
21
|
+
less than, equal to, or greater than the second one.
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
* shift, pop
|
30
|
-
* reverse_each
|
23
|
+
RBTree also provides a few additional methods to take advantage of the
|
24
|
+
ordering:
|
31
25
|
|
32
|
-
|
33
|
-
|
26
|
+
* lower_bound, upper_bound, bound
|
27
|
+
* first, last
|
28
|
+
* shift, pop
|
29
|
+
* reverse_each
|
34
30
|
|
35
|
-
|
31
|
+
== Example
|
36
32
|
|
37
|
-
|
38
|
-
|
39
|
-
duplications of keys but MultiRBTree does.
|
33
|
+
A RBTree cannot contain duplicate keys. Use MultiRBTree that is the
|
34
|
+
parent class of RBTree to store duplicate keys.
|
40
35
|
|
41
36
|
require "rbtree"
|
42
37
|
|
@@ -46,61 +41,33 @@ duplications of keys but MultiRBTree does.
|
|
46
41
|
rbtree.each do |k, v|
|
47
42
|
p [k, v]
|
48
43
|
end # => ["a", 20] ["b", 30] ["c", 10]
|
49
|
-
|
44
|
+
|
50
45
|
mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40]
|
51
46
|
p mrbtree.lower_bound("b") # => ["c", 10]
|
52
47
|
mrbtree.bound("a", "d") do |k, v|
|
53
48
|
p [k, v]
|
54
49
|
end # => ["a", 20] ["a", 40] ["c", 10]
|
55
50
|
|
56
|
-
|
51
|
+
Note: a RBTree cannot be modified during iteration.
|
57
52
|
|
58
|
-
|
53
|
+
== Installation
|
59
54
|
|
60
|
-
|
55
|
+
Run the following command.
|
61
56
|
|
62
57
|
$ sudo gem install rbtree
|
63
58
|
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
59
|
+
== Changes
|
60
|
+
=== 0.4.4
|
61
|
+
* Remove the rb_safe_level warning on Ruby 2.7.
|
79
62
|
|
80
|
-
|
81
|
-
|
82
|
-
$ rdoc rbtree.c
|
83
|
-
|
84
|
-
or online documents at ((<URL:http://rbtree.rubyforge.org/>)).
|
63
|
+
=== 0.4.3
|
64
|
+
* Quick bug fixes for Ruby 3.
|
85
65
|
|
86
66
|
== License
|
87
67
|
|
88
|
-
MIT License. Copyright (c) 2002-
|
68
|
+
MIT License. Copyright (c) 2002-2013 OZAWA Takuma.
|
89
69
|
|
90
70
|
dict.c and dict.h are modified copies that are originally in Kazlib
|
91
|
-
written by Kaz Kylheku.
|
92
|
-
and dict.h for the
|
93
|
-
|
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
|
71
|
+
1.20 written by Kaz Kylheku. Its license is similar to the MIT
|
72
|
+
license. See dict.c and dict.h for the details. The web page of Kazlib
|
73
|
+
is at http://www.kylheku.com/~kaz/kazlib.html.
|
data/dict.c
CHANGED
@@ -14,23 +14,22 @@
|
|
14
14
|
* into proprietary software; there is no requirement for such software to
|
15
15
|
* contain a copyright notice related to this source.
|
16
16
|
*
|
17
|
-
* $Id: dict.c,v 1.
|
18
|
-
* $Name:
|
17
|
+
* $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $
|
18
|
+
* $Name: kazlib_1_20 $
|
19
19
|
*/
|
20
20
|
|
21
21
|
/*
|
22
|
-
* Modified for Ruby/RBTree
|
22
|
+
* Modified for Ruby/RBTree.
|
23
23
|
*/
|
24
24
|
|
25
25
|
#include <stdlib.h>
|
26
26
|
#include <stddef.h>
|
27
27
|
#include <assert.h>
|
28
|
+
#define DICT_IMPLEMENTATION
|
28
29
|
#include "dict.h"
|
29
30
|
|
30
|
-
#include <ruby.h>
|
31
|
-
|
32
31
|
#ifdef KAZLIB_RCSID
|
33
|
-
static const char rcsid[] = "$Id: dict.c,v 1.
|
32
|
+
static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $";
|
34
33
|
#endif
|
35
34
|
|
36
35
|
/*
|
@@ -66,8 +65,6 @@ static const char rcsid[] = "$Id: dict.c,v 1.15 2005/10/06 05:16:35 kuma Exp $";
|
|
66
65
|
#define dict_nil(D) (&(D)->nilnode)
|
67
66
|
#define DICT_DEPTH_MAX 64
|
68
67
|
|
69
|
-
#define COMPARE(dict, key1, key2) dict->compare(key1, key2, dict->context)
|
70
|
-
|
71
68
|
static dnode_t *dnode_alloc(void *context);
|
72
69
|
static void dnode_free(dnode_t *node, void *context);
|
73
70
|
|
@@ -158,17 +155,17 @@ static int verify_bintree(dict_t *dict)
|
|
158
155
|
first = dict_first(dict);
|
159
156
|
|
160
157
|
if (dict->dupes) {
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
158
|
+
while (first && (next = dict_next(dict, first))) {
|
159
|
+
if (dict->compare(first->key, next->key, dict->context) > 0)
|
160
|
+
return 0;
|
161
|
+
first = next;
|
162
|
+
}
|
166
163
|
} else {
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
164
|
+
while (first && (next = dict_next(dict, first))) {
|
165
|
+
if (dict->compare(first->key, next->key, dict->context) >= 0)
|
166
|
+
return 0;
|
167
|
+
first = next;
|
168
|
+
}
|
172
169
|
}
|
173
170
|
return 1;
|
174
171
|
}
|
@@ -251,8 +248,8 @@ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
|
|
251
248
|
|
252
249
|
dict_t *dict_create(dict_comp_t comp)
|
253
250
|
{
|
254
|
-
dict_t*
|
255
|
-
|
251
|
+
dict_t *new = malloc(sizeof *new);
|
252
|
+
|
256
253
|
if (new) {
|
257
254
|
new->compare = comp;
|
258
255
|
new->allocnode = dnode_alloc;
|
@@ -263,7 +260,7 @@ dict_t *dict_create(dict_comp_t comp)
|
|
263
260
|
new->nilnode.right = &new->nilnode;
|
264
261
|
new->nilnode.parent = &new->nilnode;
|
265
262
|
new->nilnode.color = dnode_black;
|
266
|
-
|
263
|
+
new->dupes = 0;
|
267
264
|
}
|
268
265
|
return new;
|
269
266
|
}
|
@@ -291,7 +288,7 @@ void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
|
|
291
288
|
void dict_destroy(dict_t *dict)
|
292
289
|
{
|
293
290
|
assert (dict_isempty(dict));
|
294
|
-
|
291
|
+
free(dict);
|
295
292
|
}
|
296
293
|
|
297
294
|
/*
|
@@ -424,9 +421,6 @@ int dict_similar(const dict_t *left, const dict_t *right)
|
|
424
421
|
if (left->context != right->context)
|
425
422
|
return 0;
|
426
423
|
|
427
|
-
/* if (left->dupes != right->dupes) */
|
428
|
-
/* return 0; */
|
429
|
-
|
430
424
|
return 1;
|
431
425
|
}
|
432
426
|
|
@@ -447,24 +441,24 @@ dnode_t *dict_lookup(dict_t *dict, const void *key)
|
|
447
441
|
/* simple binary search adapted for trees that contain duplicate keys */
|
448
442
|
|
449
443
|
while (root != nil) {
|
450
|
-
result =
|
444
|
+
result = dict->compare(key, root->key, dict->context);
|
451
445
|
if (result < 0)
|
452
446
|
root = root->left;
|
453
447
|
else if (result > 0)
|
454
448
|
root = root->right;
|
455
449
|
else {
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
450
|
+
if (!dict->dupes) { /* no duplicates, return match */
|
451
|
+
return root;
|
452
|
+
} else { /* could be dupes, find leftmost one */
|
453
|
+
do {
|
454
|
+
saved = root;
|
455
|
+
root = root->left;
|
456
|
+
while (root != nil && dict->compare(key, root->key, dict->context))
|
457
|
+
root = root->right;
|
458
|
+
} while (root != nil);
|
459
|
+
return saved;
|
460
|
+
}
|
461
|
+
}
|
468
462
|
}
|
469
463
|
|
470
464
|
return NULL;
|
@@ -482,21 +476,21 @@ dnode_t *dict_lower_bound(dict_t *dict, const void *key)
|
|
482
476
|
dnode_t *tentative = 0;
|
483
477
|
|
484
478
|
while (root != nil) {
|
485
|
-
int result =
|
486
|
-
|
479
|
+
int result = dict->compare(key, root->key, dict->context);
|
480
|
+
|
487
481
|
if (result > 0) {
|
488
482
|
root = root->right;
|
489
483
|
} else if (result < 0) {
|
490
484
|
tentative = root;
|
491
485
|
root = root->left;
|
492
486
|
} else {
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
487
|
+
if (!dict->dupes) {
|
488
|
+
return root;
|
489
|
+
} else {
|
490
|
+
tentative = root;
|
491
|
+
root = root->left;
|
492
|
+
}
|
493
|
+
}
|
500
494
|
}
|
501
495
|
|
502
496
|
return tentative;
|
@@ -514,7 +508,7 @@ dnode_t *dict_upper_bound(dict_t *dict, const void *key)
|
|
514
508
|
dnode_t *tentative = 0;
|
515
509
|
|
516
510
|
while (root != nil) {
|
517
|
-
int result =
|
511
|
+
int result = dict->compare(key, root->key, dict->context);
|
518
512
|
|
519
513
|
if (result < 0) {
|
520
514
|
root = root->left;
|
@@ -522,13 +516,13 @@ dnode_t *dict_upper_bound(dict_t *dict, const void *key)
|
|
522
516
|
tentative = root;
|
523
517
|
root = root->right;
|
524
518
|
} else {
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
519
|
+
if (!dict->dupes) {
|
520
|
+
return root;
|
521
|
+
} else {
|
522
|
+
tentative = root;
|
523
|
+
root = root->right;
|
524
|
+
}
|
525
|
+
}
|
532
526
|
}
|
533
527
|
|
534
528
|
return tentative;
|
@@ -555,12 +549,10 @@ int dict_insert(dict_t *dict, dnode_t *node, const void *key)
|
|
555
549
|
assert (!dnode_is_in_a_dict(node));
|
556
550
|
|
557
551
|
/* basic binary tree insert */
|
558
|
-
|
552
|
+
|
559
553
|
while (where != nil) {
|
560
554
|
parent = where;
|
561
|
-
result =
|
562
|
-
/* trap attempts at duplicate key insertion unless it's explicitly allowed */
|
563
|
-
|
555
|
+
result = dict->compare(key, where->key, dict->context);
|
564
556
|
if (!dict->dupes && result == 0) {
|
565
557
|
where->data = node->data;
|
566
558
|
return 0;
|
@@ -928,6 +920,13 @@ void dict_allow_dupes(dict_t *dict)
|
|
928
920
|
dict->dupes = 1;
|
929
921
|
}
|
930
922
|
|
923
|
+
#undef dict_count
|
924
|
+
#undef dict_isempty
|
925
|
+
#undef dict_isfull
|
926
|
+
#undef dnode_get
|
927
|
+
#undef dnode_put
|
928
|
+
#undef dnode_getkey
|
929
|
+
|
931
930
|
dictcount_t dict_count(dict_t *dict)
|
932
931
|
{
|
933
932
|
return dict->nodecount;
|
@@ -1036,16 +1035,16 @@ void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
|
|
1036
1035
|
{
|
1037
1036
|
dict_t *dict = load->dictptr;
|
1038
1037
|
dnode_t *nil = &load->nilnode;
|
1039
|
-
|
1038
|
+
|
1040
1039
|
assert (!dnode_is_in_a_dict(newnode));
|
1041
1040
|
assert (dict->nodecount < DICTCOUNT_T_MAX);
|
1042
1041
|
|
1043
1042
|
#ifndef NDEBUG
|
1044
1043
|
if (dict->nodecount > 0) {
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1044
|
+
if (dict->dupes)
|
1045
|
+
assert (dict->compare(nil->left->key, key, dict->context) <= 0);
|
1046
|
+
else
|
1047
|
+
assert (dict->compare(nil->left->key, key, dict->context) < 0);
|
1049
1048
|
}
|
1050
1049
|
#endif
|
1051
1050
|
|
@@ -1152,7 +1151,7 @@ void dict_merge(dict_t *dest, dict_t *source)
|
|
1152
1151
|
|
1153
1152
|
for (;;) {
|
1154
1153
|
if (leftnode != NULL && rightnode != NULL) {
|
1155
|
-
if (
|
1154
|
+
if (dest->compare(leftnode->key, rightnode->key, dest->context) < 0)
|
1156
1155
|
goto copyleft;
|
1157
1156
|
else
|
1158
1157
|
goto copyright;
|
@@ -1192,25 +1191,307 @@ void dict_merge(dict_t *dest, dict_t *source)
|
|
1192
1191
|
dict_load_end(&load);
|
1193
1192
|
}
|
1194
1193
|
|
1195
|
-
|
1196
|
-
|
1194
|
+
#ifdef KAZLIB_TEST_MAIN
|
1195
|
+
|
1196
|
+
#include <stdio.h>
|
1197
|
+
#include <string.h>
|
1198
|
+
#include <ctype.h>
|
1199
|
+
#include <stdarg.h>
|
1200
|
+
|
1201
|
+
typedef char input_t[256];
|
1202
|
+
|
1203
|
+
static int tokenize(char *string, ...)
|
1204
|
+
{
|
1205
|
+
char **tokptr;
|
1206
|
+
va_list arglist;
|
1207
|
+
int tokcount = 0;
|
1208
|
+
|
1209
|
+
va_start(arglist, string);
|
1210
|
+
tokptr = va_arg(arglist, char **);
|
1211
|
+
while (tokptr) {
|
1212
|
+
while (*string && isspace((unsigned char) *string))
|
1213
|
+
string++;
|
1214
|
+
if (!*string)
|
1215
|
+
break;
|
1216
|
+
*tokptr = string;
|
1217
|
+
while (*string && !isspace((unsigned char) *string))
|
1218
|
+
string++;
|
1219
|
+
tokptr = va_arg(arglist, char **);
|
1220
|
+
tokcount++;
|
1221
|
+
if (!*string)
|
1222
|
+
break;
|
1223
|
+
*string++ = 0;
|
1224
|
+
}
|
1225
|
+
va_end(arglist);
|
1226
|
+
|
1227
|
+
return tokcount;
|
1228
|
+
}
|
1229
|
+
|
1230
|
+
static int comparef(const void *key1, const void *key2)
|
1197
1231
|
{
|
1198
|
-
|
1199
|
-
|
1232
|
+
return strcmp(key1, key2);
|
1233
|
+
}
|
1200
1234
|
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1235
|
+
static char *dupstring(char *str)
|
1236
|
+
{
|
1237
|
+
int sz = strlen(str) + 1;
|
1238
|
+
char *new = malloc(sz);
|
1239
|
+
if (new)
|
1240
|
+
memcpy(new, str, sz);
|
1241
|
+
return new;
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
static dnode_t *new_node(void *c)
|
1245
|
+
{
|
1246
|
+
static dnode_t few[5];
|
1247
|
+
static int count;
|
1248
|
+
|
1249
|
+
if (count < 5)
|
1250
|
+
return few + count++;
|
1251
|
+
|
1252
|
+
return NULL;
|
1253
|
+
}
|
1254
|
+
|
1255
|
+
static void del_node(dnode_t *n, void *c)
|
1256
|
+
{
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
static int prompt = 0;
|
1260
|
+
|
1261
|
+
static void construct(dict_t *d)
|
1262
|
+
{
|
1263
|
+
input_t in;
|
1264
|
+
int done = 0;
|
1265
|
+
dict_load_t dl;
|
1266
|
+
dnode_t *dn;
|
1267
|
+
char *tok1, *tok2, *val;
|
1268
|
+
const char *key;
|
1269
|
+
char *help =
|
1270
|
+
"p turn prompt on\n"
|
1271
|
+
"q finish construction\n"
|
1272
|
+
"a <key> <val> add new entry\n";
|
1273
|
+
|
1274
|
+
if (!dict_isempty(d))
|
1275
|
+
puts("warning: dictionary not empty!");
|
1276
|
+
|
1277
|
+
dict_load_begin(&dl, d);
|
1278
|
+
|
1279
|
+
while (!done) {
|
1280
|
+
if (prompt)
|
1281
|
+
putchar('>');
|
1282
|
+
fflush(stdout);
|
1283
|
+
|
1284
|
+
if (!fgets(in, sizeof(input_t), stdin))
|
1285
|
+
break;
|
1286
|
+
|
1287
|
+
switch (in[0]) {
|
1288
|
+
case '?':
|
1289
|
+
puts(help);
|
1290
|
+
break;
|
1291
|
+
case 'p':
|
1292
|
+
prompt = 1;
|
1293
|
+
break;
|
1294
|
+
case 'q':
|
1295
|
+
done = 1;
|
1296
|
+
break;
|
1297
|
+
case 'a':
|
1298
|
+
if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
|
1299
|
+
puts("what?");
|
1300
|
+
break;
|
1301
|
+
}
|
1302
|
+
key = dupstring(tok1);
|
1303
|
+
val = dupstring(tok2);
|
1304
|
+
dn = dnode_create(val);
|
1305
|
+
|
1306
|
+
if (!key || !val || !dn) {
|
1307
|
+
puts("out of memory");
|
1308
|
+
free((void *) key);
|
1309
|
+
free(val);
|
1310
|
+
if (dn)
|
1311
|
+
dnode_destroy(dn);
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
dict_load_next(&dl, dn, key);
|
1315
|
+
break;
|
1316
|
+
default:
|
1317
|
+
putchar('?');
|
1318
|
+
putchar('\n');
|
1319
|
+
break;
|
1320
|
+
}
|
1214
1321
|
}
|
1215
|
-
|
1322
|
+
|
1323
|
+
dict_load_end(&dl);
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
int main(void)
|
1327
|
+
{
|
1328
|
+
input_t in;
|
1329
|
+
dict_t darray[10];
|
1330
|
+
dict_t *d = &darray[0];
|
1331
|
+
dnode_t *dn;
|
1332
|
+
int i;
|
1333
|
+
char *tok1, *tok2, *val;
|
1334
|
+
const char *key;
|
1335
|
+
|
1336
|
+
char *help =
|
1337
|
+
"a <key> <val> add value to dictionary\n"
|
1338
|
+
"d <key> delete value from dictionary\n"
|
1339
|
+
"l <key> lookup value in dictionary\n"
|
1340
|
+
"( <key> lookup lower bound\n"
|
1341
|
+
") <key> lookup upper bound\n"
|
1342
|
+
"# <num> switch to alternate dictionary (0-9)\n"
|
1343
|
+
"j <num> <num> merge two dictionaries\n"
|
1344
|
+
"f free the whole dictionary\n"
|
1345
|
+
"k allow duplicate keys\n"
|
1346
|
+
"c show number of entries\n"
|
1347
|
+
"t dump whole dictionary in sort order\n"
|
1348
|
+
"m make dictionary out of sorted items\n"
|
1349
|
+
"p turn prompt on\n"
|
1350
|
+
"s switch to non-functioning allocator\n"
|
1351
|
+
"q quit";
|
1352
|
+
|
1353
|
+
for (i = 0; i < sizeof darray / sizeof *darray; i++)
|
1354
|
+
dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
|
1355
|
+
|
1356
|
+
for (;;) {
|
1357
|
+
if (prompt)
|
1358
|
+
putchar('>');
|
1359
|
+
fflush(stdout);
|
1360
|
+
|
1361
|
+
if (!fgets(in, sizeof(input_t), stdin))
|
1362
|
+
break;
|
1363
|
+
|
1364
|
+
switch(in[0]) {
|
1365
|
+
case '?':
|
1366
|
+
puts(help);
|
1367
|
+
break;
|
1368
|
+
case 'a':
|
1369
|
+
if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
|
1370
|
+
puts("what?");
|
1371
|
+
break;
|
1372
|
+
}
|
1373
|
+
key = dupstring(tok1);
|
1374
|
+
val = dupstring(tok2);
|
1375
|
+
|
1376
|
+
if (!key || !val) {
|
1377
|
+
puts("out of memory");
|
1378
|
+
free((void *) key);
|
1379
|
+
free(val);
|
1380
|
+
}
|
1381
|
+
|
1382
|
+
if (!dict_alloc_insert(d, key, val)) {
|
1383
|
+
puts("dict_alloc_insert failed");
|
1384
|
+
free((void *) key);
|
1385
|
+
free(val);
|
1386
|
+
break;
|
1387
|
+
}
|
1388
|
+
break;
|
1389
|
+
case 'd':
|
1390
|
+
if (tokenize(in+1, &tok1, (char **) 0) != 1) {
|
1391
|
+
puts("what?");
|
1392
|
+
break;
|
1393
|
+
}
|
1394
|
+
dn = dict_lookup(d, tok1);
|
1395
|
+
if (!dn) {
|
1396
|
+
puts("dict_lookup failed");
|
1397
|
+
break;
|
1398
|
+
}
|
1399
|
+
val = dnode_get(dn);
|
1400
|
+
key = dnode_getkey(dn);
|
1401
|
+
dict_delete_free(d, dn);
|
1402
|
+
|
1403
|
+
free(val);
|
1404
|
+
free((void *) key);
|
1405
|
+
break;
|
1406
|
+
case 'f':
|
1407
|
+
dict_free(d);
|
1408
|
+
break;
|
1409
|
+
case 'l':
|
1410
|
+
case '(':
|
1411
|
+
case ')':
|
1412
|
+
if (tokenize(in+1, &tok1, (char **) 0) != 1) {
|
1413
|
+
puts("what?");
|
1414
|
+
break;
|
1415
|
+
}
|
1416
|
+
dn = 0;
|
1417
|
+
switch (in[0]) {
|
1418
|
+
case 'l':
|
1419
|
+
dn = dict_lookup(d, tok1);
|
1420
|
+
break;
|
1421
|
+
case '(':
|
1422
|
+
dn = dict_lower_bound(d, tok1);
|
1423
|
+
break;
|
1424
|
+
case ')':
|
1425
|
+
dn = dict_upper_bound(d, tok1);
|
1426
|
+
break;
|
1427
|
+
}
|
1428
|
+
if (!dn) {
|
1429
|
+
puts("lookup failed");
|
1430
|
+
break;
|
1431
|
+
}
|
1432
|
+
val = dnode_get(dn);
|
1433
|
+
puts(val);
|
1434
|
+
break;
|
1435
|
+
case 'm':
|
1436
|
+
construct(d);
|
1437
|
+
break;
|
1438
|
+
case 'k':
|
1439
|
+
dict_allow_dupes(d);
|
1440
|
+
break;
|
1441
|
+
case 'c':
|
1442
|
+
printf("%lu\n", (unsigned long) dict_count(d));
|
1443
|
+
break;
|
1444
|
+
case 't':
|
1445
|
+
for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
|
1446
|
+
printf("%s\t%s\n", (char *) dnode_getkey(dn),
|
1447
|
+
(char *) dnode_get(dn));
|
1448
|
+
}
|
1449
|
+
break;
|
1450
|
+
case 'q':
|
1451
|
+
exit(0);
|
1452
|
+
break;
|
1453
|
+
case '\0':
|
1454
|
+
break;
|
1455
|
+
case 'p':
|
1456
|
+
prompt = 1;
|
1457
|
+
break;
|
1458
|
+
case 's':
|
1459
|
+
dict_set_allocator(d, new_node, del_node, NULL);
|
1460
|
+
break;
|
1461
|
+
case '#':
|
1462
|
+
if (tokenize(in+1, &tok1, (char **) 0) != 1) {
|
1463
|
+
puts("what?");
|
1464
|
+
break;
|
1465
|
+
} else {
|
1466
|
+
int dictnum = atoi(tok1);
|
1467
|
+
if (dictnum < 0 || dictnum > 9) {
|
1468
|
+
puts("invalid number");
|
1469
|
+
break;
|
1470
|
+
}
|
1471
|
+
d = &darray[dictnum];
|
1472
|
+
}
|
1473
|
+
break;
|
1474
|
+
case 'j':
|
1475
|
+
if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
|
1476
|
+
puts("what?");
|
1477
|
+
break;
|
1478
|
+
} else {
|
1479
|
+
int dict1 = atoi(tok1), dict2 = atoi(tok2);
|
1480
|
+
if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
|
1481
|
+
puts("invalid number");
|
1482
|
+
break;
|
1483
|
+
}
|
1484
|
+
dict_merge(&darray[dict1], &darray[dict2]);
|
1485
|
+
}
|
1486
|
+
break;
|
1487
|
+
default:
|
1488
|
+
putchar('?');
|
1489
|
+
putchar('\n');
|
1490
|
+
break;
|
1491
|
+
}
|
1492
|
+
}
|
1493
|
+
|
1494
|
+
return 0;
|
1216
1495
|
}
|
1496
|
+
|
1497
|
+
#endif
|