summaryrefslogtreecommitdiff
path: root/range.c
diff options
context:
space:
mode:
Diffstat (limited to 'range.c')
-rw-r--r--range.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/range.c b/range.c
index 22cf237fc1..6895511e59 100644
--- a/range.c
+++ b/range.c
@@ -35,7 +35,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
static void
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
{
- if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(end)) {
+ if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
VALUE v;
v = rb_funcall(beg, id_cmp, 1, end);
@@ -704,8 +704,8 @@ range_bsearch(VALUE range)
}
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
- int64_t low = double_as_int64(RFLOAT_VALUE(rb_Float(beg)));
- int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
+ int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
+ int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
int64_t mid, org_high;
BSEARCH(int64_as_double_to_num);
}
@@ -726,6 +726,18 @@ range_bsearch(VALUE range)
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
}
}
+ else if (NIL_P(beg) && is_integer_p(end)) {
+ VALUE diff = LONG2FIX(-1);
+ RETURN_ENUMERATOR(range, 0, 0);
+ while (1) {
+ VALUE mid = rb_funcall(end, '+', 1, diff);
+ BSEARCH_CHECK(mid);
+ if (!smaller) {
+ return bsearch_integer_range(mid, end, 0);
+ }
+ diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
+ }
+ }
else {
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
}
@@ -770,6 +782,9 @@ range_size(VALUE range)
return DBL2NUM(HUGE_VAL);
}
}
+ else if (NIL_P(b)) {
+ return DBL2NUM(HUGE_VAL);
+ }
return Qnil;
}
@@ -1230,7 +1245,7 @@ rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
if (!rb_range_values(range, &b, &e, &excl))
return Qfalse;
- beg = NUM2LONG(b);
+ beg = NIL_P(b) ? 0 : NUM2LONG(b);
end = NIL_P(e) ? -1 : NUM2LONG(e);
if (NIL_P(e)) excl = 0;
origbeg = beg;
@@ -1392,6 +1407,12 @@ range_include_internal(VALUE range, VALUE val)
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range));
}
+ else if (NIL_P(beg)) {
+ VALUE r = rb_funcall(val, id_cmp, 1, end);
+ if (NIL_P(r)) return Qfalse;
+ if (rb_cmpint(r, val, end) <= 0) return Qtrue;
+ return Qfalse;
+ }
else if (NIL_P(end)) {
VALUE r = rb_funcall(beg, id_cmp, 1, val);
if (NIL_P(r)) return Qfalse;
@@ -1487,7 +1508,7 @@ r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val)
static VALUE
r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
{
- if (r_less(beg, val) <= 0) {
+ if (NIL_P(beg) || r_less(beg, val) <= 0) {
int excl = EXCL(range);
if (NIL_P(end) || r_less(val, end) <= -excl)
return Qtrue;
@@ -1550,9 +1571,15 @@ range_alloc(VALUE klass)
* ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
* ('a'...'e').to_a #=> ["a", "b", "c", "d"]
*
- * == Endless Ranges
+ * == Beginless/Endless Ranges
+ *
+ * A "beginless range" and "endless range" represents a semi-infinite
+ * range. Literal notation for a beginless range is:
+ *
+ * (..1)
+ * # or
+ * (...1)
*
- * An "endless range" represents a semi-infinite range.
* Literal notation for an endless range is:
*
* (1..)
@@ -1564,14 +1591,16 @@ range_alloc(VALUE klass)
* (1..nil) # or similarly (1...nil)
* Range.new(1, nil) # or Range.new(1, nil, true)
*
- * Endless ranges are useful, for example, for idiomatic slicing of
- * arrays:
+ * Beginless/endless ranges are useful, for example, for idiomatic
+ * slicing of arrays:
*
+ * [1, 2, 3, 4, 5][...2] # => [1, 2]
* [1, 2, 3, 4, 5][2...] # => [3, 4, 5]
*
* Some implementation details:
*
- * * +end+ of endless range is +nil+;
+ * * +begin+ of beginless range and +end+ of endless range are +nil+;
+ * * +each+ of beginless range raises an exception;
* * +each+ of endless range enumerates infinite sequence (may be
* useful in combination with Enumerable#take_while or similar
* methods);