rbtree 0.2.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.
Files changed (11) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/MANIFEST +0 -1
  4. data/README +52 -57
  5. data/dict.c +364 -83
  6. data/dict.h +30 -6
  7. data/extconf.rb +12 -29
  8. data/rbtree.c +824 -519
  9. data/test.rb +393 -193
  10. metadata +52 -45
  11. data/ChangeLog +0 -425
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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2002-2004, 2007 OZAWA Takuma
1
+ Copyright (c) 2002-2013 OZAWA Takuma
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/MANIFEST CHANGED
@@ -1,4 +1,3 @@
1
- ChangeLog
2
1
  LICENSE
3
2
  MANIFEST
4
3
  README
data/README CHANGED
@@ -1,78 +1,73 @@
1
- =begin
2
-
3
1
  = Ruby/RBTree
4
2
 
5
- RBTree is a sorted associative collection using Red-Black Tree as
6
- the internal data structure. The elements of RBTree are ordered and
7
- the interface is the almost same as Hash, so simply you can
8
- consider RBTree sorted 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 interface of RBTree is the almost same as Hash although there
18
- are some limitations.
3
+ == Description
19
4
 
20
- * While iterating (e.g. in RBTree#each block), RBTree is
21
- unmodifiable.
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.
22
9
 
23
- * Comparison is done using <=> method of key objects. So all types
24
- of keys in RBTree should be comparable each other or an arbitrary
25
- Proc might be set by RBTree#readjust.
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.
26
16
 
27
- RBTree has a few searching methods that Hash doesn't have. They are
28
- RBTree#lower_bound, RBTree#upper_bound and RBTree#bound. See document
29
- of each method for details.
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.
30
22
 
31
- Pretty printing is available for RBTree by using pp.rb. The output
32
- of pp is easier than p to read. Just call Kernel#pp for the object.
23
+ RBTree also provides a few additional methods to take advantage of the
24
+ ordering:
33
25
 
34
- MultiRBTree that allows duplicates of keys is also available.
26
+ * lower_bound, upper_bound, bound
27
+ * first, last
28
+ * shift, pop
29
+ * reverse_each
35
30
 
36
- == Requirement
31
+ == Example
37
32
 
38
- * Ruby 1.6.7 or higher
39
-
40
- == Install
41
-
42
- $ sudo gem install rbtree
33
+ A RBTree cannot contain duplicate keys. Use MultiRBTree that is the
34
+ parent class of RBTree to store duplicate keys.
43
35
 
44
- or download a tarball from the link below
36
+ require "rbtree"
37
+
38
+ rbtree = RBTree["c", 10, "a", 20]
39
+ rbtree["b"] = 30
40
+ p rbtree["b"] # => 30
41
+ rbtree.each do |k, v|
42
+ p [k, v]
43
+ end # => ["a", 20] ["b", 30] ["c", 10]
44
+
45
+ mrbtree = MultiRBTree["c", 10, "a", 20, "e", 30, "a", 40]
46
+ p mrbtree.lower_bound("b") # => ["c", 10]
47
+ mrbtree.bound("a", "d") do |k, v|
48
+ p [k, v]
49
+ end # => ["a", 20] ["a", 40] ["c", 10]
45
50
 
46
- * ((<"Ruby/RBTree 0.2.0"|URL:rbtree-0.2.0.tar.gz>))
51
+ Note: a RBTree cannot be modified during iteration.
47
52
 
48
- and then
53
+ == Installation
49
54
 
50
- $ tar xzf rbtree-x.x.x.tar.gz
51
- $ cd rbtree-x.x.x.tar.gz
52
- $ ruby extconf.rb
53
- $ make
54
- $ sudo make site-install
55
+ Run the following command.
55
56
 
56
- == Test
57
-
58
- $ ruby test.rb
57
+ $ sudo gem install rbtree
59
58
 
60
- == Incomplete Document
59
+ == Changes
60
+ === 0.4.4
61
+ * Remove the rb_safe_level warning on Ruby 2.7.
61
62
 
62
- $ rdoc rbtree.c
63
+ === 0.4.3
64
+ * Quick bug fixes for Ruby 3.
63
65
 
64
66
  == License
65
67
 
66
- MIT License. Copyright (c) 2002-2004, 2007 OZAWA Takuma.
68
+ MIT License. Copyright (c) 2002-2013 OZAWA Takuma.
67
69
 
68
70
  dict.c and dict.h are modified copies that are originally in Kazlib
69
- written by Kaz Kylheku. Copyright is held by Kaz Kylheku, see dict.c
70
- and dict.h for the license. The web page of Kazlib is at
71
- ((<URL:http://users.footprints.net/~kaz/kazlib.html>)).
72
-
73
- == Support
74
-
75
- Bug fixes, suggestions and other feedbacks are welcomed. Please mail
76
- me at burningdowntheopera at yahoo dot co dot jp.
77
-
78
- =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.15 2005/10/06 05:16:35 kuma Exp $
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 by OZAWA Takuma.
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.15 2005/10/06 05:16:35 kuma Exp $";
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
- while (first && (next = dict_next(dict, first))) {
162
- if (COMPARE(dict, first->key, next->key) > 0)
163
- return 0;
164
- first = next;
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
- while (first && (next = dict_next(dict, first))) {
168
- if (COMPARE(dict, first->key, next->key) >= 0)
169
- return 0;
170
- first = next;
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* new = ALLOC(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
- new->dupes = 0;
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
- xfree(dict);
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 = COMPARE(dict, key, root->key);
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
- 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
- }
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 = COMPARE(dict, key, root->key);
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
- if (!dict->dupes) {
494
- return root;
495
- } else {
496
- tentative = root;
497
- root = root->left;
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 = COMPARE(dict, key, root->key);
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
- if (!dict->dupes) {
526
- return root;
527
- } else {
528
- tentative = root;
529
- root = root->right;
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 = COMPARE(dict, key, where->key);
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
- if (dict->dupes)
1046
- assert (COMPARE(dict, nil->left->key, key) <= 0);
1047
- else
1048
- assert (COMPARE(dict, nil->left->key, key) < 0);
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 (COMPARE(dest, leftnode->key, rightnode->key) < 0)
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
- int dict_equal(dict_t* dict1, dict_t* dict2,
1196
- dict_value_eql_t value_eql)
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
- dnode_t* node1;
1199
- dnode_t* node2;
1232
+ return strcmp(key1, key2);
1233
+ }
1200
1234
 
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;
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
- return 1;
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