Ruby: range.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

range.c
Go to the documentation of this file.
1/**********************************************************************
2
3 range.c -
4
5 $Author$
6 created at: Thu Aug 19 17:46:47 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13
14#include <assert.h>
15#include <math.h>
16
17#ifdef HAVE_FLOAT_H
18#include <float.h>
19#endif
20
21#include "id.h"
22#include "internal.h"
23#include "internal/array.h"
24#include "internal/compar.h"
25#include "internal/enum.h"
26#include "internal/enumerator.h"
27#include "internal/error.h"
28#include "internal/numeric.h"
29#include "internal/range.h"
30
31 VALUE rb_cRange;
32static ID id_beg, id_end, id_excl;
33#define id_cmp idCmp
34#define id_succ idSucc
35#define id_min idMin
36#define id_max idMax
37
38static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
39
40#define RANGE_SET_BEG(r, v) (RSTRUCT_SET(r, 0, v))
41#define RANGE_SET_END(r, v) (RSTRUCT_SET(r, 1, v))
42#define RANGE_SET_EXCL(r, v) (RSTRUCT_SET(r, 2, v))
43#define RBOOL(v) ((v) ? Qtrue : Qfalse)
44
45#define EXCL(r) RTEST(RANGE_EXCL(r))
46
47static void
48range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
49{
50 if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
51 VALUE v;
52
53 v = rb_funcall(beg, id_cmp, 1, end);
54 if (NIL_P(v))
55 rb_raise(rb_eArgError, "bad value for range");
56 }
57
58 RANGE_SET_EXCL(range, exclude_end);
59 RANGE_SET_BEG(range, beg);
60 RANGE_SET_END(range, end);
61
62 if (CLASS_OF(range) == rb_cRange) {
63 rb_obj_freeze(range);
64 }
65}
66
67 VALUE
68 rb_range_new(VALUE beg, VALUE end, int exclude_end)
69{
70 VALUE range = rb_obj_alloc(rb_cRange);
71
72 range_init(range, beg, end, RBOOL(exclude_end));
73 return range;
74}
75
76static void
77range_modify(VALUE range)
78{
79 rb_check_frozen(range);
80 /* Ranges are immutable, so that they should be initialized only once. */
81 if (RANGE_EXCL(range) != Qnil) {
82 rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
83 }
84}
85
86/*
87 * call-seq:
88 * Range.new(begin, end, exclude_end=false) -> rng
89 *
90 * Constructs a range using the given +begin+ and +end+. If the +exclude_end+
91 * parameter is omitted or is <code>false</code>, the range will include
92 * the end object; otherwise, it will be excluded.
93 */
94
95static VALUE
96range_initialize(int argc, VALUE *argv, VALUE range)
97{
98 VALUE beg, end, flags;
99
100 rb_scan_args(argc, argv, "21", &beg, &end, &flags);
101 range_modify(range);
102 range_init(range, beg, end, RBOOL(RTEST(flags)));
103 return Qnil;
104}
105
106/* :nodoc: */
107static VALUE
108range_initialize_copy(VALUE range, VALUE orig)
109{
110 range_modify(range);
111 rb_struct_init_copy(range, orig);
112 return range;
113}
114
115/*
116 * call-seq:
117 * rng.exclude_end? -> true or false
118 *
119 * Returns <code>true</code> if the range excludes its end value.
120 *
121 * (1..5).exclude_end? #=> false
122 * (1...5).exclude_end? #=> true
123 */
124
125static VALUE
126range_exclude_end_p(VALUE range)
127{
128 return EXCL(range) ? Qtrue : Qfalse;
129}
130
131static VALUE
132recursive_equal(VALUE range, VALUE obj, int recur)
133{
134 if (recur) return Qtrue; /* Subtle! */
135 if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj)))
136 return Qfalse;
137 if (!rb_equal(RANGE_END(range), RANGE_END(obj)))
138 return Qfalse;
139
140 if (EXCL(range) != EXCL(obj))
141 return Qfalse;
142 return Qtrue;
143}
144
145
146/*
147 * call-seq:
148 * rng == obj -> true or false
149 *
150 * Returns <code>true</code> only if +obj+ is a Range, has equivalent
151 * begin and end items (by comparing them with <code>==</code>), and has
152 * the same #exclude_end? setting as the range.
153 *
154 * (0..2) == (0..2) #=> true
155 * (0..2) == Range.new(0,2) #=> true
156 * (0..2) == (0...2) #=> false
157 *
158 */
159
160static VALUE
161range_eq(VALUE range, VALUE obj)
162{
163 if (range == obj)
164 return Qtrue;
165 if (!rb_obj_is_kind_of(obj, rb_cRange))
166 return Qfalse;
167
168 return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
169}
170
171/* compares _a_ and _b_ and returns:
172 * < 0: a < b
173 * = 0: a = b
174 * > 0: a > b or non-comparable
175 */
176static int
177r_less(VALUE a, VALUE b)
178{
179 VALUE r = rb_funcall(a, id_cmp, 1, b);
180
181 if (NIL_P(r))
182 return INT_MAX;
183 return rb_cmpint(r, a, b);
184}
185
186static VALUE
187recursive_eql(VALUE range, VALUE obj, int recur)
188{
189 if (recur) return Qtrue; /* Subtle! */
190 if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj)))
191 return Qfalse;
192 if (!rb_eql(RANGE_END(range), RANGE_END(obj)))
193 return Qfalse;
194
195 if (EXCL(range) != EXCL(obj))
196 return Qfalse;
197 return Qtrue;
198}
199
200/*
201 * call-seq:
202 * rng.eql?(obj) -> true or false
203 *
204 * Returns <code>true</code> only if +obj+ is a Range, has equivalent
205 * begin and end items (by comparing them with <code>eql?</code>),
206 * and has the same #exclude_end? setting as the range.
207 *
208 * (0..2).eql?(0..2) #=> true
209 * (0..2).eql?(Range.new(0,2)) #=> true
210 * (0..2).eql?(0...2) #=> false
211 *
212 */
213
214static VALUE
215range_eql(VALUE range, VALUE obj)
216{
217 if (range == obj)
218 return Qtrue;
219 if (!rb_obj_is_kind_of(obj, rb_cRange))
220 return Qfalse;
221 return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
222}
223
224/*
225 * call-seq:
226 * rng.hash -> integer
227 *
228 * Compute a hash-code for this range. Two ranges with equal
229 * begin and end points (using <code>eql?</code>), and the same
230 * #exclude_end? value will generate the same hash-code.
231 *
232 * See also Object#hash.
233 */
234
235static VALUE
236range_hash(VALUE range)
237{
238 st_index_t hash = EXCL(range);
239 VALUE v;
240
241 hash = rb_hash_start(hash);
242 v = rb_hash(RANGE_BEG(range));
243 hash = rb_hash_uint(hash, NUM2LONG(v));
244 v = rb_hash(RANGE_END(range));
245 hash = rb_hash_uint(hash, NUM2LONG(v));
246 hash = rb_hash_uint(hash, EXCL(range) << 24);
247 hash = rb_hash_end(hash);
248
249 return ST2FIX(hash);
250}
251
252static void
253range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
254{
255 int c;
256 VALUE b = RANGE_BEG(range);
257 VALUE e = RANGE_END(range);
258 VALUE v = b;
259
260 if (EXCL(range)) {
261 while (r_less(v, e) < 0) {
262 if ((*func)(v, arg)) break;
263 v = rb_funcallv(v, id_succ, 0, 0);
264 }
265 }
266 else {
267 while ((c = r_less(v, e)) <= 0) {
268 if ((*func)(v, arg)) break;
269 if (!c) break;
270 v = rb_funcallv(v, id_succ, 0, 0);
271 }
272 }
273}
274
275static int
276sym_step_i(VALUE i, VALUE arg)
277{
278 VALUE *iter = (VALUE *)arg;
279
280 if (FIXNUM_P(iter[0])) {
281 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
282 }
283 else {
284 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
285 }
286 if (iter[0] == INT2FIX(0)) {
287 rb_yield(rb_str_intern(i));
288 iter[0] = iter[1];
289 }
290 return 0;
291}
292
293static int
294step_i(VALUE i, VALUE arg)
295{
296 VALUE *iter = (VALUE *)arg;
297
298 if (FIXNUM_P(iter[0])) {
299 iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
300 }
301 else {
302 iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
303 }
304 if (iter[0] == INT2FIX(0)) {
305 rb_yield(i);
306 iter[0] = iter[1];
307 }
308 return 0;
309}
310
311static int
312discrete_object_p(VALUE obj)
313{
314 if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE; /* until Time#succ removed */
315 return rb_respond_to(obj, id_succ);
316}
317
318static int
319linear_object_p(VALUE obj)
320{
321 if (FIXNUM_P(obj) || FLONUM_P(obj)) return TRUE;
322 if (SPECIAL_CONST_P(obj)) return FALSE;
323 switch (BUILTIN_TYPE(obj)) {
324 case T_FLOAT:
325 case T_BIGNUM:
326 return TRUE;
327 default:
328 break;
329 }
330 if (rb_obj_is_kind_of(obj, rb_cNumeric)) return TRUE;
331 if (rb_obj_is_kind_of(obj, rb_cTime)) return TRUE;
332 return FALSE;
333}
334
335static VALUE
336check_step_domain(VALUE step)
337{
338 VALUE zero = INT2FIX(0);
339 int cmp;
340 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
341 step = rb_to_int(step);
342 }
343 cmp = rb_cmpint(rb_funcallv(step, idCmp, 1, &zero), step, zero);
344 if (cmp < 0) {
345 rb_raise(rb_eArgError, "step can't be negative");
346 }
347 else if (cmp == 0) {
348 rb_raise(rb_eArgError, "step can't be 0");
349 }
350 return step;
351}
352
353static VALUE
354range_step_size(VALUE range, VALUE args, VALUE eobj)
355{
356 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
357 VALUE step = INT2FIX(1);
358 if (args) {
359 step = check_step_domain(RARRAY_AREF(args, 0));
360 }
361
362 if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
363 return ruby_num_interval_step_size(b, e, step, EXCL(range));
364 }
365 return Qnil;
366}
367
368/*
369 * Document-method: Range#step
370 * Document-method: Range#%
371 * call-seq:
372 * rng.step(n=1) {| obj | block } -> rng
373 * rng.step(n=1) -> an_enumerator
374 * rng.step(n=1) -> an_arithmetic_sequence
375 * rng % n -> an_enumerator
376 * rng % n -> an_arithmetic_sequence
377 *
378 * Iterates over the range, passing each <code>n</code>th element to the block.
379 * If begin and end are numeric, +n+ is added for each iteration.
380 * Otherwise #step invokes #succ to iterate through range elements.
381 *
382 * If no block is given, an enumerator is returned instead.
383 * Especially, the enumerator is an Enumerator::ArithmeticSequence
384 * if begin and end of the range are numeric.
385 *
386 * range = Xs.new(1)..Xs.new(10)
387 * range.step(2) {|x| puts x}
388 * puts
389 * range.step(3) {|x| puts x}
390 *
391 * <em>produces:</em>
392 *
393 * 1 x
394 * 3 xxx
395 * 5 xxxxx
396 * 7 xxxxxxx
397 * 9 xxxxxxxxx
398 *
399 * 1 x
400 * 4 xxxx
401 * 7 xxxxxxx
402 * 10 xxxxxxxxxx
403 *
404 * See Range for the definition of class Xs.
405 */
406
407
408static VALUE
409range_step(int argc, VALUE *argv, VALUE range)
410{
411 VALUE b, e, step, tmp;
412
413 b = RANGE_BEG(range);
414 e = RANGE_END(range);
415 step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);
416
417 if (!rb_block_given_p()) {
418 if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
419 step = rb_to_int(step);
420 }
421 if (rb_equal(step, INT2FIX(0))) {
422 rb_raise(rb_eArgError, "step can't be 0");
423 }
424
425 const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
426 const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
427 if ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p)) {
428 return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
429 range_step_size, b, e, step, EXCL(range));
430 }
431
432 RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
433 }
434
435 step = check_step_domain(step);
436
437 if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
438 long i = FIX2LONG(b), unit = FIX2LONG(step);
439 do {
440 rb_yield(LONG2FIX(i));
441 i += unit; /* FIXABLE+FIXABLE never overflow */
442 } while (FIXABLE(i));
443 b = LONG2NUM(i);
444
445 for (;; b = rb_big_plus(b, step))
446 rb_yield(b);
447 }
448 else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
449 long end = FIX2LONG(e);
450 long i, unit = FIX2LONG(step);
451
452 if (!EXCL(range))
453 end += 1;
454 i = FIX2LONG(b);
455 while (i < end) {
456 rb_yield(LONG2NUM(i));
457 if (i + unit < i) break;
458 i += unit;
459 }
460
461 }
462 else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
463 VALUE iter[2];
464 iter[0] = INT2FIX(1);
465 iter[1] = step;
466
467 b = rb_sym2str(b);
468 if (NIL_P(e)) {
469 rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
470 }
471 else {
472 rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
473 }
474 }
475 else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
476 /* done */
477 }
478 else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
479 !NIL_P(rb_check_to_integer(b, "to_int")) ||
480 !NIL_P(rb_check_to_integer(e, "to_int"))) {
481 ID op = EXCL(range) ? '<' : idLE;
482 VALUE v = b;
483 int i = 0;
484
485 while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
486 rb_yield(v);
487 i++;
488 v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
489 }
490 }
491 else {
492 tmp = rb_check_string_type(b);
493
494 if (!NIL_P(tmp)) {
495 VALUE iter[2];
496
497 b = tmp;
498 iter[0] = INT2FIX(1);
499 iter[1] = step;
500
501 if (NIL_P(e)) {
502 rb_str_upto_endless_each(b, step_i, (VALUE)iter);
503 }
504 else {
505 rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
506 }
507 }
508 else {
509 VALUE args[2];
510
511 if (!discrete_object_p(b)) {
512 rb_raise(rb_eTypeError, "can't iterate from %s",
513 rb_obj_classname(b));
514 }
515 args[0] = INT2FIX(1);
516 args[1] = step;
517 range_each_func(range, step_i, (VALUE)args);
518 }
519 }
520 return range;
521}
522
523static VALUE
524range_percent_step(VALUE range, VALUE step)
525{
526 return range_step(1, &step, range);
527}
528
529#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
530union int64_double {
531 int64_t i;
532 double d;
533};
534
535static VALUE
536int64_as_double_to_num(int64_t i)
537{
538 union int64_double convert;
539 if (i < 0) {
540 convert.i = -i;
541 return DBL2NUM(-convert.d);
542 }
543 else {
544 convert.i = i;
545 return DBL2NUM(convert.d);
546 }
547}
548
549static int64_t
550double_as_int64(double d)
551{
552 union int64_double convert;
553 convert.d = fabs(d);
554 return d < 0 ? -convert.i : convert.i;
555}
556#endif
557
558static int
559is_integer_p(VALUE v)
560{
561 ID id_integer_p;
562 VALUE is_int;
563 CONST_ID(id_integer_p, "integer?");
564 is_int = rb_check_funcall(v, id_integer_p, 0, 0);
565 return RTEST(is_int) && is_int != Qundef;
566}
567
568static VALUE
569bsearch_integer_range(VALUE beg, VALUE end, int excl)
570{
571 VALUE satisfied = Qnil;
572 int smaller;
573
574#define BSEARCH_CHECK(expr) \
575 do { \
576 VALUE val = (expr); \
577 VALUE v = rb_yield(val); \
578 if (FIXNUM_P(v)) { \
579 if (v == INT2FIX(0)) return val; \
580 smaller = (SIGNED_VALUE)v < 0; \
581 } \
582 else if (v == Qtrue) { \
583 satisfied = val; \
584 smaller = 1; \
585 } \
586 else if (v == Qfalse || v == Qnil) { \
587 smaller = 0; \
588 } \
589 else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
590 int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
591 if (!cmp) return val; \
592 smaller = cmp < 0; \
593 } \
594 else { \
595 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE \
596 " (must be numeric, true, false or nil)", \
597 rb_obj_class(v)); \
598 } \
599 } while (0)
600
601 VALUE low = rb_to_int(beg);
602 VALUE high = rb_to_int(end);
603 VALUE mid, org_high;
604 ID id_div;
605 CONST_ID(id_div, "div");
606
607 if (excl) high = rb_funcall(high, '-', 1, INT2FIX(1));
608 org_high = high;
609
610 while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
611 mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
612 BSEARCH_CHECK(mid);
613 if (smaller) {
614 high = mid;
615 }
616 else {
617 low = rb_funcall(mid, '+', 1, INT2FIX(1));
618 }
619 }
620 if (rb_equal(low, org_high)) {
621 BSEARCH_CHECK(low);
622 if (!smaller) return Qnil;
623 }
624 return satisfied;
625}
626
627/*
628 * call-seq:
629 * rng.bsearch {|obj| block } -> value
630 *
631 * By using binary search, finds a value in range which meets the given
632 * condition in O(log n) where n is the size of the range.
633 *
634 * You can use this method in two use cases: a find-minimum mode and
635 * a find-any mode. In either case, the elements of the range must be
636 * monotone (or sorted) with respect to the block.
637 *
638 * In find-minimum mode (this is a good choice for typical use case),
639 * the block must return true or false, and there must be a value x
640 * so that:
641 *
642 * - the block returns false for any value which is less than x, and
643 * - the block returns true for any value which is greater than or
644 * equal to x.
645 *
646 * If x is within the range, this method returns the value x.
647 * Otherwise, it returns nil.
648 *
649 * ary = [0, 4, 7, 10, 12]
650 * (0...ary.size).bsearch {|i| ary[i] >= 4 } #=> 1
651 * (0...ary.size).bsearch {|i| ary[i] >= 6 } #=> 2
652 * (0...ary.size).bsearch {|i| ary[i] >= 8 } #=> 3
653 * (0...ary.size).bsearch {|i| ary[i] >= 100 } #=> nil
654 *
655 * (0.0...Float::INFINITY).bsearch {|x| Math.log(x) >= 0 } #=> 1.0
656 *
657 * In find-any mode (this behaves like libc's bsearch(3)), the block
658 * must return a number, and there must be two values x and y (x <= y)
659 * so that:
660 *
661 * - the block returns a positive number for v if v < x,
662 * - the block returns zero for v if x <= v < y, and
663 * - the block returns a negative number for v if y <= v.
664 *
665 * This method returns any value which is within the intersection of
666 * the given range and x...y (if any). If there is no value that
667 * satisfies the condition, it returns nil.
668 *
669 * ary = [0, 100, 100, 100, 200]
670 * (0..4).bsearch {|i| 100 - ary[i] } #=> 1, 2 or 3
671 * (0..4).bsearch {|i| 300 - ary[i] } #=> nil
672 * (0..4).bsearch {|i| 50 - ary[i] } #=> nil
673 *
674 * You must not mix the two modes at a time; the block must always
675 * return either true/false, or always return a number. It is
676 * undefined which value is actually picked up at each iteration.
677 */
678
679static VALUE
680range_bsearch(VALUE range)
681{
682 VALUE beg, end, satisfied = Qnil;
683 int smaller;
684
685 /* Implementation notes:
686 * Floats are handled by mapping them to 64 bits integers.
687 * Apart from sign issues, floats and their 64 bits integer have the
688 * same order, assuming they are represented as exponent followed
689 * by the mantissa. This is true with or without implicit bit.
690 *
691 * Finding the average of two ints needs to be careful about
692 * potential overflow (since float to long can use 64 bits)
693 * as well as the fact that -1/2 can be 0 or -1 in C89.
694 *
695 * Note that -0.0 is mapped to the same int as 0.0 as we don't want
696 * (-1...0.0).bsearch to yield -0.0.
697 */
698
699#define BSEARCH(conv) \
700 do { \
701 RETURN_ENUMERATOR(range, 0, 0); \
702 if (EXCL(range)) high--; \
703 org_high = high; \
704 while (low < high) { \
705 mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
706 : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
707 BSEARCH_CHECK(conv(mid)); \
708 if (smaller) { \
709 high = mid; \
710 } \
711 else { \
712 low = mid + 1; \
713 } \
714 } \
715 if (low == org_high) { \
716 BSEARCH_CHECK(conv(low)); \
717 if (!smaller) return Qnil; \
718 } \
719 return satisfied; \
720 } while (0)
721
722
723 beg = RANGE_BEG(range);
724 end = RANGE_END(range);
725
726 if (FIXNUM_P(beg) && FIXNUM_P(end)) {
727 long low = FIX2LONG(beg);
728 long high = FIX2LONG(end);
729 long mid, org_high;
730 BSEARCH(INT2FIX);
731 }
732#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
733 else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
734 int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
735 int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
736 int64_t mid, org_high;
737 BSEARCH(int64_as_double_to_num);
738 }
739#endif
740 else if (is_integer_p(beg) && is_integer_p(end)) {
741 RETURN_ENUMERATOR(range, 0, 0);
742 return bsearch_integer_range(beg, end, EXCL(range));
743 }
744 else if (is_integer_p(beg) && NIL_P(end)) {
745 VALUE diff = LONG2FIX(1);
746 RETURN_ENUMERATOR(range, 0, 0);
747 while (1) {
748 VALUE mid = rb_funcall(beg, '+', 1, diff);
749 BSEARCH_CHECK(mid);
750 if (smaller) {
751 return bsearch_integer_range(beg, mid, 0);
752 }
753 diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
754 }
755 }
756 else if (NIL_P(beg) && is_integer_p(end)) {
757 VALUE diff = LONG2FIX(-1);
758 RETURN_ENUMERATOR(range, 0, 0);
759 while (1) {
760 VALUE mid = rb_funcall(end, '+', 1, diff);
761 BSEARCH_CHECK(mid);
762 if (!smaller) {
763 return bsearch_integer_range(mid, end, 0);
764 }
765 diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
766 }
767 }
768 else {
769 rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
770 }
771 return range;
772}
773
774static int
775each_i(VALUE v, VALUE arg)
776{
777 rb_yield(v);
778 return 0;
779}
780
781static int
782sym_each_i(VALUE v, VALUE arg)
783{
784 rb_yield(rb_str_intern(v));
785 return 0;
786}
787
788/*
789 * call-seq:
790 * rng.size -> num
791 *
792 * Returns the number of elements in the range. Both the begin and the end of
793 * the Range must be Numeric, otherwise nil is returned.
794 *
795 * (10..20).size #=> 11
796 * ('a'..'z').size #=> nil
797 * (-Float::INFINITY..Float::INFINITY).size #=> Infinity
798 */
799
800static VALUE
801range_size(VALUE range)
802{
803 VALUE b = RANGE_BEG(range), e = RANGE_END(range);
804 if (rb_obj_is_kind_of(b, rb_cNumeric)) {
805 if (rb_obj_is_kind_of(e, rb_cNumeric)) {
806 return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
807 }
808 if (NIL_P(e)) {
809 return DBL2NUM(HUGE_VAL);
810 }
811 }
812 else if (NIL_P(b)) {
813 return DBL2NUM(HUGE_VAL);
814 }
815
816 return Qnil;
817}
818
819/*
820 * call-seq:
821 * rng.to_a -> array
822 * rng.entries -> array
823 *
824 * Returns an array containing the items in the range.
825 *
826 * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
827 * (1..).to_a #=> RangeError: cannot convert endless range to an array
828 */
829
830static VALUE
831range_to_a(VALUE range)
832{
833 if (NIL_P(RANGE_END(range))) {
834 rb_raise(rb_eRangeError, "cannot convert endless range to an array");
835 }
836 return rb_call_super(0, 0);
837}
838
839static VALUE
840range_enum_size(VALUE range, VALUE args, VALUE eobj)
841{
842 return range_size(range);
843}
844
845 RBIMPL_ATTR_NORETURN()
846static void
847range_each_bignum_endless(VALUE beg)
848{
849 for (;; beg = rb_big_plus(beg, INT2FIX(1))) {
850 rb_yield(beg);
851 }
852 UNREACHABLE;
853}
854
855 RBIMPL_ATTR_NORETURN()
856static void
857range_each_fixnum_endless(VALUE beg)
858{
859 for (long i = FIX2LONG(beg); FIXABLE(i); i++) {
860 rb_yield(LONG2FIX(i));
861 }
862
863 range_each_bignum_endless(LONG2NUM(RUBY_FIXNUM_MAX + 1));
864 UNREACHABLE;
865}
866
867static VALUE
868range_each_fixnum_loop(VALUE beg, VALUE end, VALUE range)
869{
870 long lim = FIX2LONG(end) + !EXCL(range);
871 for (long i = FIX2LONG(beg); i < lim; i++) {
872 rb_yield(LONG2FIX(i));
873 }
874 return range;
875}
876
877/*
878 * call-seq:
879 * rng.each {| i | block } -> rng
880 * rng.each -> an_enumerator
881 *
882 * Iterates over the elements of range, passing each in turn to the
883 * block.
884 *
885 * The +each+ method can only be used if the begin object of the range
886 * supports the +succ+ method. A TypeError is raised if the object
887 * does not have +succ+ method defined (like Float).
888 *
889 * If no block is given, an enumerator is returned instead.
890 *
891 * (10..15).each {|n| print n, ' ' }
892 * # prints: 10 11 12 13 14 15
893 *
894 * (2.5..5).each {|n| print n, ' ' }
895 * # raises: TypeError: can't iterate from Float
896 */
897
898static VALUE
899range_each(VALUE range)
900{
901 VALUE beg, end;
902 long i;
903
904 RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
905
906 beg = RANGE_BEG(range);
907 end = RANGE_END(range);
908
909 if (FIXNUM_P(beg) && NIL_P(end)) {
910 range_each_fixnum_endless(beg);
911 }
912 else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
913 return range_each_fixnum_loop(beg, end, range);
914 }
915 else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) {
916 if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */
917 if (!FIXNUM_P(beg)) {
918 if (RBIGNUM_NEGATIVE_P(beg)) {
919 do {
920 rb_yield(beg);
921 } while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1))));
922 if (NIL_P(end)) range_each_fixnum_endless(beg);
923 if (FIXNUM_P(end)) return range_each_fixnum_loop(beg, end, range);
924 }
925 else {
926 if (NIL_P(end)) range_each_bignum_endless(beg);
927 if (FIXNUM_P(end)) return range;
928 }
929 }
930 if (FIXNUM_P(beg)) {
931 i = FIX2LONG(beg);
932 do {
933 rb_yield(LONG2FIX(i));
934 } while (POSFIXABLE(++i));
935 beg = LONG2NUM(i);
936 }
937 ASSUME(!FIXNUM_P(beg));
938 ASSUME(!SPECIAL_CONST_P(end));
939 }
940 if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) {
941 if (EXCL(range)) {
942 while (rb_big_cmp(beg, end) == INT2FIX(-1)) {
943 rb_yield(beg);
944 beg = rb_big_plus(beg, INT2FIX(1));
945 }
946 }
947 else {
948 VALUE c;
949 while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
950 rb_yield(beg);
951 if (c == INT2FIX(0)) break;
952 beg = rb_big_plus(beg, INT2FIX(1));
953 }
954 }
955 }
956 }
957 else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
958 beg = rb_sym2str(beg);
959 if (NIL_P(end)) {
960 rb_str_upto_endless_each(beg, sym_each_i, 0);
961 }
962 else {
963 rb_str_upto_each(beg, rb_sym2str(end), EXCL(range), sym_each_i, 0);
964 }
965 }
966 else {
967 VALUE tmp = rb_check_string_type(beg);
968
969 if (!NIL_P(tmp)) {
970 if (!NIL_P(end)) {
971 rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
972 }
973 else {
974 rb_str_upto_endless_each(tmp, each_i, 0);
975 }
976 }
977 else {
978 if (!discrete_object_p(beg)) {
979 rb_raise(rb_eTypeError, "can't iterate from %s",
980 rb_obj_classname(beg));
981 }
982 if (!NIL_P(end))
983 range_each_func(range, each_i, 0);
984 else
985 for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
986 rb_yield(beg);
987 }
988 }
989 return range;
990}
991
992/*
993 * call-seq:
994 * rng.begin -> obj
995 *
996 * Returns the object that defines the beginning of the range.
997 *
998 * (1..10).begin #=> 1
999 */
1000
1001static VALUE
1002range_begin(VALUE range)
1003{
1004 return RANGE_BEG(range);
1005}
1006
1007
1008/*
1009 * call-seq:
1010 * rng.end -> obj
1011 *
1012 * Returns the object that defines the end of the range.
1013 *
1014 * (1..10).end #=> 10
1015 * (1...10).end #=> 10
1016 */
1017
1018
1019static VALUE
1020range_end(VALUE range)
1021{
1022 return RANGE_END(range);
1023}
1024
1025
1026static VALUE
1027first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
1028{
1029 VALUE *ary = (VALUE *)cbarg;
1030 long n = NUM2LONG(ary[0]);
1031
1032 if (n <= 0) {
1033 rb_iter_break();
1034 }
1035 rb_ary_push(ary[1], i);
1036 n--;
1037 ary[0] = LONG2NUM(n);
1038 return Qnil;
1039}
1040
1041/*
1042 * call-seq:
1043 * rng.first -> obj
1044 * rng.first(n) -> an_array
1045 *
1046 * Returns the first object in the range, or an array of the first +n+
1047 * elements.
1048 *
1049 * (10..20).first #=> 10
1050 * (10..20).first(3) #=> [10, 11, 12]
1051 */
1052
1053static VALUE
1054range_first(int argc, VALUE *argv, VALUE range)
1055{
1056 VALUE n, ary[2];
1057
1058 if (NIL_P(RANGE_BEG(range))) {
1059 rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
1060 }
1061 if (argc == 0) return RANGE_BEG(range);
1062
1063 rb_scan_args(argc, argv, "1", &n);
1064 ary[0] = n;
1065 ary[1] = rb_ary_new2(NUM2LONG(n));
1066 rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
1067
1068 return ary[1];
1069}
1070
1071static VALUE
1072rb_int_range_last(int argc, VALUE *argv, VALUE range)
1073{
1074 static const VALUE ONE = INT2FIX(1);
1075
1076 VALUE b, e, len_1, len, nv, ary;
1077 int x;
1078 long n;
1079
1080 assert(argc > 0);
1081
1082 b = RANGE_BEG(range);
1083 e = RANGE_END(range);
1084 assert(RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e));
1085
1086 x = EXCL(range);
1087
1088 len_1 = rb_int_minus(e, b);
1089 if (FIXNUM_ZERO_P(len_1) || rb_num_negative_p(len_1)) {
1090 return rb_ary_new_capa(0);
1091 }
1092
1093 if (x) {
1094 e = rb_int_minus(e, ONE);
1095 len = len_1;
1096 }
1097 else {
1098 len = rb_int_plus(len_1, ONE);
1099 }
1100
1101 rb_scan_args(argc, argv, "1", &nv);
1102 n = NUM2LONG(nv);
1103 if (n < 0) {
1104 rb_raise(rb_eArgError, "negative array size");
1105 }
1106
1107 nv = LONG2NUM(n);
1108 if (RTEST(rb_int_gt(nv, len))) {
1109 nv = len;
1110 n = NUM2LONG(nv);
1111 }
1112
1113 ary = rb_ary_new_capa(n);
1114 b = rb_int_minus(e, nv);
1115 while (n) {
1116 b = rb_int_plus(b, ONE);
1117 rb_ary_push(ary, b);
1118 --n;
1119 }
1120
1121 return ary;
1122}
1123
1124/*
1125 * call-seq:
1126 * rng.last -> obj
1127 * rng.last(n) -> an_array
1128 *
1129 * Returns the last object in the range,
1130 * or an array of the last +n+ elements.
1131 *
1132 * Note that with no arguments +last+ will return the object that defines
1133 * the end of the range even if #exclude_end? is +true+.
1134 *
1135 * (10..20).last #=> 20
1136 * (10...20).last #=> 20
1137 * (10..20).last(3) #=> [18, 19, 20]
1138 * (10...20).last(3) #=> [17, 18, 19]
1139 */
1140
1141static VALUE
1142range_last(int argc, VALUE *argv, VALUE range)
1143{
1144 VALUE b, e;
1145
1146 if (NIL_P(RANGE_END(range))) {
1147 rb_raise(rb_eRangeError, "cannot get the last element of endless range");
1148 }
1149 if (argc == 0) return RANGE_END(range);
1150
1151 b = RANGE_BEG(range);
1152 e = RANGE_END(range);
1153 if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
1154 RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
1155 return rb_int_range_last(argc, argv, range);
1156 }
1157 return rb_ary_last(argc, argv, rb_Array(range));
1158}
1159
1160
1161/*
1162 * call-seq:
1163 * rng.min -> obj
1164 * rng.min {| a,b | block } -> obj
1165 * rng.min(n) -> array
1166 * rng.min(n) {| a,b | block } -> array
1167 *
1168 * Returns the minimum value in the range. Returns +nil+ if the begin
1169 * value of the range is larger than the end value. Returns +nil+ if
1170 * the begin value of an exclusive range is equal to the end value.
1171 *
1172 * Can be given an optional block to override the default comparison
1173 * method <code>a <=> b</code>.
1174 *
1175 * (10..20).min #=> 10
1176 */
1177
1178
1179static VALUE
1180range_min(int argc, VALUE *argv, VALUE range)
1181{
1182 if (NIL_P(RANGE_BEG(range))) {
1183 rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
1184 }
1185
1186 if (rb_block_given_p()) {
1187 if (NIL_P(RANGE_END(range))) {
1188 rb_raise(rb_eRangeError, "cannot get the minimum of endless range with custom comparison method");
1189 }
1190 return rb_call_super(argc, argv);
1191 }
1192 else if (argc != 0) {
1193 return range_first(argc, argv, range);
1194 }
1195 else {
1196 struct cmp_opt_data cmp_opt = { 0, 0 };
1197 VALUE b = RANGE_BEG(range);
1198 VALUE e = RANGE_END(range);
1199 int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
1200
1201 if (c > 0 || (c == 0 && EXCL(range)))
1202 return Qnil;
1203 return b;
1204 }
1205}
1206
1207/*
1208 * call-seq:
1209 * rng.max -> obj
1210 * rng.max {| a,b | block } -> obj
1211 * rng.max(n) -> obj
1212 * rng.max(n) {| a,b | block } -> obj
1213 *
1214 * Returns the maximum value in the range, or an array of maximum
1215 * values in the range if given an \Integer argument.
1216 *
1217 * For inclusive ranges with an end, the maximum value of the range
1218 * is the same as the end of the range.
1219 *
1220 * If an argument or block is given, or +self+ is an exclusive,
1221 * non-numeric range, calls Enumerable#max (via +super+) with the
1222 * argument and/or block to get the maximum values, unless +self+ is
1223 * a beginless range, in which case it raises a RangeError.
1224 *
1225 * If +self+ is an exclusive, integer range (both start and end of the
1226 * range are integers), and no arguments or block are provided, returns
1227 * last value in the range (1 before the end). Otherwise, if +self+ is
1228 * an exclusive, numeric range, raises a TypeError.
1229 *
1230 * Returns +nil+ if the begin value of the range larger than the
1231 * end value. Returns +nil+ if the begin value of an exclusive
1232 * range is equal to the end value. Raises a RangeError if called on
1233 * an endless range.
1234 *
1235 * Examples:
1236 * (10..20).max #=> 20
1237 * (10..20).max(2) #=> [20, 19]
1238 * (10...20).max #=> 19
1239 * (10...20).max(2) #=> [19, 18]
1240 * (10...20).max{|x, y| -x <=> -y } #=> 10
1241 * (10...20).max(2){|x, y| -x <=> -y } #=> [10, 11]
1242 */
1243
1244static VALUE
1245range_max(int argc, VALUE *argv, VALUE range)
1246{
1247 VALUE e = RANGE_END(range);
1248 int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
1249
1250 if (NIL_P(RANGE_END(range))) {
1251 rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
1252 }
1253
1254 VALUE b = RANGE_BEG(range);
1255
1256 if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
1257 if (NIL_P(b)) {
1258 rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
1259 }
1260 return rb_call_super(argc, argv);
1261 }
1262 else {
1263 struct cmp_opt_data cmp_opt = { 0, 0 };
1264 int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
1265
1266 if (c > 0)
1267 return Qnil;
1268 if (EXCL(range)) {
1269 if (!RB_INTEGER_TYPE_P(e)) {
1270 rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
1271 }
1272 if (c == 0) return Qnil;
1273 if (!RB_INTEGER_TYPE_P(b)) {
1274 rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
1275 }
1276 if (FIXNUM_P(e)) {
1277 return LONG2NUM(FIX2LONG(e) - 1);
1278 }
1279 return rb_funcall(e, '-', 1, INT2FIX(1));
1280 }
1281 return e;
1282 }
1283}
1284
1285/*
1286 * call-seq:
1287 * rng.minmax -> [obj, obj]
1288 * rng.minmax {| a,b | block } -> [obj, obj]
1289 *
1290 * Returns a two element array which contains the minimum and the
1291 * maximum value in the range.
1292 *
1293 * Can be given an optional block to override the default comparison
1294 * method <code>a <=> b</code>.
1295 */
1296
1297static VALUE
1298range_minmax(VALUE range)
1299{
1300 if (rb_block_given_p()) {
1301 return rb_call_super(0, NULL);
1302 }
1303 return rb_assoc_new(
1304 rb_funcall(range, id_min, 0),
1305 rb_funcall(range, id_max, 0)
1306 );
1307}
1308
1309int
1310 rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
1311{
1312 VALUE b, e;
1313 int excl;
1314
1315 if (rb_obj_is_kind_of(range, rb_cRange)) {
1316 b = RANGE_BEG(range);
1317 e = RANGE_END(range);
1318 excl = EXCL(range);
1319 }
1320 else if (RTEST(rb_obj_is_kind_of(range, rb_cArithSeq))) {
1321 return (int)Qfalse;
1322 }
1323 else {
1324 VALUE x;
1325 b = rb_check_funcall(range, id_beg, 0, 0);
1326 if (b == Qundef) return (int)Qfalse;
1327 e = rb_check_funcall(range, id_end, 0, 0);
1328 if (e == Qundef) return (int)Qfalse;
1329 x = rb_check_funcall(range, rb_intern("exclude_end?"), 0, 0);
1330 if (x == Qundef) return (int)Qfalse;
1331 excl = RTEST(x);
1332 }
1333 *begp = b;
1334 *endp = e;
1335 *exclp = excl;
1336 return (int)Qtrue;
1337}
1338
1339/* Extract the components of a Range.
1340 *
1341 * You can use +err+ to control the behavior of out-of-range and exception.
1342 *
1343 * When +err+ is 0 or 2, if the begin offset is greater than +len+,
1344 * it is out-of-range. The +RangeError+ is raised only if +err+ is 2,
1345 * in this case. If +err+ is 0, +Qnil+ will be returned.
1346 *
1347 * When +err+ is 1, the begin and end offsets won't be adjusted even if they
1348 * are greater than +len+. It allows +rb_ary_aset+ extends arrays.
1349 *
1350 * If the begin component of the given range is negative and is too-large
1351 * abstract value, the +RangeError+ is raised only +err+ is 1 or 2.
1352 *
1353 * The case of <code>err = 0</code> is used in item accessing methods such as
1354 * +rb_ary_aref+, +rb_ary_slice_bang+, and +rb_str_aref+.
1355 *
1356 * The case of <code>err = 1</code> is used in Array's methods such as
1357 * +rb_ary_aset+ and +rb_ary_fill+.
1358 *
1359 * The case of <code>err = 2</code> is used in +rb_str_aset+.
1360 */
1361 VALUE
1362 rb_range_component_beg_len(VALUE b, VALUE e, int excl,
1363 long *begp, long *lenp, long len, int err)
1364{
1365 long beg, end;
1366
1367 beg = NIL_P(b) ? 0 : NUM2LONG(b);
1368 end = NIL_P(e) ? -1 : NUM2LONG(e);
1369 if (NIL_P(e)) excl = 0;
1370 if (beg < 0) {
1371 beg += len;
1372 if (beg < 0)
1373 goto out_of_range;
1374 }
1375 if (end < 0)
1376 end += len;
1377 if (!excl)
1378 end++; /* include end point */
1379 if (err == 0 || err == 2) {
1380 if (beg > len)
1381 goto out_of_range;
1382 if (end > len)
1383 end = len;
1384 }
1385 len = end - beg;
1386 if (len < 0)
1387 len = 0;
1388
1389 *begp = beg;
1390 *lenp = len;
1391 return Qtrue;
1392
1393 out_of_range:
1394 return Qnil;
1395}
1396
1397 VALUE
1398 rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
1399{
1400 VALUE b, e;
1401 int excl;
1402
1403 if (!rb_range_values(range, &b, &e, &excl))
1404 return Qfalse;
1405
1406 VALUE res = rb_range_component_beg_len(b, e, excl, begp, lenp, len, err);
1407 if (NIL_P(res) && err) {
1408 rb_raise(rb_eRangeError, "%+"PRIsVALUE" out of range", range);
1409 }
1410
1411 return res;
1412}
1413
1414/*
1415 * call-seq:
1416 * rng.to_s -> string
1417 *
1418 * Convert this range object to a printable form (using #to_s to convert the
1419 * begin and end objects).
1420 */
1421
1422static VALUE
1423range_to_s(VALUE range)
1424{
1425 VALUE str, str2;
1426
1427 str = rb_obj_as_string(RANGE_BEG(range));
1428 str2 = rb_obj_as_string(RANGE_END(range));
1429 str = rb_str_dup(str);
1430 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
1431 rb_str_append(str, str2);
1432
1433 return str;
1434}
1435
1436static VALUE
1437inspect_range(VALUE range, VALUE dummy, int recur)
1438{
1439 VALUE str, str2 = Qundef;
1440
1441 if (recur) {
1442 return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
1443 }
1444 if (!NIL_P(RANGE_BEG(range)) || NIL_P(RANGE_END(range))) {
1445 str = rb_str_dup(rb_inspect(RANGE_BEG(range)));
1446 }
1447 else {
1448 str = rb_str_new(0, 0);
1449 }
1450 rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
1451 if (NIL_P(RANGE_BEG(range)) || !NIL_P(RANGE_END(range))) {
1452 str2 = rb_inspect(RANGE_END(range));
1453 }
1454 if (str2 != Qundef) rb_str_append(str, str2);
1455
1456 return str;
1457}
1458
1459/*
1460 * call-seq:
1461 * rng.inspect -> string
1462 *
1463 * Convert this range object to a printable form (using #inspect to
1464 * convert the begin and end objects).
1465 */
1466
1467
1468static VALUE
1469range_inspect(VALUE range)
1470{
1471 return rb_exec_recursive(inspect_range, range, 0);
1472}
1473
1474static VALUE range_include_internal(VALUE range, VALUE val, int string_use_cover);
1475
1476/*
1477 * call-seq:
1478 * rng === obj -> true or false
1479 *
1480 * Returns <code>true</code> if +obj+ is between begin and end of range,
1481 * <code>false</code> otherwise (same as #cover?). Conveniently,
1482 * <code>===</code> is the comparison operator used by <code>case</code>
1483 * statements.
1484 *
1485 * case 79
1486 * when 1..50 then puts "low"
1487 * when 51..75 then puts "medium"
1488 * when 76..100 then puts "high"
1489 * end
1490 * # Prints "high"
1491 *
1492 * case "2.6.5"
1493 * when ..."2.4" then puts "EOL"
1494 * when "2.4"..."2.5" then puts "maintenance"
1495 * when "2.5"..."2.7" then puts "stable"
1496 * when "2.7".. then puts "upcoming"
1497 * end
1498 * # Prints "stable"
1499 *
1500 */
1501
1502static VALUE
1503range_eqq(VALUE range, VALUE val)
1504{
1505 VALUE ret = range_include_internal(range, val, 1);
1506 if (ret != Qundef) return ret;
1507 return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
1508}
1509
1510
1511/*
1512 * call-seq:
1513 * rng.member?(obj) -> true or false
1514 * rng.include?(obj) -> true or false
1515 *
1516 * Returns <code>true</code> if +obj+ is an element of
1517 * the range, <code>false</code> otherwise.
1518 *
1519 * ("a".."z").include?("g") #=> true
1520 * ("a".."z").include?("A") #=> false
1521 * ("a".."z").include?("cc") #=> false
1522 *
1523 * If you need to ensure +obj+ is between +begin+ and +end+, use #cover?
1524 *
1525 * ("a".."z").cover?("cc") #=> true
1526 *
1527 * If begin and end are numeric, #include? behaves like #cover?
1528 *
1529 * (1..3).include?(1.5) # => true
1530 */
1531
1532static VALUE
1533range_include(VALUE range, VALUE val)
1534{
1535 VALUE ret = range_include_internal(range, val, 0);
1536 if (ret != Qundef) return ret;
1537 return rb_call_super(1, &val);
1538}
1539
1540static VALUE
1541range_include_internal(VALUE range, VALUE val, int string_use_cover)
1542{
1543 VALUE beg = RANGE_BEG(range);
1544 VALUE end = RANGE_END(range);
1545 int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
1546 linear_object_p(beg) || linear_object_p(end);
1547
1548 if (nv ||
1549 !NIL_P(rb_check_to_integer(beg, "to_int")) ||
1550 !NIL_P(rb_check_to_integer(end, "to_int"))) {
1551 return r_cover_p(range, beg, end, val);
1552 }
1553 else if (RB_TYPE_P(beg, T_STRING) || RB_TYPE_P(end, T_STRING)) {
1554 if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) {
1555 if (string_use_cover) {
1556 return r_cover_p(range, beg, end, val);
1557 }
1558 else {
1559 VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
1560 return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range));
1561 }
1562 }
1563 else if (NIL_P(beg)) {
1564 VALUE r = rb_funcall(val, id_cmp, 1, end);
1565 if (NIL_P(r)) return Qfalse;
1566 if (rb_cmpint(r, val, end) <= 0) return Qtrue;
1567 return Qfalse;
1568 }
1569 else if (NIL_P(end)) {
1570 VALUE r = rb_funcall(beg, id_cmp, 1, val);
1571 if (NIL_P(r)) return Qfalse;
1572 if (rb_cmpint(r, beg, val) <= 0) return Qtrue;
1573 return Qfalse;
1574 }
1575 }
1576 return Qundef;
1577}
1578
1579static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
1580
1581/*
1582 * call-seq:
1583 * rng.cover?(obj) -> true or false
1584 * rng.cover?(range) -> true or false
1585 *
1586 * Returns <code>true</code> if +obj+ is between the begin and end of
1587 * the range.
1588 *
1589 * This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
1590 * and <code>begin <= obj < end</code> when #exclude_end? is +true+.
1591 *
1592 * If called with a Range argument, returns <code>true</code> when the
1593 * given range is covered by the receiver,
1594 * by comparing the begin and end values. If the argument can be treated as
1595 * a sequence, this method treats it that way. In the specific case of
1596 * <code>(a..b).cover?(c...d)</code> with <code>a <= c && b < d</code>,
1597 * the end of the sequence must be calculated, which may exhibit poor
1598 * performance if <code>c</code> is non-numeric.
1599 * Returns <code>false</code> if the begin value of the
1600 * range is larger than the end value. Also returns +false+ if one of the
1601 * internal calls to <code><=></code> returns +nil+ (indicating the objects
1602 * are not comparable).
1603 *
1604 * ("a".."z").cover?("c") #=> true
1605 * ("a".."z").cover?("5") #=> false
1606 * ("a".."z").cover?("cc") #=> true
1607 * ("a".."z").cover?(1) #=> false
1608 * (1..5).cover?(2..3) #=> true
1609 * (1..5).cover?(0..6) #=> false
1610 * (1..5).cover?(1...6) #=> true
1611 */
1612
1613static VALUE
1614range_cover(VALUE range, VALUE val)
1615{
1616 VALUE beg, end;
1617
1618 beg = RANGE_BEG(range);
1619 end = RANGE_END(range);
1620
1621 if (rb_obj_is_kind_of(val, rb_cRange)) {
1622 return RBOOL(r_cover_range_p(range, beg, end, val));
1623 }
1624 return r_cover_p(range, beg, end, val);
1625}
1626
1627static VALUE
1628r_call_max(VALUE r)
1629{
1630 return rb_funcallv(r, rb_intern("max"), 0, 0);
1631}
1632
1633static int
1634r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val)
1635{
1636 VALUE val_beg, val_end, val_max;
1637 int cmp_end;
1638
1639 val_beg = RANGE_BEG(val);
1640 val_end = RANGE_END(val);
1641
1642 if (!NIL_P(end) && NIL_P(val_end)) return FALSE;
1643 if (!NIL_P(beg) && NIL_P(val_beg)) return FALSE;
1644 if (!NIL_P(val_beg) && !NIL_P(val_end) && r_less(val_beg, val_end) > (EXCL(val) ? -1 : 0)) return FALSE;
1645 if (!NIL_P(val_beg) && !r_cover_p(range, beg, end, val_beg)) return FALSE;
1646
1647 cmp_end = r_less(end, val_end);
1648
1649 if (EXCL(range) == EXCL(val)) {
1650 return cmp_end >= 0;
1651 }
1652 else if (EXCL(range)) {
1653 return cmp_end > 0;
1654 }
1655 else if (cmp_end >= 0) {
1656 return TRUE;
1657 }
1658
1659 val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
1660 if (val_max == Qnil) return FALSE;
1661
1662 return r_less(end, val_max) >= 0;
1663}
1664
1665static VALUE
1666r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
1667{
1668 if (NIL_P(beg) || r_less(beg, val) <= 0) {
1669 int excl = EXCL(range);
1670 if (NIL_P(end) || r_less(val, end) <= -excl)
1671 return Qtrue;
1672 }
1673 return Qfalse;
1674}
1675
1676static VALUE
1677range_dumper(VALUE range)
1678{
1679 VALUE v = rb_obj_alloc(rb_cObject);
1680
1681 rb_ivar_set(v, id_excl, RANGE_EXCL(range));
1682 rb_ivar_set(v, id_beg, RANGE_BEG(range));
1683 rb_ivar_set(v, id_end, RANGE_END(range));
1684 return v;
1685}
1686
1687static VALUE
1688range_loader(VALUE range, VALUE obj)
1689{
1690 VALUE beg, end, excl;
1691
1692 if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
1693 rb_raise(rb_eTypeError, "not a dumped range object");
1694 }
1695
1696 range_modify(range);
1697 beg = rb_ivar_get(obj, id_beg);
1698 end = rb_ivar_get(obj, id_end);
1699 excl = rb_ivar_get(obj, id_excl);
1700 if (!NIL_P(excl)) {
1701 range_init(range, beg, end, RBOOL(RTEST(excl)));
1702 }
1703 return range;
1704}
1705
1706static VALUE
1707range_alloc(VALUE klass)
1708{
1709 /* rb_struct_alloc_noinit itself should not be used because
1710 * rb_marshal_define_compat uses equality of allocation function */
1711 return rb_struct_alloc_noinit(klass);
1712}
1713
1714/*
1715 * call-seq:
1716 * range.count -> int
1717 * range.count(item) -> int
1718 * range.count { |obj| block } -> int
1719 *
1720 * Identical to Enumerable#count, except it returns Infinity for endless
1721 * ranges.
1722 *
1723 */
1724static VALUE
1725range_count(int argc, VALUE *argv, VALUE range)
1726{
1727 if (argc != 0) {
1728 /* It is odd for instance (1...).count(0) to return Infinity. Just let
1729 * it loop. */
1730 return rb_call_super(argc, argv);
1731 }
1732 else if (rb_block_given_p()) {
1733 /* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
1734 * Infinity. Just let it loop. */
1735 return rb_call_super(argc, argv);
1736 }
1737 else if (NIL_P(RANGE_END(range))) {
1738 /* We are confident that the answer is Infinity. */
1739 return DBL2NUM(HUGE_VAL);
1740 }
1741 else if (NIL_P(RANGE_BEG(range))) {
1742 /* We are confident that the answer is Infinity. */
1743 return DBL2NUM(HUGE_VAL);
1744 }
1745 else {
1746 return rb_call_super(argc, argv);
1747 }
1748}
1749
1750/* A Range represents an interval---a set of values with a
1751 * beginning and an end. Ranges may be constructed using the
1752 * <em>s</em><code>..</code><em>e</em> and
1753 * <em>s</em><code>...</code><em>e</em> literals, or with
1754 * Range::new. Ranges constructed using <code>..</code>
1755 * run from the beginning to the end inclusively. Those created using
1756 * <code>...</code> exclude the end value. When used as an iterator,
1757 * ranges return each value in the sequence.
1758 *
1759 * (-1..-5).to_a #=> []
1760 * (-5..-1).to_a #=> [-5, -4, -3, -2, -1]
1761 * ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
1762 * ('a'...'e').to_a #=> ["a", "b", "c", "d"]
1763 *
1764 * == Beginless/Endless Ranges
1765 *
1766 * A "beginless range" and "endless range" represents a semi-infinite
1767 * range. Literal notation for a beginless range is:
1768 *
1769 * (..1)
1770 * # or
1771 * (...1)
1772 *
1773 * Literal notation for an endless range is:
1774 *
1775 * (1..)
1776 * # or similarly
1777 * (1...)
1778 *
1779 * Which is equivalent to
1780 *
1781 * (1..nil) # or similarly (1...nil)
1782 * Range.new(1, nil) # or Range.new(1, nil, true)
1783 *
1784 * Beginless/endless ranges are useful, for example, for idiomatic
1785 * slicing of arrays:
1786 *
1787 * [1, 2, 3, 4, 5][...2] # => [1, 2]
1788 * [1, 2, 3, 4, 5][2...] # => [3, 4, 5]
1789 *
1790 * Some implementation details:
1791 *
1792 * * +begin+ of beginless range and +end+ of endless range are +nil+;
1793 * * +each+ of beginless range raises an exception;
1794 * * +each+ of endless range enumerates infinite sequence (may be
1795 * useful in combination with Enumerable#take_while or similar
1796 * methods);
1797 * * <code>(1..)</code> and <code>(1...)</code> are not equal,
1798 * although technically representing the same sequence.
1799 *
1800 * == Custom Objects in Ranges
1801 *
1802 * Ranges can be constructed using any objects that can be compared
1803 * using the <code><=></code> operator.
1804 * Methods that treat the range as a sequence (#each and methods inherited
1805 * from Enumerable) expect the begin object to implement a
1806 * <code>succ</code> method to return the next object in sequence.
1807 * The #step and #include? methods require the begin
1808 * object to implement <code>succ</code> or to be numeric.
1809 *
1810 * In the <code>Xs</code> class below both <code><=></code> and
1811 * <code>succ</code> are implemented so <code>Xs</code> can be used
1812 * to construct ranges. Note that the Comparable module is included
1813 * so the <code>==</code> method is defined in terms of <code><=></code>.
1814 *
1815 * class Xs # represent a string of 'x's
1816 * include Comparable
1817 * attr :length
1818 * def initialize(n)
1819 * @length = n
1820 * end
1821 * def succ
1822 * Xs.new(@length + 1)
1823 * end
1824 * def <=>(other)
1825 * @length <=> other.length
1826 * end
1827 * def to_s
1828 * sprintf "%2d #{inspect}", @length
1829 * end
1830 * def inspect
1831 * 'x' * @length
1832 * end
1833 * end
1834 *
1835 * An example of using <code>Xs</code> to construct a range:
1836 *
1837 * r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx
1838 * r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx]
1839 * r.member?(Xs.new(5)) #=> true
1840 *
1841 */
1842
1843void
1844Init_Range(void)
1845{
1846 id_beg = rb_intern_const("begin");
1847 id_end = rb_intern_const("end");
1848 id_excl = rb_intern_const("excl");
1849
1850 rb_cRange = rb_struct_define_without_accessor(
1851 "Range", rb_cObject, range_alloc,
1852 "begin", "end", "excl", NULL);
1853
1854 rb_include_module(rb_cRange, rb_mEnumerable);
1855 rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
1856 rb_define_method(rb_cRange, "initialize", range_initialize, -1);
1857 rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
1858 rb_define_method(rb_cRange, "==", range_eq, 1);
1859 rb_define_method(rb_cRange, "===", range_eqq, 1);
1860 rb_define_method(rb_cRange, "eql?", range_eql, 1);
1861 rb_define_method(rb_cRange, "hash", range_hash, 0);
1862 rb_define_method(rb_cRange, "each", range_each, 0);
1863 rb_define_method(rb_cRange, "step", range_step, -1);
1864 rb_define_method(rb_cRange, "%", range_percent_step, 1);
1865 rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
1866 rb_define_method(rb_cRange, "begin", range_begin, 0);
1867 rb_define_method(rb_cRange, "end", range_end, 0);
1868 rb_define_method(rb_cRange, "first", range_first, -1);
1869 rb_define_method(rb_cRange, "last", range_last, -1);
1870 rb_define_method(rb_cRange, "min", range_min, -1);
1871 rb_define_method(rb_cRange, "max", range_max, -1);
1872 rb_define_method(rb_cRange, "minmax", range_minmax, 0);
1873 rb_define_method(rb_cRange, "size", range_size, 0);
1874 rb_define_method(rb_cRange, "to_a", range_to_a, 0);
1875 rb_define_method(rb_cRange, "entries", range_to_a, 0);
1876 rb_define_method(rb_cRange, "to_s", range_to_s, 0);
1877 rb_define_method(rb_cRange, "inspect", range_inspect, 0);
1878
1879 rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
1880
1881 rb_define_method(rb_cRange, "member?", range_include, 1);
1882 rb_define_method(rb_cRange, "include?", range_include, 1);
1883 rb_define_method(rb_cRange, "cover?", range_cover, 1);
1884 rb_define_method(rb_cRange, "count", range_count, -1);
1885}
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_last
VALUE rb_ary_last(int argc, const VALUE *argv, VALUE ary)
Definition: array.c:1932
rb_ary_new_capa
VALUE rb_ary_new_capa(long capa)
Definition: array.c:743
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
assert.h
RB_LIKELY
#define RB_LIKELY(x)
Definition: assume.h:39
UNREACHABLE
#define UNREACHABLE
Definition: assume.h:30
ASSUME
#define ASSUME
Definition: assume.h:29
rb_big_plus
VALUE rb_big_plus(VALUE x, VALUE y)
Definition: bignum.c:5821
rb_big_cmp
VALUE rb_big_cmp(VALUE x, VALUE y)
Definition: bignum.c:5416
ONE
#define ONE
Definition: complex.c:32
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
range
#define range(low, item, hi)
Definition: date_strftime.c:21
recur
#define recur(fmt)
Definition: date_strptime.c:152
assert
#define assert(x)
Definition: dlmalloc.c:1176
RFLOAT_VALUE
#define RFLOAT_VALUE
Definition: double.h:28
DBL2NUM
#define DBL2NUM
Definition: double.h:29
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:27
rb_cmpint
#define rb_cmpint(cmp, a, b)
id_div
#define id_div
Definition: enum.c:31
rb_cArithSeq
VALUE rb_cArithSeq
Definition: enumerator.c:197
rb_arith_seq_new
VALUE rb_arith_seq_new(VALUE obj, VALUE meth, int argc, VALUE const *argv, rb_enumerator_size_func *size_fn, VALUE beg, VALUE end, VALUE step, int excl)
Definition: enumerator.c:3327
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_cTime
VALUE rb_cTime
Definition: time.c:645
CLASS_OF
#define CLASS_OF
Definition: globals.h:153
rb_cNumeric
VALUE rb_cNumeric
Definition: numeric.c:189
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:962
rb_frame_this_func
ID rb_frame_this_func(void)
The original name of the current method.
Definition: eval.c:1216
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_rescue2
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition: eval.c:991
rb_eRangeError
VALUE rb_eRangeError
Definition: error.c:1061
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:1057
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_Float
VALUE rb_Float(VALUE)
Equivalent to Kernel#Float in Ruby.
Definition: object.c:3531
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Allocates an instance of klass.
Definition: object.c:1900
rb_eql
int rb_eql(VALUE, VALUE)
Determines if obj1 and obj2 are equal in terms of Object::eql?.
Definition: object.c:180
rb_Array
VALUE rb_Array(VALUE)
Equivalent to Kernel#Array in Ruby.
Definition: object.c:3705
rb_inspect
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:585
rb_equal
VALUE rb_equal(VALUE, VALUE)
This function is an optimized version of calling #==.
Definition: object.c:157
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:724
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1101
rb_check_to_integer
VALUE rb_check_to_integer(VALUE, const char *)
Tries to convert val into Integer.
Definition: object.c:3029
rb_to_int
VALUE rb_to_int(VALUE)
Converts val into Integer.
Definition: object.c:3051
rb_hash
VALUE rb_hash(VALUE obj)
Definition: hash.c:143
id.h
idCmp
@ idCmp
Definition: id.h:84
idLE
@ idLE
Definition: id.h:93
FIXABLE
#define FIXABLE
Definition: fixnum.h:25
RUBY_FIXNUM_MAX
#define RUBY_FIXNUM_MAX
Definition: fixnum.h:41
POSFIXABLE
#define POSFIXABLE
Definition: fixnum.h:29
config.h
Thin wrapper to ruby/config.h.
rb_iter_break
void rb_iter_break(void)
Definition: vm.c:1786
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
rb_call_super
VALUE rb_call_super(int, const VALUE *)
Definition: vm_eval.c:298
rb_ary_new2
#define rb_ary_new2
Definition: array.h:72
RETURN_SIZED_ENUMERATOR
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
Definition: enumerator.h:64
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: enumerator.h:74
rb_check_frozen
#define rb_check_frozen
Definition: error.h:72
rb_check_arity
#define rb_check_arity
Definition: error.h:34
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_hash_uint
#define rb_hash_uint(h, i)
Definition: string.h:117
rb_hash_end
#define rb_hash_end(h)
Definition: string.h:118
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_str_cat
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2962
rb_hash_start
st_index_t rb_hash_start(st_index_t)
Definition: random.c:1623
rb_check_string_type
VALUE rb_check_string_type(VALUE)
Definition: string.c:2462
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
rb_str_intern
VALUE rb_str_intern(VALUE)
Definition: symbol.c:840
rb_obj_as_string
VALUE rb_obj_as_string(VALUE)
Definition: string.c:1529
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
rb_struct_alloc_noinit
VALUE rb_struct_alloc_noinit(VALUE)
Definition: struct.c:381
rb_struct_define_without_accessor
VALUE rb_struct_define_without_accessor(const char *, VALUE, rb_alloc_func_t,...)
Definition: struct.c:451
rb_exec_recursive_paired
VALUE rb_exec_recursive_paired(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE, VALUE)
Definition: thread.c:5371
rb_exec_recursive
VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int), VALUE, VALUE)
Definition: thread.c:5360
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1234
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
rb_check_funcall
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:619
rb_respond_to
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:2561
ID2SYM
#define ID2SYM
Definition: symbol.h:44
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
CONST_ID
#define CONST_ID
Definition: symbol.h:47
HUGE_VAL
#define HUGE_VAL
Definition: missing.h:156
INT2NUM
#define INT2NUM
Definition: int.h:43
array.h
Internal header for Array.
compar.h
Internal header for Comparable.
OPTIMIZED_CMP
#define OPTIMIZED_CMP(a, b, data)
Definition: compar.h:38
enum.h
Internal header for Enumerable.
enumerator.h
Internal header for Enumerator.
numeric.h
Internal header for Numeric.
rb_num_negative_p
int rb_num_negative_p(VALUE)
Definition: numeric.c:319
ruby_num_interval_step_size
VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl)
Definition: numeric.c:2597
ruby_float_step
int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless)
Definition: numeric.c:2566
rb_int_minus
VALUE rb_int_minus(VALUE x, VALUE y)
Definition: numeric.c:3636
rb_int_plus
VALUE rb_int_plus(VALUE x, VALUE y)
Definition: numeric.c:3597
rb_int_gt
VALUE rb_int_gt(VALUE x, VALUE y)
Definition: numeric.c:4236
range.h
Internal header for Range.
rb_str_upto_each
VALUE rb_str_upto_each(VALUE, VALUE, int, int(*each)(VALUE, VALUE), VALUE)
Definition: string.c:4483
rb_str_upto_endless_each
VALUE rb_str_upto_endless_each(VALUE, int(*each)(VALUE, VALUE), VALUE)
Definition: string.c:4565
rb_struct_init_copy
VALUE rb_struct_init_copy(VALUE copy, VALUE s)
Definition: struct.c:1010
internal.h
rb_funcallv
#define rb_funcallv(...)
Definition: internal.h:77
rb_method_basic_definition_p
#define rb_method_basic_definition_p(...)
Definition: internal.h:78
RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: iterator.h:31
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
INT2FIX
#define INT2FIX
Definition: long.h:48
LONG2FIX
#define LONG2FIX
Definition: long.h:49
LONG2NUM
#define LONG2NUM
Definition: long.h:50
FIX2LONG
#define FIX2LONG
Definition: long.h:46
NUM2LONG
#define NUM2LONG
Definition: long.h:51
rb_marshal_define_compat
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Definition: marshal.c:146
math.h
Internal header for Math.
ruby::backward::cxxanyargs::rb_block_call
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
Definition: cxxanyargs.hpp:230
TRUE
#define TRUE
Definition: nkf.h:175
FALSE
#define FALSE
Definition: nkf.h:174
RBIMPL_ATTR_NORETURN
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition: noreturn.h:38
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
RANGE_SET_BEG
#define RANGE_SET_BEG(r, v)
Definition: range.c:40
RBOOL
#define RBOOL(v)
Definition: range.c:43
id_succ
#define id_succ
Definition: range.c:34
RANGE_SET_EXCL
#define RANGE_SET_EXCL(r, v)
Definition: range.c:42
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1310
id_min
#define id_min
Definition: range.c:35
rb_range_new
VALUE rb_range_new(VALUE beg, VALUE end, int exclude_end)
Definition: range.c:68
rb_cRange
VALUE rb_cRange
Definition: range.c:31
rb_range_beg_len
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Definition: range.c:1398
BSEARCH_CHECK
#define BSEARCH_CHECK(expr)
BSEARCH
#define BSEARCH(conv)
id_max
#define id_max
Definition: range.c:36
Init_Range
void Init_Range(void)
Definition: range.c:1844
EXCL
#define EXCL(r)
Definition: range.c:45
id_cmp
#define id_cmp
Definition: range.c:33
rb_range_component_beg_len
VALUE rb_range_component_beg_len(VALUE b, VALUE e, int excl, long *begp, long *lenp, long len, int err)
Definition: range.c:1362
RANGE_SET_END
#define RANGE_SET_END(r, v)
Definition: range.c:41
RBASIC
#define RBASIC(obj)
Definition: rbasic.h:34
RBIGNUM_SIGN
#define RBIGNUM_SIGN
Definition: rbignum.h:28
NULL
#define NULL
Definition: regenc.h:69
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:308
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
RB_INTEGER_TYPE_P
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
ST2FIX
#define ST2FIX(h)
Definition: ruby_missing.h:21
Qundef
#define Qundef
Definition: special_consts.h:53
SPECIAL_CONST_P
#define SPECIAL_CONST_P
Definition: special_consts.h:47
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
FIXNUM_P
#define FIXNUM_P
Definition: special_consts.h:44
st_index_t
st_data_t st_index_t
Definition: st.h:50
rb_str_include_range_p
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive)
Definition: string.c:4618
cmp_opt_data
Definition: compar.h:23
smaller
#define smaller(tree, n, m, depth)
Definition: trees.c:441
VALUE
unsigned long VALUE
Definition: value.h:38
ID
unsigned long ID
Definition: value.h:39
T_STRING
#define T_STRING
Definition: value_type.h:77
T_FLOAT
#define T_FLOAT
Definition: value_type.h:63
T_BIGNUM
#define T_BIGNUM
Definition: value_type.h:56
T_OBJECT
#define T_OBJECT
Definition: value_type.h:74
BUILTIN_TYPE
#define BUILTIN_TYPE
Definition: value_type.h:84
SYMBOL_P
#define SYMBOL_P
Definition: value_type.h:87
err
int err
Definition: win32.c:142