range.c: implement (part of) `Range#to_a` in C.
Mostly for performance reason.
MODIFY
mrblib/range.rb
mrblib/range.rb
@@ -79,8 +79,18 @@ class Range
h
end
+ ##
+ # call-seq:
+ # rng.to_a -> array
+ # rng.entries -> array
+ #
+ # Returns an array containing the items in the range.
+ #
+ # (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
+ # (1..).to_a #=> RangeError: cannot convert endless range to an array
def to_a
- raise RangeError, "cannot convert endless range to an array" if self.last.nil?
+ a = __num_to_a
+ return a if a
super
end
alias entries to_a

MODIFY
src/range.c
src/range.c
@@ -342,6 +342,55 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
return copy;
}
+static mrb_value
+range_num_to_a(mrb_state *mrb, mrb_value range)
+{
+ struct RRange *r = mrb_range_ptr(mrb, range);
+ mrb_value beg = RANGE_BEG(r);
+ mrb_value end = RANGE_END(r);
+ mrb_value ary;
+
+ if (mrb_nil_p(end)) {
+ mrb_raise(mrb, E_RANGE_ERROR, "cannot convert endless range to an array");
+ }
+ if (mrb_integer_p(beg)) {
+ if (mrb_integer_p(end)) {
+ mrb_int a = mrb_integer(beg);
+ mrb_int b = mrb_integer(end);
+ mrb_int len = b - a;
+
+ if (!RANGE_EXCL(r)) len++;
+ ary = mrb_ary_new_capa(mrb, len);
+ for (mrb_int i=0; i<len; i++) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, a+i));
+ }
+ return ary;
+ }
+#ifndef MRB_NO_FLOAT
+ if (mrb_float_p(end)) {
+ mrb_float a = (mrb_float)mrb_integer(beg);
+ mrb_float b = mrb_float(end);
+
+ ary = mrb_ary_new_capa(mrb, (mrb_int)(b - a) + 1);
+ if (RANGE_EXCL(r)) {
+ while (a < b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, a));
+ a += 1.0;
+ }
+ }
+ else {
+ while (a <= b) {
+ mrb_ary_push(mrb, ary, mrb_int_value(mrb, a));
+ a += 1.0;
+ }
+ }
+ return ary;
+ }
+#endif
+ }
+ return mrb_nil_value();
+}
+
mrb_value
mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int))
{
@@ -456,4 +505,5 @@ mrb_init_range(mrb_state *mrb)
mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */
mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */
mrb_define_method(mrb, r, "initialize_copy", range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */
+ mrb_define_method(mrb, r, "__num_to_a", range_num_to_a, MRB_ARGS_NONE());
}

range.c: implement (part of) `Range#to_a` in C.

Mostly for performance reason.