mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-array-ext: implement Array#insert in C
This commit also corrects the behavior of `Array#insert` when a negative index is out of bounds. It now raises an `IndexError`, which is consistent with CRuby. Co-authored-by: Gemini <gemini@google.com>
This commit is contained in:
@@ -233,25 +233,7 @@ class Array
|
||||
self.replace(result)
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.insert(index, obj...) -> ary
|
||||
#
|
||||
# Inserts the given values before the element with the given +index+.
|
||||
#
|
||||
# Negative indices count backwards from the end of the array, where +-1+ is
|
||||
# the last element.
|
||||
#
|
||||
# a = %w{ a b c d }
|
||||
# a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
|
||||
# a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
|
||||
|
||||
def insert(idx, *args)
|
||||
idx = idx.__to_int
|
||||
idx += self.size + 1 if idx < 0
|
||||
self[idx, 0] = args
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mruby.h>
|
||||
#include <string.h>
|
||||
#include <mruby/value.h>
|
||||
#include <mruby/array.h>
|
||||
#include <mruby/range.h>
|
||||
@@ -1136,6 +1137,61 @@ ary_flatten_bang(mrb_state *mrb, mrb_value self)
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ary.insert(index, obj...) -> ary
|
||||
*
|
||||
* Inserts the given values before the element with the given index.
|
||||
*
|
||||
* Negative indices count backwards from the end of the array, where -1
|
||||
* is the last element. If a negative index is used, the elements are
|
||||
* inserted after that element.
|
||||
*
|
||||
* If the index is greater than the length of the array, the array is
|
||||
* extended with nil elements.
|
||||
*
|
||||
* a = %w{ a b c d }
|
||||
* a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
|
||||
* a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
|
||||
*/
|
||||
static mrb_value
|
||||
ary_insert(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int idx;
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
|
||||
mrb_get_args(mrb, "i*", &idx, &argv, &argc);
|
||||
|
||||
if (argc == 0) {
|
||||
return self;
|
||||
}
|
||||
|
||||
mrb_int len = RARRAY_LEN(self);
|
||||
|
||||
if (idx < 0) {
|
||||
idx += len + 1;
|
||||
if (idx < 0) {
|
||||
mrb_raisef(mrb, E_INDEX_ERROR, "index %i outside of array bounds", idx - (len + 1));
|
||||
}
|
||||
}
|
||||
|
||||
mrb_ary_modify(mrb, mrb_ary_ptr(self));
|
||||
|
||||
mrb_int new_len = (idx > len ? idx : len) + argc;
|
||||
mrb_ary_resize(mrb, self, new_len);
|
||||
|
||||
if (idx < len) {
|
||||
memmove(RARRAY_PTR(self) + idx + argc, RARRAY_PTR(self) + idx, (len - idx) * sizeof(mrb_value));
|
||||
}
|
||||
|
||||
for (mrb_int i = 0; i < argc; i++) {
|
||||
mrb_ary_set(mrb, self, idx + i, argv[i]);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_array_ext_gem_init(mrb_state* mrb)
|
||||
{
|
||||
@@ -1163,6 +1219,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb)
|
||||
mrb_define_method_id(mrb, a, MRB_SYM_B(__uniq), ary_uniq_bang, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, a, MRB_SYM(flatten), ary_flatten, MRB_ARGS_OPT(1));
|
||||
mrb_define_method_id(mrb, a, MRB_SYM_B(flatten), ary_flatten_bang, MRB_ARGS_OPT(1));
|
||||
mrb_define_method_id(mrb, a, MRB_SYM(insert), ary_insert, MRB_ARGS_ARG(1, -1));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -461,12 +461,63 @@ assert("Array#reject!") do
|
||||
end
|
||||
|
||||
assert("Array#insert") do
|
||||
a = ["a", "b", "c", "d"]
|
||||
assert_equal ["a", "b", 99, "c", "d"], a.insert(2, 99)
|
||||
assert_equal ["a", "b", 99, "c", 1, 2, 3, "d"], a.insert(-2, 1, 2, 3)
|
||||
# Basic insertion
|
||||
a = [1, 2, 3]
|
||||
assert_same a, a.insert(1, 99)
|
||||
assert_equal [1, 99, 2, 3], a
|
||||
|
||||
b = ["a", "b", "c", "d"]
|
||||
assert_equal ["a", "b", "c", "d", nil, nil, 99], b.insert(6, 99)
|
||||
# Multiple elements
|
||||
a = [1, 2, 3]
|
||||
a.insert(2, 'a', 'b')
|
||||
assert_equal [1, 2, 'a', 'b', 3], a
|
||||
|
||||
# Negative index
|
||||
a = [1, 2, 3, 4]
|
||||
a.insert(-2, 99)
|
||||
assert_equal [1, 2, 3, 99, 4], a
|
||||
|
||||
# Negative index out of bounds
|
||||
a = [1, 2, 3]
|
||||
assert_raise(IndexError) { a.insert(-5, 99) }
|
||||
assert_equal [1, 2, 3], a
|
||||
|
||||
# Insertion beyond bounds (creates nils)
|
||||
a = [1, 2]
|
||||
a.insert(5, 99)
|
||||
assert_equal [1, 2, nil, nil, nil, 99], a
|
||||
|
||||
# Insertion at the end
|
||||
a = [1, 2, 3]
|
||||
a.insert(3, 99)
|
||||
assert_equal [1, 2, 3, 99], a
|
||||
|
||||
# Insertion into an empty array
|
||||
a = []
|
||||
a.insert(0, 1, 2)
|
||||
assert_equal [1, 2], a
|
||||
|
||||
# Insertion into an empty array at a non-zero index
|
||||
a = []
|
||||
a.insert(2, 99)
|
||||
assert_equal [nil, nil, 99], a
|
||||
|
||||
# No-op (inserting zero elements)
|
||||
a = [1, 2, 3]
|
||||
a.insert(1)
|
||||
assert_equal [1, 2, 3], a
|
||||
|
||||
# Return value is self
|
||||
a = [1, 2, 3]
|
||||
b = a.insert(1, 99)
|
||||
assert_same a, b
|
||||
|
||||
# Large array insertion
|
||||
a = (0...1000).to_a
|
||||
a.insert(500, "x")
|
||||
assert_equal 1001, a.size
|
||||
assert_equal "x", a[500]
|
||||
assert_equal 499, a[499]
|
||||
assert_equal 500, a[501]
|
||||
end
|
||||
|
||||
assert("Array#bsearch") do
|
||||
|
||||
Reference in New Issue
Block a user