From eee83ed7af27edecfe209423f6d15ce84b0b97d9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 29 Jun 2024 13:43:57 +0900 Subject: [PATCH] array.c: implement Array#index and Array#rindex in C No need to override Array#index in mruby-array-ext. We can call `to_enum` from C implemented methods. --- mrbgems/mruby-array-ext/mrblib/array.rb | 29 ---------- mrbgems/mruby-array-ext/test/array.rb | 5 -- src/array.c | 72 +++++++++++++++++++++---- test/t/array.rb | 10 ++++ 4 files changed, 72 insertions(+), 44 deletions(-) diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 5add0a5bd..0ff622774 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -700,35 +700,6 @@ class Array self.replace(result) end - ## - # call-seq: - # ary.index(val) -> int or nil - # ary.index {|item| block } -> int or nil - # - # Returns the _index_ of the first object in +ary+ such that the object is - # == to +obj+. - # - # If a block is given instead of an argument, returns the _index_ of the - # first object for which the block returns +true+. Returns +nil+ if no - # match is found. - # - # ISO 15.2.12.5.14 - def index(val=NONE, &block) - return to_enum(:find_index, val) if !block && NONE.equal?(val) - - if block - idx = 0 - len = size - while idx < len - return idx if block.call self[idx] - idx += 1 - end - else - return self.__ary_index(val) - end - nil - end - ## # call-seq: # ary.dig(idx, ...) -> object diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index bd7a2dc45..5197c8cd2 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -361,11 +361,6 @@ assert('Array#to_h') do assert_raise(ArgumentError) { [[1]].to_h } end -assert("Array#index (block)") do - assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } - assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } -end - assert("Array#dig") do h = [[[1]], 0] assert_equal(1, h.dig(0, 0, 0)) diff --git a/src/array.c b/src/array.c index 6319a10e4..21e7f5aa1 100644 --- a/src/array.c +++ b/src/array.c @@ -1133,31 +1133,84 @@ mrb_ary_last(mrb_state *mrb, mrb_value self) return mrb_ary_new_from_values(mrb, size, ARY_PTR(a) + alen - size); } +/* + * call-seq: + * ary.index(val) -> int or nil + * ary.index {|item| block } -> int or nil + * array.index -> enumerator + * + * Returns the _index_ of the first object in +ary+ such that the object is + * == to +obj+. + * + * If a block is given instead of an argument, returns the _index_ of the + * first object for which the block returns +true+. Returns +nil+ if no + * match is found. + * + * ISO 15.2.12.5.14 + */ static mrb_value mrb_ary_index_m(mrb_state *mrb, mrb_value self) { - mrb_value obj = mrb_get_arg1(mrb); + mrb_value obj, blk; - for (mrb_int i = 0; i < RARRAY_LEN(self); i++) { - if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { - return mrb_int_value(mrb, i); + if (mrb_get_args(mrb, "|o&", &obj, &blk) == 0 && mrb_nil_p(blk)) { + return mrb_funcall_id(mrb, self, MRB_SYM(to_enum), 1, mrb_symbol_value(MRB_SYM(index))); + } + + if (mrb_nil_p(blk)) { + for (mrb_int i = 0; i < RARRAY_LEN(self); i++) { + if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { + return mrb_int_value(mrb, i); + } + } + } + else { + for (mrb_int i = 0; i < RARRAY_LEN(self); i++) { + mrb_value eq = mrb_funcall_id(mrb, blk, MRB_SYM(call), 1, RARRAY_PTR(self)[i]); + if (mrb_test(eq)) { + return mrb_int_value(mrb, i); + } } } return mrb_nil_value(); } +/* + * call-seq: + * ary.rindex(val) -> int or nil + * ary.rindex {|item| block } -> int or nil + * array.rindex -> enumerator + * + * Returns the _index_ of the first object in +ary+ such that the object is + * == to +obj+. + * + * If a block is given instead of an argument, returns the _index_ of the + * first object for which the block returns +true+. Returns +nil+ if no + * match is found. + * + * ISO 15.2.12.5.26 + */ static mrb_value mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) { - mrb_value obj = mrb_get_arg1(mrb); + mrb_value obj, blk; + + if (mrb_get_args(mrb, "|o&", &obj, &blk) == 0 && mrb_nil_p(blk)) { + return mrb_funcall_id(mrb, self, MRB_SYM(to_enum), 1, mrb_symbol_value(MRB_SYM(rindex))); + } for (mrb_int i = RARRAY_LEN(self) - 1; i >= 0; i--) { - mrb_int len; - - if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { + if (mrb_nil_p(blk)) { + if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { return mrb_int_value(mrb, i); + } } - if (i > (len = RARRAY_LEN(self))) { + else { + mrb_value eq = mrb_funcall_id(mrb, blk, MRB_SYM(call), 1, RARRAY_PTR(self)[i]); + if (mrb_test(eq)) return mrb_int_value(mrb, i); + } + mrb_int len = RARRAY_LEN(self); + if (i > len) { i = len; } } @@ -1623,7 +1676,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method_id(mrb, a, MRB_SYM(inspect), mrb_ary_to_s, MRB_ARGS_NONE()); mrb_define_method_id(mrb, a, MRB_SYM_B(sort), mrb_ary_sort_bang, MRB_ARGS_NONE()); - mrb_define_method_id(mrb, a, MRB_SYM(__ary_index), mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method_id(mrb, a, MRB_SYM(__delete), mrb_ary_delete, MRB_ARGS_REQ(1)); mrb_define_method_id(mrb, a, MRB_SYM(__svalue), mrb_ary_svalue, MRB_ARGS_NONE()); } diff --git a/test/t/array.rb b/test/t/array.rb index b40c03dd7..34b8aacbd 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -189,6 +189,11 @@ assert('Array#index', '15.2.12.5.14') do assert_equal(nil, a.index(0)) end +assert("Array#index (block)") do + assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } + assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } +end + assert('Array#initialize', '15.2.12.5.15') do a = [].initialize(1) b = [].initialize(2) @@ -288,6 +293,11 @@ assert('Array#rindex', '15.2.12.5.26') do assert_equal(nil, a.rindex(0)) end +assert("Array#rindex (block)") do + assert_nil (1..10).to_a.rindex { |i| i % 5 == 0 and i % 7 == 0 } + assert_equal 69, (1..100).to_a.rindex { |i| i % 5 == 0 and i % 7 == 0 } +end + assert('Array#shift', '15.2.12.5.27') do a = [1,2,3] b = a.shift