rbtree 0.3.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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