rbtree 0.3.0 → 0.4.0

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 +45 -68
  5. data/dict.c +60 -84
  6. data/dict.h +27 -3
  7. data/extconf.rb +10 -1
  8. data/rbtree.c +724 -437
  9. data/test.rb +311 -182
  10. metadata +37 -41
  11. data/ChangeLog +0 -505
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b2c9450418c5e8acbcf6dfe359cbd7f5495558ea
4
+ data.tar.gz: 3cc9df43495129924dc06ef7571309dc604b99d9
5
+ SHA512:
6
+ metadata.gz: aba578f329b5ceb9dd07de643671d97ff16110bab46b1fbceec28424ec10a69898129f137bcfa382412f6d8580a31008fbb309e7e3098d50821b12881826937d
7
+ data.tar.gz: 6cbef7d7032c04e4a2183c4346418ebe2220de66309b5e3d41c275eee9e091a542a8c51ebd81948e8fa39a5aeb71ad81b2ae1fe81c9f4e6b88f619836a82500d
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,43 @@ 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
59
+ == Changes
60
+ === 0.4.0
77
61
 
78
- $ ruby test.rb
79
-
80
- == Incomplete Documents
81
-
82
- $ rdoc rbtree.c
83
-
84
- or online documents at ((<URL:http://rbtree.rubyforge.org/>)).
62
+ * Fixed build failure with Ruby 2.0.0.
63
+ * \#bound now returns an enumerator if no block is given.
64
+ * \#select now returns a new MultiRBTree / RBTree.
65
+ * Fixed a bug where \#reject could return nil.
66
+ * \#to_s is now equivalent to \#inspect.
67
+ * \#each now passes a two elements array as an argument to the given block.
68
+ * Added new methods: \#default_proc=, \#flatten, \#keep_if, \#key, \#select! and \#to_h.
85
69
 
86
70
  == License
87
71
 
88
- MIT License. Copyright (c) 2002-2004, 2007, 2009-2010 OZAWA Takuma.
72
+ MIT License. Copyright (c) 2002-2013 OZAWA Takuma.
89
73
 
90
74
  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.
75
+ 1.20 written by Kaz Kylheku. Its license is similar to the MIT
76
+ license. See dict.c and dict.h for the details. The web page of Kazlib
77
+ is at http://www.kylheku.com/~kaz/kazlib.html.
99
78
 
100
- == Links
79
+ == Contact
101
80
 
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>))
81
+ Run the following command.
105
82
 
106
- =end
83
+ $ ruby -e "puts 'YnVybmluZ2Rvd250aGVvcGVyYUB5YWhvby5jby5qcA==\n'.unpack('m')"
data/dict.c CHANGED
@@ -25,10 +25,9 @@
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
32
  static const char rcsid[] = "$Id: dict.c,v 1.15 2005/10/06 05:16:35 kuma Exp $";
34
33
  #endif
@@ -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;
@@ -1191,26 +1190,3 @@ void dict_merge(dict_t *dest, dict_t *source)
1191
1190
  dict_clear(source);
1192
1191
  dict_load_end(&load);
1193
1192
  }
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
- }
data/dict.h CHANGED
@@ -26,6 +26,9 @@
26
26
  #define DICT_H
27
27
 
28
28
  #include <limits.h>
29
+ #ifdef KAZLIB_SIDEEFFECT_DEBUG
30
+ #include "sfx.h"
31
+ #endif
29
32
 
30
33
  /*
31
34
  * Blurb for inclusion into C++ translation units
@@ -45,21 +48,24 @@ typedef unsigned long dictcount_t;
45
48
  typedef enum { dnode_red, dnode_black } dnode_color_t;
46
49
 
47
50
  typedef struct dnode_t {
51
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
48
52
  struct dnode_t *dict_left;
49
53
  struct dnode_t *dict_right;
50
54
  struct dnode_t *dict_parent;
51
55
  dnode_color_t dict_color;
52
56
  const void *dict_key;
53
57
  void *dict_data;
58
+ #else
59
+ int dict_dummy;
60
+ #endif
54
61
  } dnode_t;
55
62
 
56
63
  typedef int (*dict_comp_t)(const void *, const void *, void *);
57
64
  typedef dnode_t *(*dnode_alloc_t)(void *);
58
65
  typedef void (*dnode_free_t)(dnode_t *, void *);
59
66
 
60
- typedef int (*dict_value_eql_t)(const void *, const void *);
61
-
62
67
  typedef struct dict_t {
68
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
63
69
  dnode_t dict_nilnode;
64
70
  dictcount_t dict_nodecount;
65
71
  dict_comp_t dict_compare;
@@ -67,13 +73,20 @@ typedef struct dict_t {
67
73
  dnode_free_t dict_freenode;
68
74
  void *dict_context;
69
75
  int dict_dupes;
76
+ #else
77
+ int dict_dummmy;
78
+ #endif
70
79
  } dict_t;
71
80
 
72
81
  typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
73
82
 
74
83
  typedef struct dict_load_t {
84
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
75
85
  dict_t *dict_dictptr;
76
86
  dnode_t dict_nilnode;
87
+ #else
88
+ int dict_dummmy;
89
+ #endif
77
90
  } dict_load_t;
78
91
 
79
92
  extern dict_t *dict_create(dict_comp_t);
@@ -114,7 +127,18 @@ extern void dict_load_next(dict_load_t *, dnode_t *, const void *);
114
127
  extern void dict_load_end(dict_load_t *);
115
128
  extern void dict_merge(dict_t *, dict_t *);
116
129
 
117
- int dict_equal(dict_t*, dict_t*, dict_value_eql_t);
130
+ #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
131
+ #ifdef KAZLIB_SIDEEFFECT_DEBUG
132
+ #define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
133
+ #else
134
+ #define dict_isfull(D) ((D)->dict_nodecount == DICTCOUNT_T_MAX)
135
+ #endif
136
+ #define dict_count(D) ((D)->dict_nodecount)
137
+ #define dict_isempty(D) ((D)->dict_nodecount == 0)
138
+ #define dnode_get(N) ((N)->dict_data)
139
+ #define dnode_getkey(N) ((N)->dict_key)
140
+ #define dnode_put(N, X) ((N)->dict_data = (X))
141
+ #endif
118
142
 
119
143
  #ifdef __cplusplus
120
144
  }