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.
This commit is contained in:
Yukihiro "Matz" Matsumoto
2024-06-29 13:43:57 +09:00
parent dd808a0be4
commit eee83ed7af
4 changed files with 72 additions and 44 deletions
-29
View File
@@ -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
# <code>==</code> 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
-5
View File
@@ -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))
+62 -10
View File
@@ -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
* <code>==</code> 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
* <code>==</code> 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());
}
+10
View File
@@ -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