rbtree 0.2.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 +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
data/dict.h CHANGED
@@ -14,18 +14,21 @@
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.h,v 1.9 2005/10/06 05:16:35 kuma Exp $
18
- * $Name: $
17
+ * $Id: dict.h,v 1.22.2.6 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
  #ifndef DICT_H
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
  }
data/extconf.rb CHANGED
@@ -1,34 +1,17 @@
1
1
  require 'mkmf'
2
- require 'rbconfig'
3
2
 
4
- if Config::CONFIG['CC'] =~ /gcc/
5
- $CFLAGS << ' -std=c89 -pedantic -Wall -Wno-long-long'
6
- end
7
-
8
- $defs << '-DNDEBUG'
9
-
10
- print 'checking for allocation framework... '
11
- if Object.respond_to?(:allocate)
12
- print "yes\n"
13
- $defs << '-DHAVE_OBJECT_ALLOCATE'
3
+ if enable_config('debug')
4
+ $CFLAGS << ' -g -std=c99 -pedantic -Wall'
14
5
  else
15
- print "no\n"
6
+ $defs << '-DNDEBUG'
7
+ end
8
+ have_func('rb_exec_recursive', 'ruby.h')
9
+ have_func('rb_exec_recursive_paired', 'ruby.h')
10
+ have_func('rb_proc_lambda_p', 'ruby.h')
11
+ have_func('rb_ary_resize', 'ruby.h')
12
+ have_func('rb_obj_hide', 'ruby.h')
13
+ have_func('rb_safe_level', 'ruby.h')
14
+ if Hash.method_defined?(:flatten)
15
+ $defs << '-DHAVE_HASH_FLATTEN'
16
16
  end
17
-
18
- have_func('rb_obj_init_copy')
19
- have_func('rb_block_proc')
20
- have_func('rb_yield_values')
21
- have_func('rb_marshal_dump')
22
- have_func('rb_marshal_load')
23
-
24
- print 'checking for inline keyword... '
25
- inline = ['inline', '__inline', '__inline__', ''].find {|e|
26
- try_link(<<EOS)
27
- int main() { return 0; }
28
- #{e} void foo() {}
29
- EOS
30
- }
31
- print "#{inline}\n"
32
- $defs << "-Dinline=#{inline}"
33
-
34
17
  create_makefile('rbtree')
data/rbtree.c CHANGED
@@ -1,47 +1,56 @@
1
1
  /*
2
2
  * MIT License
3
- * Copyright (c) 2002-2004, 2007 OZAWA Takuma
3
+ * Copyright (c) 2002-2013 OZAWA Takuma
4
4
  */
5
5
  #include <ruby.h>
6
- #include <version.h>
6
+ #ifdef HAVE_RUBY_ST_H
7
+ #include <ruby/st.h>
8
+ #else
7
9
  #include <st.h>
8
- #include <stdarg.h>
10
+ #endif
9
11
  #include "dict.h"
10
12
 
11
- #define RBTREE_IN_ITERATION FL_USER1
12
13
  #define RBTREE_PROC_DEFAULT FL_USER2
13
14
  #define HASH_PROC_DEFAULT FL_USER2
14
15
 
15
- #ifndef ULONG2NUM
16
- #define ULONG2NUM UINT2NUM
16
+ #ifdef RETURN_SIZED_ENUMERATOR
17
+ #define HAVE_SIZED_ENUMERATOR
18
+ #else
19
+ #ifdef RETURN_ENUMERATOR
20
+ #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) RETURN_ENUMERATOR(obj, argc, argv)
21
+ #else
22
+ #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) ((void)0)
23
+ #endif
24
+ #endif
25
+
26
+ #ifndef RARRAY_AREF
27
+ #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
28
+ #endif
29
+
30
+ #ifndef RHASH_SET_IFNONE
31
+ #define RHASH_SET_IFNONE(h, v) (RHASH(h)->ifnone = (v))
17
32
  #endif
18
33
 
19
34
  VALUE RBTree;
20
35
  VALUE MultiRBTree;
21
36
 
22
- static ID id_bound;
23
37
  static ID id_cmp;
24
38
  static ID id_call;
25
39
  static ID id_default;
26
-
27
- #ifndef HAVE_RB_MARSHAL_DUMP
28
- static VALUE rb_mMarshal;
29
- static ID id_dump;
30
- static ID id_load;
31
- #endif
40
+ static ID id_flatten_bang;
32
41
 
33
42
  typedef struct {
34
43
  dict_t* dict;
35
44
  VALUE ifnone;
45
+ VALUE cmp_proc;
36
46
  int iter_lev;
37
47
  } rbtree_t;
38
48
 
39
49
  #define RBTREE(rbtree) DATA_PTR(rbtree)
40
50
  #define DICT(rbtree) ((rbtree_t*)RBTREE(rbtree))->dict
41
51
  #define IFNONE(rbtree) ((rbtree_t*)RBTREE(rbtree))->ifnone
52
+ #define CMP_PROC(rbtree) ((rbtree_t*)RBTREE(rbtree))->cmp_proc
42
53
  #define ITER_LEV(rbtree) ((rbtree_t*)RBTREE(rbtree))->iter_lev
43
- #define COMPARE(rbtree) DICT(rbtree)->dict_compare
44
- #define CONTEXT(rbtree) DICT(rbtree)->dict_context
45
54
 
46
55
  #define TO_KEY(arg) ((const void*)arg)
47
56
  #define TO_VAL(arg) ((void*)arg)
@@ -51,46 +60,11 @@ typedef struct {
51
60
 
52
61
  /*********************************************************************/
53
62
 
54
- #ifndef HAVE_RB_BLOCK_PROC
55
- static VALUE
56
- rb_block_proc()
57
- {
58
- return rb_f_lambda();
59
- }
60
- #endif
61
-
62
- #ifndef HAVE_RB_YIELD_VALUES
63
- static VALUE
64
- rb_yield_values(int n, ...)
65
- {
66
- int i;
67
- va_list ap;
68
- VALUE ary = rb_ary_new2(n);
69
-
70
- va_start(ap, n);
71
- for (i = 0; i < n; i++)
72
- rb_ary_push(ary, va_arg(ap, VALUE));
73
- va_end(ap);
74
- return rb_yield(ary);
75
- }
76
- #endif
77
-
78
- static int
79
- cmpint(VALUE i, VALUE a, VALUE b)
80
- {
81
- #if RUBY_VERSION_CODE >= 180
82
- return rb_cmpint(i, a, b);
83
- #else
84
- return rb_cmpint(i);
85
- #endif
86
- }
87
-
88
-
89
63
  static void
90
64
  rbtree_free(rbtree_t* rbtree)
91
65
  {
92
66
  dict_free_nodes(rbtree->dict);
93
- dict_destroy(rbtree->dict);
67
+ xfree(rbtree->dict);
94
68
  xfree(rbtree);
95
69
  }
96
70
 
@@ -109,9 +83,9 @@ rbtree_mark(rbtree_t* rbtree)
109
83
  rb_gc_mark(GET_KEY(node));
110
84
  rb_gc_mark(GET_VAL(node));
111
85
  }
112
- rb_gc_mark((VALUE)dict->dict_context);
113
86
  }
114
87
  rb_gc_mark(rbtree->ifnone);
88
+ rb_gc_mark(rbtree->cmp_proc);
115
89
  }
116
90
 
117
91
  static dnode_t*
@@ -127,79 +101,115 @@ rbtree_free_node(dnode_t* node, void* context)
127
101
  }
128
102
 
129
103
  static void
130
- rbtree_argc_error()
131
- {
132
- rb_raise(rb_eArgError, "wrong number of arguments");
104
+ rbtree_check_argument_count(const int argc, const int min, const int max)
105
+ {
106
+ if (argc < min || argc > max) {
107
+ static const char* const message = "wrong number of arguments";
108
+ if (min == max) {
109
+ rb_raise(rb_eArgError, "%s (%d for %d)", message, argc, min);
110
+ } else if (max == INT_MAX) {
111
+ rb_raise(rb_eArgError, "%s (%d for %d+)", message, argc, -min - 1);
112
+ } else {
113
+ rb_raise(rb_eArgError, "%s (%d for %d..%d)", message, argc, min, max);
114
+ }
115
+ }
116
+ }
117
+
118
+ static void
119
+ rbtree_check_proc_arity(VALUE proc, const int expected)
120
+ {
121
+ #ifdef HAVE_RB_PROC_LAMBDA_P
122
+ if (rb_proc_lambda_p(proc)) {
123
+ const int arity = rb_proc_arity(proc);
124
+ const int min = arity < 0 ? -arity - 1 : arity;
125
+ const int max = arity < 0 ? INT_MAX : arity;
126
+ if (expected < min || expected > max) {
127
+ rb_raise(rb_eTypeError, "proc takes %d arguments", expected);
128
+ }
129
+ }
130
+ #endif
133
131
  }
134
132
 
135
133
  static int
136
134
  rbtree_cmp(const void* key1, const void* key2, void* context)
137
135
  {
138
- VALUE ret;
136
+ VALUE result;
139
137
  if (TYPE(key1) == T_STRING && TYPE(key2) == T_STRING)
140
138
  return rb_str_cmp((VALUE)key1, (VALUE)key2);
141
- ret = rb_funcall((VALUE)key1, id_cmp, 1, (VALUE)key2);
142
- return cmpint(ret, (VALUE)key1, (VALUE)key2);
139
+ result = rb_funcall2((VALUE)key1, id_cmp, 1, (VALUE*)&key2);
140
+ return rb_cmpint(result, (VALUE)key1, (VALUE)key2);
141
+ }
142
+
143
+ static VALUE
144
+ rbtree_user_cmp_ensure(rbtree_t* rbtree)
145
+ {
146
+ rbtree->iter_lev--;
147
+ return Qnil;
148
+ }
149
+
150
+ static VALUE
151
+ rbtree_user_cmp_body(VALUE* args)
152
+ {
153
+ rbtree_t* rbtree = (rbtree_t*)args[2];
154
+ rbtree->iter_lev++;
155
+ return rb_funcall2(rbtree->cmp_proc, id_call, 2, args);
143
156
  }
144
157
 
145
158
  static int
146
- rbtree_user_cmp(const void* key1, const void* key2, void* cmp_proc)
159
+ rbtree_user_cmp(const void* key1, const void* key2, void* context)
147
160
  {
148
- VALUE ret = rb_funcall((VALUE)cmp_proc, id_call, 2,
149
- (VALUE)key1, (VALUE)key2);
150
- return cmpint(ret, (VALUE)key1, (VALUE)key2);
161
+ rbtree_t* rbtree = (rbtree_t*)context;
162
+ VALUE args[3];
163
+ VALUE result;
164
+
165
+ args[0] = (VALUE)key1;
166
+ args[1] = (VALUE)key2;
167
+ args[2] = (VALUE)rbtree;
168
+ result = rb_ensure(rbtree_user_cmp_body, (VALUE)&args,
169
+ rbtree_user_cmp_ensure, (VALUE)rbtree);
170
+ return rb_cmpint(result, (VALUE)key1, (VALUE)key2);
151
171
  }
152
172
 
153
173
  static void
154
174
  rbtree_modify(VALUE self)
155
175
  {
156
176
  if (ITER_LEV(self) > 0)
157
- rb_raise(rb_eTypeError, "can't modify rbtree in iteration");
158
- if (OBJ_FROZEN(self))
159
- rb_error_frozen("rbtree");
177
+ rb_raise(rb_eTypeError, "can't modify rbtree during iteration");
178
+ rb_check_frozen(self);
179
+ #if defined(HAVE_RB_SAFE_LEVEL) && !defined(RUBY_SAFE_LEVEL_MAX)
160
180
  if (!OBJ_TAINTED(self) && rb_safe_level() >= 4)
161
181
  rb_raise(rb_eSecurityError, "Insecure: can't modify rbtree");
182
+ #endif
162
183
  }
163
184
 
164
185
  static VALUE
165
186
  rbtree_alloc(VALUE klass)
166
187
  {
167
188
  dict_t* dict;
168
- VALUE rbtree = Data_Wrap_Struct(klass, rbtree_mark, rbtree_free, 0);
189
+ VALUE rbtree = Data_Wrap_Struct(klass, rbtree_mark, rbtree_free, NULL);
169
190
  RBTREE(rbtree) = ALLOC(rbtree_t);
170
191
  MEMZERO(RBTREE(rbtree), rbtree_t, 1);
171
192
 
172
- dict = dict_create(rbtree_cmp);
193
+ dict = ALLOC(dict_t);
194
+ dict_init(dict, rbtree_cmp);
173
195
  dict_set_allocator(dict, rbtree_alloc_node, rbtree_free_node,
174
- (void*)Qnil);
175
- if (klass == MultiRBTree)
196
+ RBTREE(rbtree));
197
+ if (!RTEST(rb_class_inherited_p(klass, RBTree)))
176
198
  dict_allow_dupes(dict);
177
-
199
+
178
200
  DICT(rbtree) = dict;
179
201
  IFNONE(rbtree) = Qnil;
202
+ CMP_PROC(rbtree) = Qnil;
180
203
  return rbtree;
181
204
  }
182
205
 
183
206
  VALUE rbtree_aset(VALUE, VALUE, VALUE);
184
- VALUE rbtree_clear(VALUE);
185
207
  VALUE rbtree_has_key(VALUE, VALUE);
186
208
  VALUE rbtree_update(VALUE, VALUE);
209
+ VALUE rbtree_to_a(VALUE);
187
210
 
188
211
  /*********************************************************************/
189
212
 
190
- #ifndef HAVE_OBJECT_ALLOCATE
191
- /*
192
- *
193
- */
194
- VALUE
195
- rbtree_s_new(int argc, VALUE* argv, VALUE klass)
196
- {
197
- VALUE rbtree = rbtree_alloc(klass);
198
- rb_obj_call_init(rbtree, argc, argv);
199
- return rbtree;
200
- }
201
- #endif
202
-
203
213
  static int
204
214
  hash_to_rbtree_i(VALUE key, VALUE value, VALUE rbtree)
205
215
  {
@@ -214,23 +224,59 @@ hash_to_rbtree_i(VALUE key, VALUE value, VALUE rbtree)
214
224
  VALUE
215
225
  rbtree_s_create(int argc, VALUE* argv, VALUE klass)
216
226
  {
217
- int i;
227
+ long i;
218
228
  VALUE rbtree;
219
229
 
220
230
  if (argc == 1) {
231
+ VALUE temp;
232
+
221
233
  if (rb_obj_is_kind_of(argv[0], klass)) {
222
234
  rbtree = rbtree_alloc(klass);
223
235
  rbtree_update(rbtree, argv[0]);
224
236
  return rbtree;
225
- } else if (TYPE(argv[0]) == T_HASH) {
237
+ }
238
+
239
+ if (RTEST(rb_class_inherited_p(klass, RBTree)) &&
240
+ (rb_obj_is_kind_of(argv[0], MultiRBTree) && !rb_obj_is_kind_of(argv[0], RBTree))) {
241
+
242
+ rb_raise(rb_eTypeError, "wrong argument type MultiRBTree (expected RBTree)");
243
+ }
244
+
245
+ temp = rb_check_convert_type(argv[0], T_HASH, "Hash", "to_hash");
246
+ if (!NIL_P(temp)) {
226
247
  rbtree = rbtree_alloc(klass);
227
- st_foreach(RHASH(argv[0])->tbl, hash_to_rbtree_i, rbtree);
248
+ rb_hash_foreach(temp, hash_to_rbtree_i, rbtree);
249
+ return rbtree;
250
+ }
251
+
252
+ temp = rb_check_array_type(argv[0]);
253
+ if (!NIL_P(temp)) {
254
+ rbtree = rbtree_alloc(klass);
255
+ for (i = 0; i < RARRAY_LEN(temp); i++) {
256
+ VALUE v = rb_check_array_type(RARRAY_AREF(temp, i));
257
+ if (NIL_P(v)) {
258
+ rb_warn("wrong element type %s at %ld (expected Array)",
259
+ rb_obj_classname(RARRAY_AREF(temp, i)), i);
260
+ continue;
261
+ }
262
+ switch(RARRAY_LEN(v)) {
263
+ case 1:
264
+ rbtree_aset(rbtree, RARRAY_AREF(v, 0), Qnil);
265
+ break;
266
+ case 2:
267
+ rbtree_aset(rbtree, RARRAY_AREF(v, 0), RARRAY_AREF(v, 1));
268
+ break;
269
+ default:
270
+ rb_warn("invalid number of elements (%ld for 1..2)",
271
+ RARRAY_LEN(v));
272
+ }
273
+ }
228
274
  return rbtree;
229
275
  }
230
276
  }
231
-
277
+
232
278
  if (argc % 2 != 0)
233
- rb_raise(rb_eArgError, "odd number of arguments for RBTree");
279
+ rb_raise(rb_eArgError, "odd number of arguments for %s", rb_class2name(klass));
234
280
 
235
281
  rbtree = rbtree_alloc(klass);
236
282
  for (i = 0; i < argc; i += 2)
@@ -247,15 +293,17 @@ rbtree_initialize(int argc, VALUE* argv, VALUE self)
247
293
  rbtree_modify(self);
248
294
 
249
295
  if (rb_block_given_p()) {
250
- if (argc > 0)
251
- rbtree_argc_error();
252
- IFNONE(self) = rb_block_proc();
296
+ VALUE proc;
297
+ rbtree_check_argument_count(argc, 0, 0);
298
+ proc = rb_block_proc();
299
+ rbtree_check_proc_arity(proc, 2);
300
+ IFNONE(self) = proc;
253
301
  FL_SET(self, RBTREE_PROC_DEFAULT);
254
302
  } else {
255
- if (argc > 1)
256
- rbtree_argc_error();
257
- else if (argc == 1)
303
+ rbtree_check_argument_count(argc, 0, 1);
304
+ if (argc == 1) {
258
305
  IFNONE(self) = argv[0];
306
+ }
259
307
  }
260
308
  return self;
261
309
  }
@@ -263,42 +311,50 @@ rbtree_initialize(int argc, VALUE* argv, VALUE self)
263
311
  /*********************************************************************/
264
312
 
265
313
  typedef enum {
266
- INITIAL_VALUE, NODE_NOT_FOUND, NODE_FOUND
267
- } insert_node_ret_t;
314
+ NoNodeInserted,
315
+ KeyAllocationFailed,
316
+ InsertionSucceeded
317
+ } insert_result_t;
268
318
 
269
319
  typedef struct {
270
320
  dict_t* dict;
271
321
  dnode_t* node;
272
- const void* key;
273
- insert_node_ret_t ret;
274
- } insert_node_t;
322
+ insert_result_t result;
323
+ } rbtree_insert_arg_t;
275
324
 
276
325
  static VALUE
277
- insert_node_body(insert_node_t* arg)
326
+ insert_node_body(rbtree_insert_arg_t* arg)
278
327
  {
279
- if (dict_insert(arg->dict, arg->node, arg->key))
280
- arg->ret = NODE_NOT_FOUND;
281
- else
282
- arg->ret = NODE_FOUND;
328
+ dict_t* dict = arg->dict;
329
+ dnode_t* node = arg->node;
330
+
331
+ if (dict_insert(dict, node, dnode_getkey(node))) {
332
+ if (TYPE(GET_KEY(node)) == T_STRING) {
333
+ arg->result = KeyAllocationFailed;
334
+ node->dict_key = TO_KEY(rb_str_new4(GET_KEY(node)));
335
+ }
336
+ } else {
337
+ dict->dict_freenode(node, dict->dict_context);
338
+ }
339
+ arg->result = InsertionSucceeded;
283
340
  return Qnil;
284
341
  }
285
342
 
286
343
  static VALUE
287
- insert_node_ensure(insert_node_t* arg)
344
+ insert_node_ensure(rbtree_insert_arg_t* arg)
288
345
  {
289
346
  dict_t* dict = arg->dict;
290
347
  dnode_t* node = arg->node;
291
- switch (arg->ret) {
292
- case INITIAL_VALUE:
293
- dict->dict_freenode(node, dict->dict_context);
294
- break;
295
- case NODE_NOT_FOUND:
296
- if (TYPE(arg->key) == T_STRING)
297
- node->dict_key = TO_KEY(rb_str_new4(GET_KEY(node)));
348
+
349
+ switch (arg->result) {
350
+ case InsertionSucceeded:
298
351
  break;
299
- case NODE_FOUND:
352
+ case NoNodeInserted:
300
353
  dict->dict_freenode(node, dict->dict_context);
301
354
  break;
355
+ case KeyAllocationFailed:
356
+ dict_delete_free(dict, node);
357
+ break;
302
358
  }
303
359
  return Qnil;
304
360
  }
@@ -306,16 +362,16 @@ insert_node_ensure(insert_node_t* arg)
306
362
  static void
307
363
  rbtree_insert(VALUE self, VALUE key, VALUE value)
308
364
  {
309
- insert_node_t arg;
365
+ rbtree_insert_arg_t arg;
310
366
  dict_t* dict = DICT(self);
311
367
  dnode_t* node = dict->dict_allocnode(dict->dict_context);
312
368
 
313
369
  dnode_init(node, TO_VAL(value));
370
+ node->dict_key = TO_KEY(key);
314
371
 
315
372
  arg.dict = dict;
316
373
  arg.node = node;
317
- arg.key = TO_KEY(key);
318
- arg.ret = INITIAL_VALUE;
374
+ arg.result = NoNodeInserted;
319
375
 
320
376
  rb_ensure(insert_node_body, (VALUE)&arg,
321
377
  insert_node_ensure, (VALUE)&arg);
@@ -351,7 +407,7 @@ rbtree_aref(VALUE self, VALUE key)
351
407
  {
352
408
  dnode_t* node = dict_lookup(DICT(self), TO_KEY(key));
353
409
  if (node == NULL)
354
- return rb_funcall(self, id_default, 1, key);
410
+ return rb_funcall2(self, id_default, 1, &key);
355
411
  else
356
412
  return GET_VAL(node);
357
413
  }
@@ -363,22 +419,23 @@ VALUE
363
419
  rbtree_fetch(int argc, VALUE* argv, VALUE self)
364
420
  {
365
421
  dnode_t* node;
366
- int block_given;
367
422
 
368
- if (argc == 0 || argc > 2)
369
- rbtree_argc_error();
370
- block_given = rb_block_given_p();
371
- if (block_given && argc == 2)
372
- rb_warn("block supersedes default value argument");
423
+ rbtree_check_argument_count(argc, 1, 2);
424
+ if (argc == 2 && rb_block_given_p()) {
425
+ rb_warn("block supersedes default value argument");
426
+ }
373
427
 
374
428
  node = dict_lookup(DICT(self), TO_KEY(argv[0]));
375
- if (node != NULL)
429
+ if (node != NULL) {
376
430
  return GET_VAL(node);
431
+ }
377
432
 
378
- if (block_given)
433
+ if (rb_block_given_p()) {
379
434
  return rb_yield(argv[0]);
380
- if (argc == 1)
435
+ }
436
+ if (argc == 1) {
381
437
  rb_raise(rb_eIndexError, "key not found");
438
+ }
382
439
  return argv[1];
383
440
  }
384
441
 
@@ -406,15 +463,12 @@ rbtree_empty_p(VALUE self)
406
463
  VALUE
407
464
  rbtree_default(int argc, VALUE* argv, VALUE self)
408
465
  {
409
- VALUE key = Qnil;
410
- if (argc == 1)
411
- key = argv[0];
412
- else if (argc > 1)
413
- rbtree_argc_error();
414
-
466
+ rbtree_check_argument_count(argc, 0, 1);
415
467
  if (FL_TEST(self, RBTREE_PROC_DEFAULT)) {
416
- if (argc == 0) return Qnil;
417
- return rb_funcall(IFNONE(self), id_call, 2, self, key);
468
+ if (argc == 0) {
469
+ return Qnil;
470
+ }
471
+ return rb_funcall(IFNONE(self), id_call, 2, self, argv[0]);
418
472
  }
419
473
  return IFNONE(self);
420
474
  }
@@ -442,10 +496,54 @@ rbtree_default_proc(VALUE self)
442
496
  return Qnil;
443
497
  }
444
498
 
445
- static int
446
- value_eq(const void* key1, const void* key2)
499
+ /*
500
+ *
501
+ */
502
+ VALUE
503
+ rbtree_set_default_proc(VALUE self, VALUE proc)
447
504
  {
448
- return rb_equal((VALUE)key1, (VALUE)key2);
505
+ VALUE temp;
506
+
507
+ rbtree_modify(self);
508
+ if (NIL_P(proc)) {
509
+ IFNONE(self) = Qnil;
510
+ FL_UNSET(self, RBTREE_PROC_DEFAULT);
511
+ return Qnil;
512
+ }
513
+
514
+ temp = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
515
+ if (NIL_P(temp)) {
516
+ rb_raise(rb_eTypeError,
517
+ "wrong default_proc type %s (expected Proc)",
518
+ rb_obj_classname(proc));
519
+ }
520
+ rbtree_check_proc_arity(temp, 2);
521
+ IFNONE(self) = temp;
522
+ FL_SET(self, RBTREE_PROC_DEFAULT);
523
+ return proc;
524
+ }
525
+
526
+ static VALUE
527
+ rbtree_recursive_equal(VALUE self, VALUE other, int recursive)
528
+ {
529
+ dict_t* dict1 = DICT(self);
530
+ dict_t* dict2 = DICT(other);
531
+ dnode_t* node1;
532
+ dnode_t* node2;
533
+
534
+ if (recursive)
535
+ return Qtrue;
536
+ for (node1 = dict_first(dict1), node2 = dict_first(dict2);
537
+ node1 != NULL && node2 != NULL;
538
+ node1 = dict_next(dict1, node1), node2 = dict_next(dict2, node2)) {
539
+
540
+ if (!rb_equal(GET_KEY(node1), GET_KEY(node2)) ||
541
+ !rb_equal(GET_VAL(node1), GET_VAL(node2))) {
542
+
543
+ return Qfalse;
544
+ }
545
+ }
546
+ return Qtrue;
449
547
  }
450
548
 
451
549
  /*
@@ -454,13 +552,23 @@ value_eq(const void* key1, const void* key2)
454
552
  VALUE
455
553
  rbtree_equal(VALUE self, VALUE other)
456
554
  {
457
- int ret;
458
555
  if (self == other)
459
556
  return Qtrue;
460
557
  if (!rb_obj_is_kind_of(other, MultiRBTree))
461
558
  return Qfalse;
462
- ret = dict_equal(DICT(self), DICT(other), value_eq);
463
- return ret ? Qtrue : Qfalse;
559
+ if (dict_count(DICT(self)) != dict_count(DICT(other)) ||
560
+ DICT(self)->dict_compare != DICT(other)->dict_compare ||
561
+ CMP_PROC(self) != CMP_PROC(other)) {
562
+
563
+ return Qfalse;
564
+ }
565
+ #if defined(HAVE_RB_EXEC_RECURSIVE_PAIRED)
566
+ return rb_exec_recursive_paired(rbtree_recursive_equal, self, other, other);
567
+ #elif defined(HAVE_RB_EXEC_RECURSIVE)
568
+ return rb_exec_recursive(rbtree_recursive_equal, self, other);
569
+ #else
570
+ return rbtree_recursive_equal(self, other, 0);
571
+ #endif
464
572
  }
465
573
 
466
574
  /*********************************************************************/
@@ -493,7 +601,7 @@ rbtree_each_body(rbtree_each_arg_t* arg)
493
601
  dnode_t* node;
494
602
  dnode_t* first_node;
495
603
  dnode_t* (*next_func)(dict_t*, dnode_t*);
496
-
604
+
497
605
  if (arg->reverse) {
498
606
  first_node = dict_last(dict);
499
607
  next_func = dict_prev;
@@ -501,12 +609,12 @@ rbtree_each_body(rbtree_each_arg_t* arg)
501
609
  first_node = dict_first(dict);
502
610
  next_func = dict_next;
503
611
  }
504
-
612
+
505
613
  ITER_LEV(self)++;
506
614
  for (node = first_node;
507
615
  node != NULL;
508
616
  node = next_func(dict, node)) {
509
-
617
+
510
618
  if (arg->func(node, arg->arg) == EACH_STOP)
511
619
  break;
512
620
  }
@@ -539,43 +647,29 @@ rbtree_reverse_for_each(VALUE self, each_callback_func func, void* arg)
539
647
 
540
648
  /*********************************************************************/
541
649
 
542
- static each_return_t
543
- each_i(dnode_t* node, void* arg)
544
- {
545
- rb_yield(ASSOC(node));
546
- return EACH_NEXT;
547
- }
548
-
549
- /*
550
- * call-seq:
551
- * rbtree.each {|key, value| block} => rbtree
552
- *
553
- * Calls block once for each key in order, passing the key and value
554
- * as a two-element array parameters.
555
- */
556
- VALUE
557
- rbtree_each(VALUE self)
558
- {
559
- return rbtree_for_each(self, each_i, NULL);
560
- }
561
-
562
650
  static each_return_t
563
651
  each_pair_i(dnode_t* node, void* arg)
564
652
  {
565
- rb_yield_values(2, GET_KEY(node), GET_VAL(node));
653
+ rb_yield(ASSOC(node));
566
654
  return EACH_NEXT;
567
655
  }
568
656
 
569
657
  /*
570
658
  * call-seq:
659
+ * rbtree.each {|key, value| block} => rbtree
571
660
  * rbtree.each_pair {|key, value| block} => rbtree
661
+ * rbtree.each => enumerator
662
+ * rbtree.each_pair => enumerator
572
663
  *
573
- * Calls block once for each key in order, passing the key and value
664
+ * Calls block once for each key in order, passing the key-value pair
574
665
  * as parameters.
666
+ *
667
+ * Returns an enumerator if no block is given.
575
668
  */
576
669
  VALUE
577
670
  rbtree_each_pair(VALUE self)
578
671
  {
672
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
579
673
  return rbtree_for_each(self, each_pair_i, NULL);
580
674
  }
581
675
 
@@ -589,13 +683,17 @@ each_key_i(dnode_t* node, void* arg)
589
683
  /*
590
684
  * call-seq:
591
685
  * rbtree.each_key {|key| block} => rbtree
686
+ * rbtree.each_key => enumerator
592
687
  *
593
- * Calls block once for each key in order, passing the key as
594
- * parameters.
688
+ * Calls block once for each key in order, passing the key as a
689
+ * parameter.
690
+ *
691
+ * Returns an enumerator if no block is given.
595
692
  */
596
693
  VALUE
597
694
  rbtree_each_key(VALUE self)
598
695
  {
696
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
599
697
  return rbtree_for_each(self, each_key_i, NULL);
600
698
  }
601
699
 
@@ -609,26 +707,34 @@ each_value_i(dnode_t* node, void* arg)
609
707
  /*
610
708
  * call-seq:
611
709
  * rbtree.each_value {|value| block} => rbtree
710
+ * rbtree.each_value => enumerator
711
+ *
712
+ * Calls block once for each key in order, passing the value as a
713
+ * parameter.
612
714
  *
613
- * Calls block once for each key in order, passing the value as
614
- * parameters.
715
+ * Returns an enumerator if no block is given.
615
716
  */
616
717
  VALUE
617
718
  rbtree_each_value(VALUE self)
618
719
  {
720
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
619
721
  return rbtree_for_each(self, each_value_i, NULL);
620
722
  }
621
723
 
622
724
  /*
623
725
  * call-seq:
624
726
  * rbtree.reverse_each {|key, value| block} => rbtree
727
+ * rbtree.reverse_each => enumerator
625
728
  *
626
- * Calls block once for each key in reverse order, passing the key and
627
- * value as parameters.
729
+ * Calls block once for each key in reverse order, passing the
730
+ * key-value pair as parameters.
731
+ *
732
+ * Returns an enumerator if no block is given.
628
733
  */
629
734
  VALUE
630
735
  rbtree_reverse_each(VALUE self)
631
736
  {
737
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
632
738
  return rbtree_reverse_for_each(self, each_pair_i, NULL);
633
739
  }
634
740
 
@@ -640,11 +746,17 @@ aset_i(dnode_t* node, void* self)
640
746
  }
641
747
 
642
748
  static void
643
- copy_dict(VALUE src, VALUE dest, dict_comp_t cmp, void* context)
749
+ copy_dict(VALUE src, VALUE dest, dict_comp_t cmp_func, VALUE cmp_proc)
644
750
  {
645
751
  VALUE temp = rbtree_alloc(CLASS_OF(dest));
646
- COMPARE(temp) = cmp;
647
- CONTEXT(temp) = context;
752
+ #ifdef HAVE_RB_OBJ_HIDE
753
+ rb_obj_hide(temp);
754
+ #else
755
+ RBASIC(temp)->klass = 0;
756
+ #endif
757
+ DICT(temp)->dict_compare = cmp_func;
758
+ CMP_PROC(temp) = cmp_proc;
759
+
648
760
  rbtree_for_each(src, aset_i, (void*)temp);
649
761
  {
650
762
  dict_t* t = DICT(temp);
@@ -652,7 +764,11 @@ copy_dict(VALUE src, VALUE dest, dict_comp_t cmp, void* context)
652
764
  DICT(dest) = t;
653
765
  }
654
766
  rbtree_free(RBTREE(temp));
767
+ RBTREE(temp) = NULL;
655
768
  rb_gc_force_recycle(temp);
769
+
770
+ DICT(dest)->dict_context = RBTREE(dest);
771
+ CMP_PROC(dest) = cmp_proc;
656
772
  }
657
773
 
658
774
  /*
@@ -661,16 +777,18 @@ copy_dict(VALUE src, VALUE dest, dict_comp_t cmp, void* context)
661
777
  VALUE
662
778
  rbtree_initialize_copy(VALUE self, VALUE other)
663
779
  {
780
+ rbtree_modify(self);
781
+
664
782
  if (self == other)
665
783
  return self;
666
784
  if (!rb_obj_is_kind_of(other, CLASS_OF(self))) {
667
785
  rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
668
- rb_class2name(CLASS_OF(other)),
669
- rb_class2name(CLASS_OF(self)));
786
+ rb_obj_classname(other),
787
+ rb_obj_classname(self));
670
788
  }
671
-
672
- copy_dict(other, self, COMPARE(other), CONTEXT(other));
673
-
789
+
790
+ copy_dict(other, self, DICT(other)->dict_compare, CMP_PROC(other));
791
+
674
792
  IFNONE(self) = IFNONE(other);
675
793
  if (FL_TEST(other, RBTREE_PROC_DEFAULT))
676
794
  FL_SET(self, RBTREE_PROC_DEFAULT);
@@ -679,38 +797,28 @@ rbtree_initialize_copy(VALUE self, VALUE other)
679
797
  return self;
680
798
  }
681
799
 
682
- #ifndef HAVE_RB_OBJ_INIT_COPY
683
- /*
684
- *
685
- */
686
- VALUE
687
- rbtree_clone(VALUE self)
688
- {
689
- VALUE clone = rbtree_alloc(CLASS_OF(self));
690
- rbtree_initialize_copy(clone, self);
691
- return clone;
692
- }
693
- #endif
694
-
695
800
  /*
696
801
  *
697
802
  */
698
803
  VALUE
699
804
  rbtree_values_at(int argc, VALUE* argv, VALUE self)
700
805
  {
701
- int i;
702
- VALUE ary = rb_ary_new();
703
-
806
+ long i;
807
+ VALUE ary = rb_ary_new2(argc);
808
+
704
809
  for (i = 0; i < argc; i++)
705
810
  rb_ary_push(ary, rbtree_aref(self, argv[i]));
706
811
  return ary;
707
812
  }
708
813
 
709
814
  static each_return_t
710
- select_i(dnode_t* node, void* ary)
815
+ key_i(dnode_t* node, void* args_)
711
816
  {
712
- if (RTEST(rb_yield_values(2, GET_KEY(node), GET_VAL(node))))
713
- rb_ary_push((VALUE)ary, ASSOC(node));
817
+ VALUE* args = (VALUE*)args_;
818
+ if (rb_equal(GET_VAL(node), args[1])) {
819
+ args[0] = GET_KEY(node);
820
+ return EACH_STOP;
821
+ }
714
822
  return EACH_NEXT;
715
823
  }
716
824
 
@@ -718,22 +826,13 @@ select_i(dnode_t* node, void* ary)
718
826
  *
719
827
  */
720
828
  VALUE
721
- rbtree_select(VALUE self)
722
- {
723
- VALUE ary = rb_ary_new();
724
- rbtree_for_each(self, select_i, (void*)ary);
725
- return ary;
726
- }
727
-
728
- static each_return_t
729
- index_i(dnode_t* node, void* arg_)
829
+ rbtree_key(VALUE self, VALUE value)
730
830
  {
731
- VALUE* arg = (VALUE*)arg_;
732
- if (rb_equal(GET_VAL(node), arg[1])) {
733
- arg[0] = GET_KEY(node);
734
- return EACH_STOP;
735
- }
736
- return EACH_NEXT;
831
+ VALUE args[2];
832
+ args[0] = Qnil;
833
+ args[1] = value;
834
+ rbtree_for_each(self, key_i, &args);
835
+ return args[0];
737
836
  }
738
837
 
739
838
  /*
@@ -742,11 +841,10 @@ index_i(dnode_t* node, void* arg_)
742
841
  VALUE
743
842
  rbtree_index(VALUE self, VALUE value)
744
843
  {
745
- VALUE arg[2];
746
- arg[0] = Qnil;
747
- arg[1] = value;
748
- rbtree_for_each(self, index_i, (void*)&arg);
749
- return arg[0];
844
+ VALUE klass = rb_obj_is_kind_of(self, RBTree) ? RBTree : MultiRBTree;
845
+ const char* classname = rb_class2name(klass);
846
+ rb_warn("%s#index is deprecated; use %s#key", classname, classname);
847
+ return rbtree_key(self, value);
750
848
  }
751
849
 
752
850
  /*
@@ -790,10 +888,11 @@ typedef struct {
790
888
  VALUE self;
791
889
  dnode_list_t* list;
792
890
  int raised;
793
- } rbtree_delete_if_arg_t;
891
+ int if_true;
892
+ } rbtree_remove_if_arg_t;
794
893
 
795
894
  static VALUE
796
- rbtree_delete_if_ensure(rbtree_delete_if_arg_t* arg)
895
+ rbtree_remove_if_ensure(rbtree_remove_if_arg_t* arg)
797
896
  {
798
897
  dict_t* dict = DICT(arg->self);
799
898
  dnode_list_t* list = arg->list;
@@ -811,7 +910,7 @@ rbtree_delete_if_ensure(rbtree_delete_if_arg_t* arg)
811
910
  }
812
911
 
813
912
  static VALUE
814
- rbtree_delete_if_body(rbtree_delete_if_arg_t* arg)
913
+ rbtree_remove_if_body(rbtree_remove_if_arg_t* arg)
815
914
  {
816
915
  VALUE self = arg->self;
817
916
  dict_t* dict = DICT(self);
@@ -823,7 +922,9 @@ rbtree_delete_if_body(rbtree_delete_if_arg_t* arg)
823
922
  node != NULL;
824
923
  node = dict_next(dict, node)) {
825
924
 
826
- if (RTEST(rb_yield_values(2, GET_KEY(node), GET_VAL(node)))) {
925
+ VALUE key = GET_KEY(node);
926
+ VALUE value = GET_VAL(node);
927
+ if (RTEST(rb_yield_values(2, key, value)) == arg->if_true) {
827
928
  dnode_list_t* l = ALLOC(dnode_list_t);
828
929
  l->node = node;
829
930
  l->prev = arg->list;
@@ -834,6 +935,20 @@ rbtree_delete_if_body(rbtree_delete_if_arg_t* arg)
834
935
  return self;
835
936
  }
836
937
 
938
+ static VALUE
939
+ rbtree_remove_if(VALUE self, const int if_true)
940
+ {
941
+ rbtree_remove_if_arg_t arg;
942
+
943
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
944
+ rbtree_modify(self);
945
+ arg.self = self;
946
+ arg.list = NULL;
947
+ arg.if_true = if_true;
948
+ return rb_ensure(rbtree_remove_if_body, (VALUE)&arg,
949
+ rbtree_remove_if_ensure, (VALUE)&arg);
950
+ }
951
+
837
952
  /*********************************************************************/
838
953
 
839
954
  /*
@@ -842,13 +957,16 @@ rbtree_delete_if_body(rbtree_delete_if_arg_t* arg)
842
957
  VALUE
843
958
  rbtree_delete_if(VALUE self)
844
959
  {
845
- rbtree_delete_if_arg_t arg;
960
+ return rbtree_remove_if(self, 1);
961
+ }
846
962
 
847
- rbtree_modify(self);
848
- arg.self = self;
849
- arg.list = NULL;
850
- return rb_ensure(rbtree_delete_if_body, (VALUE)&arg,
851
- rbtree_delete_if_ensure, (VALUE)&arg);
963
+ /*
964
+ *
965
+ */
966
+ VALUE
967
+ rbtree_keep_if(VALUE self)
968
+ {
969
+ return rbtree_remove_if(self, 0);
852
970
  }
853
971
 
854
972
  /*
@@ -857,53 +975,112 @@ rbtree_delete_if(VALUE self)
857
975
  VALUE
858
976
  rbtree_reject_bang(VALUE self)
859
977
  {
860
- const dictcount_t count = dict_count(DICT(self));
978
+ dictcount_t count;
979
+
980
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
981
+ count = dict_count(DICT(self));
861
982
  rbtree_delete_if(self);
862
983
  if (count == dict_count(DICT(self)))
863
984
  return Qnil;
864
985
  return self;
865
986
  }
866
987
 
988
+ /*
989
+ *
990
+ */
991
+ VALUE
992
+ rbtree_select_bang(VALUE self)
993
+ {
994
+ dictcount_t count;
995
+
996
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
997
+ count = dict_count(DICT(self));
998
+ rbtree_keep_if(self);
999
+ if (count == dict_count(DICT(self)))
1000
+ return Qnil;
1001
+ return self;
1002
+
1003
+ }
1004
+
1005
+ /*********************************************************************/
1006
+
1007
+ typedef struct {
1008
+ VALUE result;
1009
+ int if_true;
1010
+ } rbtree_select_if_arg_t;
1011
+
1012
+ static each_return_t
1013
+ select_i(dnode_t* node, void* arg_)
1014
+ {
1015
+ VALUE key = GET_KEY(node);
1016
+ VALUE value = GET_VAL(node);
1017
+ rbtree_select_if_arg_t* arg = arg_;
1018
+
1019
+ if (RTEST(rb_yield_values(2, key, value)) == arg->if_true) {
1020
+ rbtree_aset(arg->result, key, value);
1021
+ }
1022
+ return EACH_NEXT;
1023
+ }
1024
+
1025
+ static VALUE
1026
+ rbtree_select_if(VALUE self, const int if_true)
1027
+ {
1028
+ rbtree_select_if_arg_t arg;
1029
+
1030
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, rbtree_size);
1031
+ arg.result = rbtree_alloc(CLASS_OF(self));
1032
+ arg.if_true = if_true;
1033
+ rbtree_for_each(self, select_i, &arg);
1034
+ return arg.result;
1035
+ }
1036
+
1037
+ /*********************************************************************/
1038
+
867
1039
  /*
868
1040
  *
869
1041
  */
870
1042
  VALUE
871
1043
  rbtree_reject(VALUE self)
872
1044
  {
873
- return rbtree_reject_bang(rb_obj_dup(self));
1045
+ return rbtree_select_if(self, 0);
1046
+ }
1047
+
1048
+ /*
1049
+ *
1050
+ */
1051
+ VALUE
1052
+ rbtree_select(VALUE self)
1053
+ {
1054
+ return rbtree_select_if(self, 1);
874
1055
  }
875
1056
 
876
1057
  static VALUE
877
- rbtree_shift_pop(VALUE self, const int mode)
1058
+ rbtree_shift_pop(VALUE self, const int shift)
878
1059
  {
879
1060
  dict_t* dict = DICT(self);
880
1061
  dnode_t* node;
881
- VALUE ret;
1062
+ VALUE assoc;
882
1063
 
883
1064
  rbtree_modify(self);
884
1065
 
885
- if (dict_isempty(dict)) {
886
- if (FL_TEST(self, RBTREE_PROC_DEFAULT)) {
887
- return rb_funcall(IFNONE(self), id_call, 2, self, Qnil);
888
- }
889
- return IFNONE(self);
890
- }
1066
+ if (dict_isempty(dict))
1067
+ return rb_funcall(self, id_default, 1, Qnil);
891
1068
 
892
- if (mode == 0)
893
- node = dict_first(dict);
894
- else
1069
+ if (shift)
895
1070
  node = dict_last(dict);
896
- ret = ASSOC(node);
1071
+ else
1072
+ node = dict_first(dict);
1073
+ assoc = ASSOC(node);
897
1074
  dict_delete_free(dict, node);
898
- return ret;
1075
+ return assoc;
899
1076
  }
900
1077
 
901
1078
  /*
902
1079
  * call-seq:
903
- * rbtree.shift => array or object
1080
+ * rbtree.shift => array or object or nil
904
1081
  *
905
- * Removes the first(that is, the smallest) key-value pair and returns
906
- * it as a two-item array.
1082
+ * Removes the first (that is, the smallest) key-value pair and
1083
+ * returns it.
907
1084
  */
908
1085
  VALUE
909
1086
  rbtree_shift(VALUE self)
@@ -913,10 +1090,10 @@ rbtree_shift(VALUE self)
913
1090
 
914
1091
  /*
915
1092
  * call-seq:
916
- * rbtree.pop => array or object
1093
+ * rbtree.pop => array or object or nil
917
1094
  *
918
- * Removes the last(that is, the biggest) key-value pair and returns
919
- * it as a two-item array.
1095
+ * Removes the last (that is, the greatest) key-value pair and returns
1096
+ * it.
920
1097
  */
921
1098
  VALUE
922
1099
  rbtree_pop(VALUE self)
@@ -967,10 +1144,10 @@ rbtree_update(VALUE self, VALUE other)
967
1144
  return self;
968
1145
  if (!rb_obj_is_kind_of(other, CLASS_OF(self))) {
969
1146
  rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
970
- rb_class2name(CLASS_OF(other)),
971
- rb_class2name(CLASS_OF(self)));
1147
+ rb_obj_classname(other),
1148
+ rb_obj_classname(self));
972
1149
  }
973
-
1150
+
974
1151
  if (rb_block_given_p())
975
1152
  rbtree_for_each(other, update_block_i, (void*)self);
976
1153
  else
@@ -987,6 +1164,35 @@ rbtree_merge(VALUE self, VALUE other)
987
1164
  return rbtree_update(rb_obj_dup(self), other);
988
1165
  }
989
1166
 
1167
+ static each_return_t
1168
+ to_flat_ary_i(dnode_t* node, void* ary)
1169
+ {
1170
+ rb_ary_push((VALUE)ary, GET_KEY(node));
1171
+ rb_ary_push((VALUE)ary, GET_VAL(node));
1172
+ return EACH_NEXT;
1173
+ }
1174
+
1175
+ /*
1176
+ *
1177
+ */
1178
+ VALUE
1179
+ rbtree_flatten(int argc, VALUE* argv, VALUE self)
1180
+ {
1181
+ VALUE ary;
1182
+
1183
+ rbtree_check_argument_count(argc, 0, 1);
1184
+ ary = rb_ary_new2(dict_count(DICT(self)) * 2);
1185
+ rbtree_for_each(self, to_flat_ary_i, (void*)ary);
1186
+ if (argc == 1) {
1187
+ const int level = NUM2INT(argv[0]) - 1;
1188
+ if (level > 0) {
1189
+ argv[0] = INT2FIX(level);
1190
+ rb_funcall2(ary, id_flatten_bang, argc, argv);
1191
+ }
1192
+ }
1193
+ return ary;
1194
+ }
1195
+
990
1196
  /*
991
1197
  *
992
1198
  */
@@ -997,11 +1203,11 @@ rbtree_has_key(VALUE self, VALUE key)
997
1203
  }
998
1204
 
999
1205
  static each_return_t
1000
- has_value_i(dnode_t* node, void* arg_)
1206
+ has_value_i(dnode_t* node, void* args_)
1001
1207
  {
1002
- VALUE* arg = (VALUE*)arg_;
1003
- if (rb_equal(GET_VAL(node), arg[1])) {
1004
- arg[0] = Qtrue;
1208
+ VALUE* args = (VALUE*)args_;
1209
+ if (rb_equal(GET_VAL(node), args[1])) {
1210
+ args[0] = Qtrue;
1005
1211
  return EACH_STOP;
1006
1212
  }
1007
1213
  return EACH_NEXT;
@@ -1013,11 +1219,11 @@ has_value_i(dnode_t* node, void* arg_)
1013
1219
  VALUE
1014
1220
  rbtree_has_value(VALUE self, VALUE value)
1015
1221
  {
1016
- VALUE arg[2];
1017
- arg[0] = Qfalse;
1018
- arg[1] = value;
1019
- rbtree_for_each(self, has_value_i, (void*)&arg);
1020
- return arg[0];
1222
+ VALUE args[2];
1223
+ args[0] = Qfalse;
1224
+ args[1] = value;
1225
+ rbtree_for_each(self, has_value_i, &args);
1226
+ return args[0];
1021
1227
  }
1022
1228
 
1023
1229
  static each_return_t
@@ -1033,7 +1239,7 @@ keys_i(dnode_t* node, void* ary)
1033
1239
  VALUE
1034
1240
  rbtree_keys(VALUE self)
1035
1241
  {
1036
- VALUE ary = rb_ary_new();
1242
+ VALUE ary = rb_ary_new2(dict_count(DICT(self)));
1037
1243
  rbtree_for_each(self, keys_i, (void*)ary);
1038
1244
  return ary;
1039
1245
  }
@@ -1051,9 +1257,9 @@ values_i(dnode_t* node, void* ary)
1051
1257
  VALUE
1052
1258
  rbtree_values(VALUE self)
1053
1259
  {
1054
- VALUE ret = rb_ary_new();
1055
- rbtree_for_each(self, values_i, (void*)ret);
1056
- return ret;
1260
+ VALUE ary = rb_ary_new2(dict_count(DICT(self)));
1261
+ rbtree_for_each(self, values_i, (void*)ary);
1262
+ return ary;
1057
1263
  }
1058
1264
 
1059
1265
  static each_return_t
@@ -1069,7 +1275,7 @@ to_a_i(dnode_t* node, void* ary)
1069
1275
  VALUE
1070
1276
  rbtree_to_a(VALUE self)
1071
1277
  {
1072
- VALUE ary = rb_ary_new();
1278
+ VALUE ary = rb_ary_new2(dict_count(DICT(self)));
1073
1279
  rbtree_for_each(self, to_a_i, (void*)ary);
1074
1280
  OBJ_INFECT(ary, self);
1075
1281
  return ary;
@@ -1078,7 +1284,7 @@ rbtree_to_a(VALUE self)
1078
1284
  static each_return_t
1079
1285
  to_hash_i(dnode_t* node, void* hash)
1080
1286
  {
1081
- st_insert(RHASH(hash)->tbl, GET_KEY(node), GET_VAL(node));
1287
+ rb_hash_aset((VALUE)hash, GET_KEY(node), GET_VAL(node));
1082
1288
  return EACH_NEXT;
1083
1289
  }
1084
1290
 
@@ -1088,9 +1294,13 @@ to_hash_i(dnode_t* node, void* hash)
1088
1294
  VALUE
1089
1295
  rbtree_to_hash(VALUE self)
1090
1296
  {
1091
- VALUE hash = rb_hash_new();
1297
+ VALUE hash;
1298
+ if (!rb_obj_is_kind_of(self, RBTree))
1299
+ rb_raise(rb_eTypeError, "can't convert MultiRBTree to Hash");
1300
+
1301
+ hash = rb_hash_new();
1092
1302
  rbtree_for_each(self, to_hash_i, (void*)hash);
1093
- RHASH(hash)->ifnone = IFNONE(self);
1303
+ RHASH_SET_IFNONE(hash, IFNONE(self));
1094
1304
  if (FL_TEST(self, RBTREE_PROC_DEFAULT))
1095
1305
  FL_SET(hash, HASH_PROC_DEFAULT);
1096
1306
  OBJ_INFECT(hash, self);
@@ -1109,78 +1319,69 @@ rbtree_to_rbtree(VALUE self)
1109
1319
  static VALUE
1110
1320
  rbtree_begin_inspect(VALUE self)
1111
1321
  {
1112
- const char* c = rb_class2name(CLASS_OF(self));
1113
- VALUE str = rb_str_new(0, strlen(c) + 5);
1114
- const size_t len = sprintf(RSTRING(str)->ptr, "#<%s: ", c);
1115
- RSTRING(str)->len = len;
1116
- return str;
1117
- }
1118
-
1119
- static VALUE
1120
- to_s_rbtree(VALUE self, VALUE nil)
1121
- {
1122
- return rb_ary_to_s(rbtree_to_a(self));
1123
- }
1124
-
1125
- /*
1126
- *
1127
- */
1128
- VALUE
1129
- rbtree_to_s(VALUE self)
1130
- {
1131
- if (rb_inspecting_p(self))
1132
- return rb_str_cat2(rbtree_begin_inspect(self), "...>");
1133
- return rb_protect_inspect(to_s_rbtree, self, Qnil);
1322
+ VALUE result = rb_str_new2("#<");
1323
+ rb_str_cat2(result, rb_obj_classname(self));
1324
+ rb_str_cat2(result, ": ");
1325
+ return result;
1134
1326
  }
1135
1327
 
1136
1328
  static each_return_t
1137
- inspect_i(dnode_t* node, void* ret_)
1329
+ inspect_i(dnode_t* node, void* result_)
1138
1330
  {
1139
- VALUE ret = (VALUE)ret_;
1331
+ VALUE result = (VALUE)result_;
1140
1332
  VALUE str;
1141
1333
 
1142
- if (RSTRING(ret)->ptr[0] == '-')
1143
- RSTRING(ret)->ptr[0] = '#';
1334
+ if (RSTRING_PTR(result)[0] == '-')
1335
+ RSTRING_PTR(result)[0] = '#';
1144
1336
  else
1145
- rb_str_cat2(ret, ", ");
1337
+ rb_str_cat2(result, ", ");
1146
1338
 
1147
1339
  str = rb_inspect(GET_KEY(node));
1148
- rb_str_append(ret, str);
1149
- OBJ_INFECT(ret, str);
1340
+ rb_str_append(result, str);
1341
+ OBJ_INFECT(result, str);
1150
1342
 
1151
- rb_str_cat2(ret, "=>");
1343
+ rb_str_cat2(result, "=>");
1152
1344
 
1153
1345
  str = rb_inspect(GET_VAL(node));
1154
- rb_str_append(ret, str);
1155
- OBJ_INFECT(ret, str);
1346
+ rb_str_append(result, str);
1347
+ OBJ_INFECT(result, str);
1156
1348
 
1157
1349
  return EACH_NEXT;
1158
1350
  }
1159
1351
 
1160
1352
  static VALUE
1161
- inspect_rbtree(VALUE self, VALUE ret)
1353
+ inspect_rbtree(VALUE self, VALUE result)
1162
1354
  {
1163
1355
  VALUE str;
1164
-
1165
- rb_str_cat2(ret, "{");
1166
- RSTRING(ret)->ptr[0] = '-';
1167
- rbtree_for_each(self, inspect_i, (void*)ret);
1168
- RSTRING(ret)->ptr[0] = '#';
1169
- rb_str_cat2(ret, "}");
1356
+
1357
+ rb_str_cat2(result, "{");
1358
+ RSTRING_PTR(result)[0] = '-';
1359
+ rbtree_for_each(self, inspect_i, (void*)result);
1360
+ RSTRING_PTR(result)[0] = '#';
1361
+ rb_str_cat2(result, "}");
1170
1362
 
1171
1363
  str = rb_inspect(IFNONE(self));
1172
- rb_str_cat2(ret, ", default=");
1173
- rb_str_append(ret, str);
1174
- OBJ_INFECT(ret, str);
1175
-
1176
- str = rb_inspect((VALUE)CONTEXT(self));
1177
- rb_str_cat2(ret, ", cmp_proc=");
1178
- rb_str_append(ret, str);
1179
- OBJ_INFECT(ret, str);
1364
+ rb_str_cat2(result, ", default=");
1365
+ rb_str_append(result, str);
1366
+ OBJ_INFECT(result, str);
1367
+
1368
+ str = rb_inspect(CMP_PROC(self));
1369
+ rb_str_cat2(result, ", cmp_proc=");
1370
+ rb_str_append(result, str);
1371
+ OBJ_INFECT(result, str);
1180
1372
 
1181
- rb_str_cat2(ret, ">");
1182
- OBJ_INFECT(ret, self);
1183
- return ret;
1373
+ rb_str_cat2(result, ">");
1374
+ OBJ_INFECT(result, self);
1375
+ return result;
1376
+ }
1377
+
1378
+ static VALUE
1379
+ rbtree_inspect_recursive(VALUE self, VALUE arg, int recursive)
1380
+ {
1381
+ VALUE str = rbtree_begin_inspect(self);
1382
+ if (recursive)
1383
+ return rb_str_cat2(str, "...>");
1384
+ return inspect_rbtree(self, str);
1184
1385
  }
1185
1386
 
1186
1387
  /*
@@ -1189,19 +1390,32 @@ inspect_rbtree(VALUE self, VALUE ret)
1189
1390
  VALUE
1190
1391
  rbtree_inspect(VALUE self)
1191
1392
  {
1393
+ #ifdef HAVE_RB_EXEC_RECURSIVE
1394
+ return rb_exec_recursive(rbtree_inspect_recursive, self, Qnil);
1395
+ #else
1192
1396
  VALUE str = rbtree_begin_inspect(self);
1193
1397
  if (rb_inspecting_p(self))
1194
1398
  return rb_str_cat2(str, "...>");
1195
1399
  return rb_protect_inspect(inspect_rbtree, self, str);
1400
+ #endif
1196
1401
  }
1197
1402
 
1198
1403
  /*
1199
1404
  * call-seq:
1200
- * rbtree.lower_bound(key) => array
1405
+ * rbtree.lower_bound(key) => array or nil
1201
1406
  *
1202
- * Retruns key-value pair corresponding to the lowest key that is
1203
- * equal to or greater than the given key(inside of lower
1407
+ * Retruns the key-value pair corresponding to the lowest key that is
1408
+ * equal to or greater than the given key (inside the lower
1204
1409
  * boundary). If there is no such key, returns nil.
1410
+ *
1411
+ * rbtree = RBTree["az", 10, "ba", 20]
1412
+ * rbtree.lower_bound("ba") # => ["ba", 20]
1413
+ *
1414
+ * # "ba" is the lowest key that is greater than "b"
1415
+ * rbtree.lower_bound("b") # => ["ba", 20]
1416
+ *
1417
+ * # no key that is equal to or greater than "c"
1418
+ * rbtree.lower_bound("c") # => nil
1205
1419
  */
1206
1420
  VALUE
1207
1421
  rbtree_lower_bound(VALUE self, VALUE key)
@@ -1214,11 +1428,20 @@ rbtree_lower_bound(VALUE self, VALUE key)
1214
1428
 
1215
1429
  /*
1216
1430
  * call-seq:
1217
- * rbtree.upper_bound(key) => array
1431
+ * rbtree.upper_bound(key) => array or nil
1432
+ *
1433
+ * Retruns the key-value pair corresponding to the greatest key that
1434
+ * is equal to or lower than the given key (inside the upper
1435
+ * boundary). If there is no such key, returns nil.
1436
+ *
1437
+ * rbtree = RBTree["az", 10, "ba", 20]
1438
+ * rbtree.upper_bound("ba") # => ["ba", 20]
1218
1439
  *
1219
- * Retruns key-value pair corresponding to the greatest key that is
1220
- * equal to or lower than the given key(inside of upper boundary). If
1221
- * there is no such key, returns nil.
1440
+ * # "az" is the greatest key that is lower than "b"
1441
+ * rbtree.upper_bound("b") # => ["az", 10]
1442
+ *
1443
+ * # no key that is equal to or lower than "a"
1444
+ * rbtree.upper_bound("a") # => nil
1222
1445
  */
1223
1446
  VALUE
1224
1447
  rbtree_upper_bound(VALUE self, VALUE key)
@@ -1235,7 +1458,7 @@ typedef struct {
1235
1458
  VALUE self;
1236
1459
  dnode_t* lower_node;
1237
1460
  dnode_t* upper_node;
1238
- VALUE ret;
1461
+ VALUE result;
1239
1462
  } rbtree_bound_arg_t;
1240
1463
 
1241
1464
  static VALUE
@@ -1246,33 +1469,75 @@ rbtree_bound_body(rbtree_bound_arg_t* arg)
1246
1469
  dnode_t* lower_node = arg->lower_node;
1247
1470
  dnode_t* upper_node = arg->upper_node;
1248
1471
  const int block_given = rb_block_given_p();
1249
- VALUE ret = arg->ret;
1472
+ VALUE result = arg->result;
1250
1473
  dnode_t* node;
1251
1474
 
1252
1475
  ITER_LEV(self)++;
1253
- for (node = lower_node;;
1476
+ for (node = lower_node;
1477
+ node != NULL;
1254
1478
  node = dict_next(dict, node)) {
1255
1479
 
1256
1480
  if (block_given)
1257
1481
  rb_yield_values(2, GET_KEY(node), GET_VAL(node));
1258
1482
  else
1259
- rb_ary_push(ret, ASSOC(node));
1483
+ rb_ary_push(result, ASSOC(node));
1260
1484
  if (node == upper_node)
1261
1485
  break;
1262
1486
  }
1263
- return ret;
1487
+ return result;
1264
1488
  }
1265
1489
 
1490
+ #ifdef HAVE_SIZED_ENUMERATOR
1491
+ static VALUE
1492
+ rbtree_bound_size(VALUE self, VALUE args)
1493
+ {
1494
+ VALUE key1 = RARRAY_AREF(args, 0);
1495
+ VALUE key2 = RARRAY_AREF(args, RARRAY_LEN(args) - 1);
1496
+ dnode_t* lower_node = dict_lower_bound(DICT(self), TO_KEY(key1));
1497
+ dnode_t* upper_node = dict_upper_bound(DICT(self), TO_KEY(key2));
1498
+ dictcount_t count = 0;
1499
+ dnode_t* node;
1500
+
1501
+ if (lower_node == NULL || upper_node == NULL ||
1502
+ DICT(self)->dict_compare(dnode_getkey(lower_node),
1503
+ dnode_getkey(upper_node),
1504
+ DICT(self)->dict_context) > 0) {
1505
+ return INT2FIX(0);
1506
+ }
1507
+
1508
+ for (node = lower_node;
1509
+ node != NULL;
1510
+ node = dict_next(DICT(self), node)) {
1511
+
1512
+ count++;
1513
+ if (node == upper_node) {
1514
+ break;
1515
+ }
1516
+ }
1517
+ return ULONG2NUM(count);
1518
+ }
1519
+ #endif
1520
+
1266
1521
  /*********************************************************************/
1267
1522
 
1268
1523
  /*
1269
1524
  * call-seq:
1270
- * rbtree.bound(key1, key2 = key1) => array
1271
1525
  * rbtree.bound(key1, key2 = key1) {|key, value| block} => rbtree
1526
+ * rbtree.bound(key1, key2 = key1) => enumerator
1527
+ *
1528
+ * Calls block once for each key between the result of
1529
+ * rbtree.lower_bound(key1) and rbtree.upper_bound(key2) in order,
1530
+ * passing the key-value pair as parameters. If the lower bound
1531
+ * exceeds the upper bound, block is not called.
1532
+ *
1533
+ * Returns an enumerator if no block is given.
1272
1534
  *
1273
- * Returns an array containing key-value pairs between the result of
1274
- * MultiRBTree#lower_bound and MultiRBTree#upper_bound. If a block is
1275
- * given it calls the block once for each pair.
1535
+ * mrbtree = MultiRBTree["az", 10, "ba", 20, "ba", 30, "bz", 40]
1536
+ * mrbtree.bound("ba").to_a # => [["ba", 20], ["ba", 30]]
1537
+ * mrbtree.bound("b", "c").to_a # => [["ba", 20], ["ba", 30], ["bz", 40]]
1538
+ *
1539
+ * # the lower bound ("ba") exceeds the upper bound ("az")
1540
+ * mrbtree.bound("b").to_a # => []
1276
1541
  */
1277
1542
  VALUE
1278
1543
  rbtree_bound(int argc, VALUE* argv, VALUE self)
@@ -1280,46 +1545,42 @@ rbtree_bound(int argc, VALUE* argv, VALUE self)
1280
1545
  dict_t* dict = DICT(self);
1281
1546
  dnode_t* lower_node;
1282
1547
  dnode_t* upper_node;
1283
- VALUE ret;
1284
-
1285
- if (argc == 0 || argc > 2)
1286
- rbtree_argc_error();
1287
-
1548
+ VALUE result;
1549
+
1550
+ rbtree_check_argument_count(argc, 1, 2);
1551
+
1552
+ RETURN_SIZED_ENUMERATOR(self, argc, argv, rbtree_bound_size);
1553
+
1288
1554
  lower_node = dict_lower_bound(dict, TO_KEY(argv[0]));
1289
1555
  upper_node = dict_upper_bound(dict, TO_KEY(argv[argc - 1]));
1290
- ret = rb_block_given_p() ? self : rb_ary_new();
1291
-
1556
+ result = rb_block_given_p() ? self : rb_ary_new();
1557
+
1292
1558
  if (lower_node == NULL || upper_node == NULL ||
1293
- COMPARE(self)(dnode_getkey(lower_node),
1294
- dnode_getkey(upper_node),
1295
- CONTEXT(self)) > 0) {
1296
- return ret;
1559
+ DICT(self)->dict_compare(dnode_getkey(lower_node),
1560
+ dnode_getkey(upper_node),
1561
+ DICT(self)->dict_context) > 0) {
1562
+ return result;
1297
1563
  } else {
1298
1564
  rbtree_bound_arg_t arg;
1299
1565
  arg.self = self;
1300
1566
  arg.lower_node = lower_node;
1301
1567
  arg.upper_node = upper_node;
1302
- arg.ret = ret;
1303
-
1568
+ arg.result = result;
1304
1569
  return rb_ensure(rbtree_bound_body, (VALUE)&arg,
1305
1570
  rbtree_each_ensure, self);
1306
1571
  }
1307
1572
  }
1308
1573
 
1309
1574
  static VALUE
1310
- rbtree_first_last(VALUE self, const int mode)
1575
+ rbtree_first_last(VALUE self, const int first)
1311
1576
  {
1312
1577
  dict_t* dict = DICT(self);
1313
1578
  dnode_t* node;
1314
1579
 
1315
- if (dict_isempty(dict)) {
1316
- if (FL_TEST(self, RBTREE_PROC_DEFAULT)) {
1317
- return rb_funcall(IFNONE(self), id_call, 2, self, Qnil);
1318
- }
1319
- return IFNONE(self);
1320
- }
1321
-
1322
- if (mode == 0)
1580
+ if (dict_isempty(dict))
1581
+ return rb_funcall(self, id_default, 1, Qnil);
1582
+
1583
+ if (first)
1323
1584
  node = dict_first(dict);
1324
1585
  else
1325
1586
  node = dict_last(dict);
@@ -1328,26 +1589,26 @@ rbtree_first_last(VALUE self, const int mode)
1328
1589
 
1329
1590
  /*
1330
1591
  * call-seq:
1331
- * rbtree.first => array or object
1592
+ * rbtree.first => array or object or nil
1332
1593
  *
1333
- * Returns the first(that is, the smallest) key-value pair.
1594
+ * Returns the first (that is, the smallest) key-value pair.
1334
1595
  */
1335
1596
  VALUE
1336
1597
  rbtree_first(VALUE self)
1337
1598
  {
1338
- return rbtree_first_last(self, 0);
1599
+ return rbtree_first_last(self, 1);
1339
1600
  }
1340
1601
 
1341
1602
  /*
1342
1603
  * call-seq:
1343
- * rbtree.last => array of object
1604
+ * rbtree.last => array or object or nil
1344
1605
  *
1345
- * Returns the last(that is, the biggest) key-value pair.
1606
+ * Returns the last (that is, the greatest) key-value pair.
1346
1607
  */
1347
1608
  VALUE
1348
1609
  rbtree_last(VALUE self)
1349
1610
  {
1350
- return rbtree_first_last(self, 1);
1611
+ return rbtree_first_last(self, 0);
1351
1612
  }
1352
1613
 
1353
1614
  /*
@@ -1358,232 +1619,281 @@ rbtree_last(VALUE self)
1358
1619
  * rbtree.readjust {|key1, key2| block} => rbtree
1359
1620
  *
1360
1621
  * Sets a proc to compare keys and readjusts elements using the given
1361
- * block or a Proc object given as the argument. The block takes two
1362
- * key arguments and returns negative, 0, or positive depending on the
1363
- * first argument is less than, equal to, or greater than the second
1364
- * one. If no block is given it just readjusts elements using current
1365
- * comparison block. If nil is given as the argument it sets default
1366
- * comparison block.
1622
+ * block or a Proc object given as an argument. The block takes two
1623
+ * keys and returns a negative integer, 0, or a positive integer as
1624
+ * the first argument is less than, equal to, or greater than the
1625
+ * second one. If no block is given, just readjusts elements using the
1626
+ * current comparison block. If nil is given as an argument the
1627
+ * default comparison block that uses the <=> method is set.
1628
+ *
1629
+ * rbtree = RBTree["a", 10, "b", 20]
1630
+ * rbtree.readjust {|a, b| b <=> a }
1631
+ * rbtree.first # => ["b", 20]
1632
+ *
1633
+ * rbtree.readjust(nil)
1634
+ * rbtree.first # => ["a", 10]
1367
1635
  */
1368
1636
  VALUE
1369
1637
  rbtree_readjust(int argc, VALUE* argv, VALUE self)
1370
1638
  {
1371
- dict_comp_t cmp = NULL;
1372
- void* context = NULL;
1373
-
1639
+ dict_comp_t cmp_func = NULL;
1640
+ VALUE cmp_proc = Qnil;
1641
+
1374
1642
  rbtree_modify(self);
1375
1643
 
1376
- if (argc == 0) {
1377
- if (rb_block_given_p()) {
1378
- cmp = rbtree_user_cmp;
1379
- context = (void*)rb_block_proc();
1380
- } else {
1381
- cmp = COMPARE(self);
1382
- context = CONTEXT(self);
1383
- }
1384
- } else if (argc == 1 && !rb_block_given_p()) {
1385
- if (argv[0] == Qnil) {
1386
- cmp = rbtree_cmp;
1387
- context = (void*)Qnil;
1644
+ if (rb_block_given_p()) {
1645
+ rbtree_check_argument_count(argc, 0, 0);
1646
+ cmp_func = rbtree_user_cmp;
1647
+ cmp_proc = rb_block_proc();
1648
+ rbtree_check_proc_arity(cmp_proc, 2);
1649
+ } else {
1650
+ rbtree_check_argument_count(argc, 0, 1);
1651
+ if (argc == 0) {
1652
+ cmp_func = DICT(self)->dict_compare;
1653
+ cmp_proc = CMP_PROC(self);
1388
1654
  } else {
1389
- if (CLASS_OF(argv[0]) != rb_cProc)
1390
- rb_raise(rb_eTypeError,
1391
- "wrong argument type %s (expected Proc)",
1392
- rb_class2name(CLASS_OF(argv[0])));
1393
- cmp = rbtree_user_cmp;
1394
- context = (void*)argv[0];
1655
+ if (NIL_P(argv[0])) {
1656
+ cmp_func = rbtree_cmp;
1657
+ cmp_proc = Qnil;
1658
+ } else {
1659
+ VALUE proc = rb_check_convert_type(argv[0], T_DATA, "Proc", "to_proc");
1660
+ if (NIL_P(proc)) {
1661
+ rb_raise(rb_eTypeError,
1662
+ "wrong cmp_proc type %s (expected Proc)",
1663
+ rb_obj_classname(argv[0]));
1664
+ }
1665
+ cmp_func = rbtree_user_cmp;
1666
+ cmp_proc = proc;
1667
+ rbtree_check_proc_arity(cmp_proc, 2);
1668
+ }
1395
1669
  }
1396
- } else {
1397
- rbtree_argc_error();
1398
1670
  }
1399
1671
 
1400
1672
  if (dict_isempty(DICT(self))) {
1401
- COMPARE(self) = cmp;
1402
- CONTEXT(self) = context;
1673
+ DICT(self)->dict_compare = cmp_func;
1674
+ CMP_PROC(self) = cmp_proc;
1403
1675
  return self;
1404
1676
  }
1405
- copy_dict(self, self, cmp, context);
1677
+ copy_dict(self, self, cmp_func, cmp_proc);
1406
1678
  return self;
1407
1679
  }
1408
1680
 
1409
1681
  /*
1410
1682
  * call-seq:
1411
- * rbtree.cmp_proc => proc
1683
+ * rbtree.cmp_proc => proc or nil
1412
1684
  *
1413
- * Returns the comparison block that is given by MultiRBTree#readjust.
1685
+ * Returns the comparison block that is set by
1686
+ * MultiRBTree#readjust. If the default comparison block is set,
1687
+ * returns nil.
1414
1688
  */
1415
1689
  VALUE
1416
1690
  rbtree_cmp_proc(VALUE self)
1417
1691
  {
1418
- return (VALUE)(CONTEXT(self));
1692
+ return CMP_PROC(self);
1419
1693
  }
1420
1694
 
1421
1695
  /*********************************************************************/
1422
1696
 
1697
+ static ID id_breakable;
1423
1698
  static ID id_comma_breakable;
1699
+ static ID id_group;
1424
1700
  static ID id_object_group;
1425
1701
  static ID id_pp;
1426
- static ID id_pp_hash;
1427
1702
  static ID id_text;
1428
1703
 
1704
+ static VALUE
1705
+ pp_group(VALUE args_)
1706
+ {
1707
+ VALUE* args = (VALUE*)args_;
1708
+ return rb_funcall(args[0], id_group, 3, args[1], args[2], args[3]);
1709
+ }
1710
+
1429
1711
  typedef struct {
1430
- VALUE rbtree;
1431
1712
  VALUE pp;
1432
- } pp_arg_t;
1713
+ dnode_t* node;
1714
+ } pp_pair_arg_t;
1433
1715
 
1434
1716
  static VALUE
1435
- pp_object_group(VALUE arg_)
1717
+ pp_value(VALUE nil, pp_pair_arg_t* pair_arg)
1436
1718
  {
1437
- pp_arg_t* arg = (pp_arg_t*)arg_;
1438
- return rb_funcall(arg->pp, id_object_group, 1, arg->rbtree);
1719
+ VALUE pp = pair_arg->pp;
1720
+ rb_funcall(pp, id_breakable, 1, rb_str_new(NULL, 0));
1721
+ return rb_funcall(pp, id_pp, 1, GET_VAL(pair_arg->node));
1722
+ }
1723
+
1724
+ static VALUE
1725
+ pp_pair(VALUE nil, pp_pair_arg_t* pair_arg)
1726
+ {
1727
+ VALUE pp = pair_arg->pp;
1728
+ VALUE group_args[4];
1729
+ group_args[0] = pp;
1730
+ group_args[1] = INT2FIX(1);
1731
+ group_args[2] = rb_str_new(NULL, 0);
1732
+ group_args[3] = rb_str_new(NULL, 0);
1733
+
1734
+ rb_funcall(pp, id_pp, 1, GET_KEY(pair_arg->node));
1735
+ rb_funcall(pp, id_text, 1, rb_str_new2("=>"));
1736
+ return rb_iterate(pp_group, (VALUE)&group_args, pp_value, (VALUE)pair_arg);
1737
+ }
1738
+
1739
+ typedef struct {
1740
+ VALUE pp;
1741
+ int first;
1742
+ } pp_each_pair_arg_t;
1743
+
1744
+ static each_return_t
1745
+ pp_each_pair_i(dnode_t* node, void* each_pair_arg_)
1746
+ {
1747
+ pp_each_pair_arg_t* each_pair_arg = (pp_each_pair_arg_t*)each_pair_arg_;
1748
+ VALUE group_args[4];
1749
+ pp_pair_arg_t pair_arg;
1750
+
1751
+ if (each_pair_arg->first) {
1752
+ each_pair_arg->first = 0;
1753
+ } else {
1754
+ rb_funcall(each_pair_arg->pp, id_comma_breakable, 0);
1755
+ }
1756
+
1757
+ group_args[0] = each_pair_arg->pp;
1758
+ group_args[1] = INT2FIX(0);
1759
+ group_args[2] = rb_str_new(NULL, 0);
1760
+ group_args[3] = rb_str_new(NULL, 0);
1761
+
1762
+ pair_arg.pp = each_pair_arg->pp;
1763
+ pair_arg.node = node;
1764
+
1765
+ rb_iterate(pp_group, (VALUE)&group_args, pp_pair, (VALUE)&pair_arg);
1766
+ return EACH_NEXT;
1439
1767
  }
1440
1768
 
1769
+ typedef struct {
1770
+ VALUE pp;
1771
+ VALUE rbtree;
1772
+ } pp_rbtree_arg_t;
1773
+
1441
1774
  static VALUE
1442
- pp_block(VALUE nil, pp_arg_t* arg)
1775
+ pp_each_pair(VALUE nil, pp_rbtree_arg_t* rbtree_arg)
1443
1776
  {
1444
- VALUE pp = arg->pp;
1445
- VALUE rbtree = arg->rbtree;
1777
+ pp_each_pair_arg_t each_pair_arg;
1778
+ each_pair_arg.pp = rbtree_arg->pp;
1779
+ each_pair_arg.first = 1;
1780
+ return rbtree_for_each(rbtree_arg->rbtree, pp_each_pair_i, &each_pair_arg);
1781
+ }
1782
+
1783
+ static VALUE
1784
+ pp_rbtree(VALUE nil, pp_rbtree_arg_t* rbtree_arg)
1785
+ {
1786
+ VALUE pp = rbtree_arg->pp;
1787
+ VALUE rbtree = rbtree_arg->rbtree;
1788
+
1789
+ VALUE group_args[4];
1790
+ group_args[0] = pp;
1791
+ group_args[1] = INT2FIX(1);
1792
+ group_args[2] = rb_str_new2("{");
1793
+ group_args[3] = rb_str_new2("}");
1446
1794
 
1447
1795
  rb_funcall(pp, id_text, 1, rb_str_new2(": "));
1448
- rb_funcall(pp, id_pp_hash, 1, rbtree);
1796
+ rb_iterate(pp_group, (VALUE)&group_args, pp_each_pair, (VALUE)rbtree_arg);
1449
1797
  rb_funcall(pp, id_comma_breakable, 0);
1450
1798
  rb_funcall(pp, id_text, 1, rb_str_new2("default="));
1451
1799
  rb_funcall(pp, id_pp, 1, IFNONE(rbtree));
1452
1800
  rb_funcall(pp, id_comma_breakable, 0);
1453
1801
  rb_funcall(pp, id_text, 1, rb_str_new2("cmp_proc="));
1454
- rb_funcall(pp, id_pp, 1, CONTEXT(rbtree));
1455
- return pp;
1802
+ return rb_funcall(pp, id_pp, 1, CMP_PROC(rbtree));
1803
+ }
1804
+
1805
+ static VALUE
1806
+ pp_rbtree_group(VALUE arg_)
1807
+ {
1808
+ pp_rbtree_arg_t* arg = (pp_rbtree_arg_t*)arg_;
1809
+ return rb_funcall(arg->pp, id_object_group, 1, arg->rbtree);
1456
1810
  }
1457
1811
 
1458
1812
  /*********************************************************************/
1459
1813
 
1460
- /*
1461
- * Called by pretty printing function pp.
1814
+ /* :nodoc:
1815
+ *
1462
1816
  */
1463
1817
  VALUE
1464
1818
  rbtree_pretty_print(VALUE self, VALUE pp)
1465
1819
  {
1466
- pp_arg_t pp_arg;
1467
- pp_arg.rbtree = self;
1468
- pp_arg.pp = pp;
1469
-
1470
- return rb_iterate(pp_object_group, (VALUE)&pp_arg,
1471
- pp_block, (VALUE)&pp_arg);
1820
+ pp_rbtree_arg_t arg;
1821
+ arg.rbtree = self;
1822
+ arg.pp = pp;
1823
+ return rb_iterate(pp_rbtree_group, (VALUE)&arg, pp_rbtree, (VALUE)&arg);
1472
1824
  }
1473
1825
 
1474
- /*
1475
- * Called by pretty printing function pp.
1826
+ /* :nodoc:
1827
+ *
1476
1828
  */
1477
1829
  VALUE
1478
1830
  rbtree_pretty_print_cycle(VALUE self, VALUE pp)
1479
1831
  {
1480
- return rb_funcall(pp, id_pp, 1, rbtree_inspect(self));
1832
+ return rb_funcall(pp, id_pp, 1, rbtree_inspect_recursive(self, Qnil, 1));
1481
1833
  }
1482
1834
 
1483
1835
  /*********************************************************************/
1484
1836
 
1485
- #ifndef HAVE_RB_MARSHAL_DUMP
1486
- static VALUE
1487
- rb_marshal_dump(VALUE obj, VALUE port)
1488
- {
1489
- return rb_funcall(rb_mMarshal, id_dump, 2, obj, port);
1490
- }
1491
-
1492
- static VALUE
1493
- rb_marshal_load(VALUE port)
1494
- {
1495
- return rb_funcall(rb_mMarshal, id_load, 1, port);
1496
- }
1497
- #endif
1498
-
1499
- static each_return_t
1500
- to_flatten_ary_i(dnode_t* node, void* ary)
1501
- {
1502
- rb_ary_push((VALUE)ary, GET_KEY(node));
1503
- rb_ary_push((VALUE)ary, GET_VAL(node));
1504
- return EACH_NEXT;
1505
- }
1506
-
1507
- /*********************************************************************/
1508
-
1509
- /*
1510
- * Called by Marshal.dump.
1837
+ /* :nodoc:
1838
+ *
1511
1839
  */
1512
1840
  VALUE
1513
1841
  rbtree_dump(VALUE self, VALUE limit)
1514
1842
  {
1515
1843
  VALUE ary;
1516
- VALUE ret;
1517
-
1844
+ VALUE result;
1845
+
1518
1846
  if (FL_TEST(self, RBTREE_PROC_DEFAULT))
1519
- rb_raise(rb_eTypeError, "cannot dump rbtree with default proc");
1520
- if ((VALUE)CONTEXT(self) != Qnil)
1521
- rb_raise(rb_eTypeError, "cannot dump rbtree with compare proc");
1522
-
1847
+ rb_raise(rb_eTypeError, "can't dump rbtree with default proc");
1848
+ if (CMP_PROC(self) != Qnil)
1849
+ rb_raise(rb_eTypeError, "can't dump rbtree with comparison proc");
1850
+
1523
1851
  ary = rb_ary_new2(dict_count(DICT(self)) * 2 + 1);
1524
- rbtree_for_each(self, to_flatten_ary_i, (void*)ary);
1852
+ rbtree_for_each(self, to_flat_ary_i, (void*)ary);
1525
1853
  rb_ary_push(ary, IFNONE(self));
1526
1854
 
1527
- ret = rb_marshal_dump(ary, limit);
1855
+ result = rb_marshal_dump(ary, Qnil);
1856
+ #ifdef HAVE_RB_ARY_RESIZE
1857
+ rb_ary_resize(ary, 0);
1858
+ #else
1528
1859
  rb_ary_clear(ary);
1529
- rb_gc_force_recycle(ary);
1530
- return ret;
1860
+ #endif
1861
+ return result;
1531
1862
  }
1532
1863
 
1533
- /*
1534
- * Called by Marshal.load.
1864
+ /* :nodoc:
1865
+ *
1535
1866
  */
1536
1867
  VALUE
1537
1868
  rbtree_s_load(VALUE klass, VALUE str)
1538
1869
  {
1539
1870
  VALUE rbtree = rbtree_alloc(klass);
1540
1871
  VALUE ary = rb_marshal_load(str);
1541
- VALUE* ptr = RARRAY(ary)->ptr;
1542
- long len = RARRAY(ary)->len - 1;
1872
+ long len = RARRAY_LEN(ary) - 1;
1543
1873
  long i;
1544
-
1874
+
1545
1875
  for (i = 0; i < len; i += 2)
1546
- rbtree_aset(rbtree, ptr[i], ptr[i + 1]);
1547
- IFNONE(rbtree) = ptr[len];
1548
-
1876
+ rbtree_aset(rbtree, RARRAY_AREF(ary, i), RARRAY_AREF(ary, i + 1));
1877
+ IFNONE(rbtree) = RARRAY_AREF(ary, len);
1878
+
1879
+ #ifdef HAVE_RB_ARY_RESIZE
1880
+ rb_ary_resize(ary, 0);
1881
+ #else
1549
1882
  rb_ary_clear(ary);
1550
- rb_gc_force_recycle(ary);
1883
+ #endif
1551
1884
  return rbtree;
1552
1885
  }
1553
1886
 
1554
1887
  /*********************************************************************/
1555
1888
 
1556
1889
  /*
1557
- * RBTree is a sorted associative collection using Red-Black Tree as
1558
- * the internal data structure. The elements of RBTree are ordered and
1559
- * the interface is the almost same as Hash, so simply you can
1560
- * consider RBTree sorted Hash.
1561
- *
1562
- * Red-Black Tree is a kind of binary tree that automatically balances
1563
- * by itself when a node is inserted or deleted. Thus the complexity
1564
- * for insert, search and delete is O(log N) in expected and worst
1565
- * case. On the other hand the complexity of Hash is O(1). Because
1566
- * Hash is unordered the data structure is more effective than
1567
- * Red-Black Tree as an associative collection.
1568
- *
1569
- * The interface of RBTree is the almost same as Hash although there
1570
- * are some limitations.
1571
- *
1572
- * * While iterating (e.g. in RBTree#each block), RBTree is
1573
- * unmodifiable.
1574
- *
1575
- * * Comparison is done using <=> method of key objects. So all types
1576
- * of keys in RBTree should be comparable each other or an arbitrary
1577
- * Proc might be set by RBTree#readjust.
1890
+ * Document-class: MultiRBTree
1578
1891
  *
1579
- * RBTree has a few searching methods that Hash doesn't have. They are
1580
- * RBTree#lower_bound, RBTree#upper_bound and RBTree#bound. See
1581
- * document of each method for details.
1582
- *
1583
- * Pretty printing is available for RBTree by using pp.rb. The output
1584
- * of pp is easier than p to read. Just call Kernel#pp for the object.
1585
- *
1586
- * MultiRBTree that allows duplicates of keys is also available.
1892
+ * A sorted associative collection that can contain duplicate keys.
1893
+ */
1894
+ /*
1895
+ * A sorted associative collection that cannot contain duplicate
1896
+ * keys. RBTree is a subclass of MultiRBTree.
1587
1897
  */
1588
1898
  void Init_rbtree()
1589
1899
  {
@@ -1591,27 +1901,20 @@ void Init_rbtree()
1591
1901
  RBTree = rb_define_class("RBTree", MultiRBTree);
1592
1902
 
1593
1903
  rb_include_module(MultiRBTree, rb_mEnumerable);
1594
-
1595
- #ifdef HAVE_OBJECT_ALLOCATE
1904
+
1596
1905
  rb_define_alloc_func(MultiRBTree, rbtree_alloc);
1597
- #else
1598
- rb_define_singleton_method(MultiRBTree, "new", rbtree_s_new, -1);
1599
- #endif
1906
+
1600
1907
  rb_define_singleton_method(MultiRBTree, "[]", rbtree_s_create, -1);
1601
1908
 
1602
1909
  rb_define_method(MultiRBTree, "initialize", rbtree_initialize, -1);
1603
-
1604
- #ifdef HAVE_RB_OBJ_INIT_COPY
1605
1910
  rb_define_method(MultiRBTree, "initialize_copy", rbtree_initialize_copy, 1);
1606
- #else
1607
- rb_define_method(MultiRBTree, "clone", rbtree_clone, 0);
1608
- #endif
1609
1911
 
1610
1912
  rb_define_method(MultiRBTree, "to_a", rbtree_to_a, 0);
1611
- rb_define_method(MultiRBTree, "to_s", rbtree_to_s, 0);
1913
+ rb_define_method(MultiRBTree, "to_h", rbtree_to_hash, 0);
1612
1914
  rb_define_method(MultiRBTree, "to_hash", rbtree_to_hash, 0);
1613
1915
  rb_define_method(MultiRBTree, "to_rbtree", rbtree_to_rbtree, 0);
1614
1916
  rb_define_method(MultiRBTree, "inspect", rbtree_inspect, 0);
1917
+ rb_define_alias(MultiRBTree, "to_s", "inspect");
1615
1918
 
1616
1919
  rb_define_method(MultiRBTree, "==", rbtree_equal, 1);
1617
1920
  rb_define_method(MultiRBTree, "[]", rbtree_aref, 1);
@@ -1626,12 +1929,14 @@ void Init_rbtree()
1626
1929
  rb_define_method(MultiRBTree, "default", rbtree_default, -1);
1627
1930
  rb_define_method(MultiRBTree, "default=", rbtree_set_default, 1);
1628
1931
  rb_define_method(MultiRBTree, "default_proc", rbtree_default_proc, 0);
1932
+ rb_define_method(MultiRBTree, "default_proc=", rbtree_set_default_proc, 1);
1933
+ rb_define_method(MultiRBTree, "key", rbtree_key, 1);
1629
1934
  rb_define_method(MultiRBTree, "index", rbtree_index, 1);
1630
1935
  rb_define_method(MultiRBTree, "empty?", rbtree_empty_p, 0);
1631
1936
  rb_define_method(MultiRBTree, "size", rbtree_size, 0);
1632
1937
  rb_define_method(MultiRBTree, "length", rbtree_size, 0);
1633
1938
 
1634
- rb_define_method(MultiRBTree, "each", rbtree_each, 0);
1939
+ rb_define_method(MultiRBTree, "each", rbtree_each_pair, 0);
1635
1940
  rb_define_method(MultiRBTree, "each_value", rbtree_each_value, 0);
1636
1941
  rb_define_method(MultiRBTree, "each_key", rbtree_each_key, 0);
1637
1942
  rb_define_method(MultiRBTree, "each_pair", rbtree_each_pair, 0);
@@ -1645,15 +1950,20 @@ void Init_rbtree()
1645
1950
  rb_define_method(MultiRBTree, "pop", rbtree_pop, 0);
1646
1951
  rb_define_method(MultiRBTree, "delete", rbtree_delete, 1);
1647
1952
  rb_define_method(MultiRBTree, "delete_if", rbtree_delete_if, 0);
1648
- rb_define_method(MultiRBTree, "select", rbtree_select, 0);
1953
+ rb_define_method(MultiRBTree, "keep_if", rbtree_keep_if, 0);
1649
1954
  rb_define_method(MultiRBTree, "reject", rbtree_reject, 0);
1650
1955
  rb_define_method(MultiRBTree, "reject!", rbtree_reject_bang, 0);
1956
+ rb_define_method(MultiRBTree, "select", rbtree_select, 0);
1957
+ rb_define_method(MultiRBTree, "select!", rbtree_select_bang, 0);
1651
1958
  rb_define_method(MultiRBTree, "clear", rbtree_clear, 0);
1652
1959
  rb_define_method(MultiRBTree, "invert", rbtree_invert, 0);
1653
1960
  rb_define_method(MultiRBTree, "update", rbtree_update, 1);
1654
1961
  rb_define_method(MultiRBTree, "merge!", rbtree_update, 1);
1655
1962
  rb_define_method(MultiRBTree, "merge", rbtree_merge, 1);
1656
1963
  rb_define_method(MultiRBTree, "replace", rbtree_initialize_copy, 1);
1964
+ #ifdef HAVE_HASH_FLATTEN
1965
+ rb_define_method(MultiRBTree, "flatten", rbtree_flatten, -1);
1966
+ #endif
1657
1967
 
1658
1968
  rb_define_method(MultiRBTree, "include?", rbtree_has_key, 1);
1659
1969
  rb_define_method(MultiRBTree, "member?", rbtree_has_key, 1);
@@ -1667,25 +1977,20 @@ void Init_rbtree()
1667
1977
 
1668
1978
  rb_define_method(MultiRBTree, "_dump", rbtree_dump, 1);
1669
1979
  rb_define_singleton_method(MultiRBTree, "_load", rbtree_s_load, 1);
1670
- #ifndef HAVE_RB_MARSHAL_DUMP
1671
- rb_mMarshal = rb_path2class("Marshal");
1672
- id_dump = rb_intern("dump");
1673
- id_load = rb_intern("load");
1674
- #endif
1675
-
1676
- id_bound = rb_intern("bound");
1980
+
1677
1981
  id_cmp = rb_intern("<=>");
1678
1982
  id_call = rb_intern("call");
1679
1983
  id_default = rb_intern("default");
1680
-
1984
+ id_flatten_bang = rb_intern("flatten!");
1681
1985
 
1682
1986
  rb_define_method(MultiRBTree, "pretty_print", rbtree_pretty_print, 1);
1683
1987
  rb_define_method(MultiRBTree,
1684
1988
  "pretty_print_cycle", rbtree_pretty_print_cycle, 1);
1685
1989
 
1990
+ id_breakable = rb_intern("breakable");
1686
1991
  id_comma_breakable = rb_intern("comma_breakable");
1992
+ id_group = rb_intern("group");
1687
1993
  id_object_group = rb_intern("object_group");
1688
- id_pp_hash = rb_intern("pp_hash");
1689
- id_text = rb_intern("text");
1690
1994
  id_pp = rb_intern("pp");
1995
+ id_text = rb_intern("text");
1691
1996
  }