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.
Files changed (11) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +1 -1
  3. data/MANIFEST +0 -1
  4. data/README +38 -71
  5. data/dict.c +364 -83
  6. data/dict.h +30 -6
  7. data/extconf.rb +13 -2
  8. data/rbtree.c +772 -482
  9. data/test.rb +309 -182
  10. metadata +42 -45
  11. data/ChangeLog +0 -505
@@ -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, 2009-2010 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,42 +1,37 @@
1
- =begin
2
-
3
1
  = Ruby/RBTree
4
2
 
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.
3
+ == Description
9
4
 
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.
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
- 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.
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 interface of RBTree is the almost same as Hash and there are a
25
- few methods to take advantage of the ordering:
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
- * lower_bound, upper_bound, bound
28
- * first, last
29
- * shift, pop
30
- * reverse_each
23
+ RBTree also provides a few additional methods to take advantage of the
24
+ ordering:
31
25
 
32
- Note: while iterating RBTree (e.g. in a block of each method), it is
33
- not modifiable, or TypeError is thrown.
26
+ * lower_bound, upper_bound, bound
27
+ * first, last
28
+ * shift, pop
29
+ * reverse_each
34
30
 
35
- RBTree supoorts pretty printing using pp.
31
+ == Example
36
32
 
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.
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
- == Requirement
51
+ Note: a RBTree cannot be modified during iteration.
57
52
 
58
- * Ruby 1.8.x, 1.9.1
53
+ == Installation
59
54
 
60
- == Install
55
+ Run the following command.
61
56
 
62
57
  $ sudo gem install rbtree
63
58
 
64
- or download a tarball from the link below
65
-
66
- * ((<"Ruby/RBTree 0.3.0"|URL:rbtree-0.3.0.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
59
+ == Changes
60
+ === 0.4.4
61
+ * Remove the rb_safe_level warning on Ruby 2.7.
79
62
 
80
- == Incomplete Documents
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-2004, 2007, 2009-2010 OZAWA Takuma.
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. 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
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