From 5346bdd76b3946a94efaea96ef10cbdbc5f8251e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Jan 2014 14:53:38 +0900 Subject: move range aware aget to array.c from mruby-array-ext gem --- src/array.c | 91 ++++++++++++++++++++++++++++++++++++++++++++---------------- src/string.c | 4 +-- 2 files changed, 68 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 0fcbffcd8..0c30e2c7f 100644 --- a/src/array.c +++ b/src/array.c @@ -8,6 +8,7 @@ #include "mruby/array.h" #include "mruby/class.h" #include "mruby/string.h" +#include "mruby/range.h" #include "value_array.h" #define ARY_DEFAULT_LEN 4 @@ -677,37 +678,79 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) return mrb_obj_value(b); } +static mrb_int +aget_index(mrb_state *mrb, mrb_value index) +{ + if (mrb_fixnum_p(index)) { + return mrb_fixnum(index); + } + else { + mrb_int i; + + mrb_get_args(mrb, "i", &i); + return i; + } +} + +/* + * call-seq: + * ary[index] -> obj or nil + * ary[start, length] -> new_ary or nil + * ary[range] -> new_ary or nil + * ary.slice(index) -> obj or nil + * ary.slice(start, length) -> new_ary or nil + * ary.slice(range) -> new_ary or nil + * + * Element Reference --- Returns the element at +index+, or returns a + * subarray starting at the +start+ index and continuing for +length+ + * elements, or returns a subarray specified by +range+ of indices. + * + * Negative indices count backward from the end of the array (-1 is the last + * element). For +start+ and +range+ cases the starting index is just before + * an element. Additionally, an empty array is returned when the starting + * index for an element range is at the end of the array. + * + * Returns +nil+ if the index (or starting index) are out of range. + * + * a = [ "a", "b", "c", "d", "e" ] + * a[1] => "b" + * a[1,2] => ["b", "c"] + * a[1..-2] => ["b", "c", "d"] + * + */ + mrb_value mrb_ary_aget(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int index, len; - mrb_value *argv; - int size; - - mrb_get_args(mrb, "i*", &index, &argv, &size); - switch(size) { - case 0: - return mrb_ary_ref(mrb, self, index); - - case 1: - if (!mrb_fixnum_p(argv[0])) { - mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum"); + mrb_int i, len; + mrb_value index; + + if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { + switch (mrb_type(index)) { + case MRB_TT_RANGE: + len = a->len; + if (mrb_range_beg_len(mrb, index, &i, &len, len)) { + return ary_subseq(mrb, a, i, len); + } + else { + return mrb_nil_value(); + } + case MRB_TT_FIXNUM: + return mrb_ary_ref(mrb, self, mrb_fixnum(index)); + default: + return mrb_ary_ref(mrb, self, aget_index(mrb, index)); } - if (index < 0) index += a->len; - if (index < 0 || a->len < (int)index) return mrb_nil_value(); - len = mrb_fixnum(argv[0]); - if (len < 0) return mrb_nil_value(); - if (a->len == (int)index) return mrb_ary_new(mrb); - if (len > a->len - index) len = a->len - index; - return ary_subseq(mrb, a, index, len); - - default: - mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); - break; } - return mrb_nil_value(); /* dummy to avoid warning : not reach here */ + i = aget_index(mrb, index); + if (i < 0) i += a->len; + if (i < 0 || a->len < (int)i) return mrb_nil_value(); + if (len < 0) return mrb_nil_value(); + if (a->len == (int)i) return mrb_ary_new(mrb); + if (len > a->len - i) len = a->len - i; + + return ary_subseq(mrb, a, i, len); } mrb_value diff --git a/src/string.c b/src/string.c index b68b533f3..6e5f91e3d 100644 --- a/src/string.c +++ b/src/string.c @@ -741,12 +741,10 @@ num_index: /* check if indx is Range */ { mrb_int beg, len; - mrb_value tmp; len = RSTRING_LEN(str); if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { - tmp = mrb_str_subseq(mrb, str, beg, len); - return tmp; + return mrb_str_subseq(mrb, str, beg, len); } else { return mrb_nil_value(); -- cgit v1.2.3