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