summaryrefslogtreecommitdiff
path: root/range.c
diff options
context:
space:
mode:
Diffstat (limited to 'range.c')
-rw-r--r--range.c73
1 files changed, 48 insertions, 25 deletions
diff --git a/range.c b/range.c
index 90d9ae2ab3..041cd93f73 100644
--- a/range.c
+++ b/range.c
@@ -47,6 +47,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
static void
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
{
+ // Changing this condition has implications for JITs. If you do, please let maintainers know.
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
VALUE v;
@@ -153,14 +154,14 @@ recursive_equal(VALUE range, VALUE obj, int recur)
* call-seq:
* self == other -> true or false
*
- * Returns +true+ if and only if:
+ * Returns whether all of the following are true:
*
* - +other+ is a range.
* - <tt>other.begin == self.begin</tt>.
* - <tt>other.end == self.end</tt>.
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
*
- * Otherwise returns +false+.
+ * Examples:
*
* r = (1..5)
* r == (1..5) # => true
@@ -199,11 +200,10 @@ range_eq(VALUE range, VALUE obj)
static int
r_less(VALUE a, VALUE b)
{
- VALUE r = rb_funcall(a, id_cmp, 1, b);
-
- if (NIL_P(r))
- return INT_MAX;
- return rb_cmpint(r, a, b);
+ VALUE r;
+#define rb_cmpint(cmp, a, b) (NIL_P(r = (cmp)) ? INT_MAX : rb_cmpint(r, (a), (b)))
+ return OPTIMIZED_CMP(a, b);
+#undef rb_cmpint
}
static VALUE
@@ -783,7 +783,7 @@ bsearch_integer_range(VALUE beg, VALUE end, int excl)
*
* Returns an element from +self+ selected by a binary search.
*
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc].
*
*/
@@ -1017,6 +1017,29 @@ range_to_a(VALUE range)
return rb_call_super(0, 0);
}
+/*
+ * call-seq:
+ * to_set -> set
+ *
+ * Returns a set containing the elements in +self+, if a finite collection;
+ * raises an exception otherwise.
+ *
+ * (1..4).to_set # => Set[1, 2, 3, 4]
+ * (1...4).to_set # => Set[1, 2, 3]
+ *
+ * (1..).to_set
+ * # in 'Range#to_set': cannot convert endless range to a set (RangeError)
+ *
+ */
+static VALUE
+range_to_set(VALUE range)
+{
+ if (NIL_P(RANGE_END(range))) {
+ rb_raise(rb_eRangeError, "cannot convert endless range to a set");
+ }
+ return rb_call_super(0, NULL);
+}
+
static VALUE
range_enum_size(VALUE range, VALUE args, VALUE eobj)
{
@@ -2030,10 +2053,9 @@ VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
/*
* call-seq:
- * self === object -> true or false
+ * self === other -> true or false
*
- * Returns +true+ if +object+ is between <tt>self.begin</tt> and <tt>self.end</tt>.
- * +false+ otherwise:
+ * Returns whether +other+ is between <tt>self.begin</tt> and <tt>self.end</tt>:
*
* (1..4) === 2 # => true
* (1..4) === 5 # => false
@@ -2561,7 +2583,7 @@ range_overlap(VALUE range, VALUE other)
/* if both begin values are equal, no more comparisons needed */
if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
}
- else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg)) {
+ else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg) && !NIL_P(other_end)) {
VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
return RBOOL(!NIL_P(cmp));
}
@@ -2588,12 +2610,12 @@ range_overlap(VALUE range, VALUE other)
*
* - Method Range.new:
*
- * # Ranges that by default include the given end value.
- * Range.new(1, 4).to_a # => [1, 2, 3, 4]
- * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
- * # Ranges that use third argument +exclude_end+ to exclude the given end value.
- * Range.new(1, 4, true).to_a # => [1, 2, 3]
- * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
+ * # Ranges that by default include the given end value.
+ * Range.new(1, 4).to_a # => [1, 2, 3, 4]
+ * Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
+ * # Ranges that use third argument +exclude_end+ to exclude the given end value.
+ * Range.new(1, 4, true).to_a # => [1, 2, 3]
+ * Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
*
* == Beginless Ranges
*
@@ -2661,14 +2683,14 @@ range_overlap(VALUE range, VALUE other)
* end
* a # => [2, 4, 6, 8, 10]
*
- * A range can be both beginless and endless. For literal beginless, endless
+ * A range can be both beginless and endless. For literal beginless, endless
* ranges, at least the beginning or end of the range must be given as an
* explicit nil value. It is recommended to use an explicit nil beginning and
- * implicit nil end, since that is what Ruby uses for Range#inspect:
+ * end, since that is what Ruby uses for Range#inspect:
*
- * (nil..) # => (nil..)
- * (..nil) # => (nil..)
- * (nil..nil) # => (nil..)
+ * (nil..) # => (nil..nil)
+ * (..nil) # => (nil..nil)
+ * (nil..nil) # => (nil..nil)
*
* == Ranges and Other Classes
*
@@ -2745,8 +2767,8 @@ range_overlap(VALUE range, VALUE other)
*
* First, what's elsewhere. Class \Range:
*
- * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
+ * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
+ * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
* which provides dozens of additional methods.
*
* Here, class \Range provides methods that are useful for:
@@ -2844,6 +2866,7 @@ Init_Range(void)
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
rb_define_method(rb_cRange, "size", range_size, 0);
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
+ rb_define_method(rb_cRange, "to_set", range_to_set, 0);
rb_define_method(rb_cRange, "entries", range_to_a, 0);
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
rb_define_method(rb_cRange, "inspect", range_inspect, 0);