rbtree 0.3.0 → 0.4.0

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 +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
  }