diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-05-14 08:39:14 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-05-14 08:39:14 +0900 |
| commit | 364f275997a8deb2972b452f38b7155f21df4e92 (patch) | |
| tree | 5b2a42ef196c9dbc7644824908e42747ff74a04a | |
| parent | 99f0adc3f47d9994a0bc783d9249fb5cf9ac2bb4 (diff) | |
| download | mruby-364f275997a8deb2972b452f38b7155f21df4e92.tar.gz mruby-364f275997a8deb2972b452f38b7155f21df4e92.zip | |
range.c: implement (part of) `Range#to_a` in C.
Mostly for performance reason.
| -rw-r--r-- | mrblib/range.rb | 12 | ||||
| -rw-r--r-- | src/range.c | 50 |
2 files changed, 61 insertions, 1 deletions
diff --git a/mrblib/range.rb b/mrblib/range.rb index fb217f771..f808053ca 100644 --- a/mrblib/range.rb +++ b/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 diff --git a/src/range.c b/src/range.c index 3ef4b14f5..1615f03b2 100644 --- a/src/range.c +++ b/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()); } |
