summaryrefslogtreecommitdiff
path: root/src/array.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/array.c')
-rw-r--r--src/array.c785
1 files changed, 689 insertions, 96 deletions
diff --git a/src/array.c b/src/array.c
index 1d649c1..cf28c35 100644
--- a/src/array.c
+++ b/src/array.c
@@ -11,7 +11,6 @@
#include <mruby/range.h>
#include <mruby/proc.h>
#include <mruby/internal.h>
-#include <mruby/presym.h>
#include "value_array.h"
#define ARY_DEFAULT_LEN 4
@@ -22,12 +21,14 @@
#endif
#define ARY_MAX_SIZE ((mrb_int)((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? ARY_C_MAX_SIZE : MRB_INT_MAX-1))
+/* Raises an ArgumentError when array size exceeds limits */
static void
ary_too_big(mrb_state *mrb)
{
mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
}
+/* Checks if array size would exceed limits and raises error if so */
static inline void
ary_check_too_big(mrb_state *mrb, mrb_int a, mrb_int b)
{
@@ -39,6 +40,7 @@ ary_check_too_big(mrb_state *mrb, mrb_int a, mrb_int b)
#endif
}
+/* Creates a new RArray with specified capacity */
static struct RArray*
ary_new_capa(mrb_state *mrb, mrb_int capa)
{
@@ -59,6 +61,17 @@ ary_new_capa(mrb_state *mrb, mrb_int capa)
return a;
}
+/**
+ * Creates a new array with a specified initial capacity.
+ *
+ * This function allocates an array that can hold at least `capa` elements
+ * without needing to immediately reallocate memory. If `capa` is 0,
+ * it may still allocate a small default capacity.
+ *
+ * @param mrb The mruby state.
+ * @param capa The initial capacity desired for the array.
+ * @return A new mrb_value representing the created array.
+ */
MRB_API mrb_value
mrb_ary_new_capa(mrb_state *mrb, mrb_int capa)
{
@@ -66,6 +79,15 @@ mrb_ary_new_capa(mrb_state *mrb, mrb_int capa)
return mrb_obj_value(a);
}
+/**
+ * Creates a new, empty array.
+ *
+ * This function is equivalent to calling `mrb_ary_new_capa` with a capacity of 0.
+ * The array will dynamically resize as elements are added.
+ *
+ * @param mrb The mruby state.
+ * @return A new mrb_value representing the created empty array.
+ */
MRB_API mrb_value
mrb_ary_new(mrb_state *mrb)
{
@@ -85,6 +107,7 @@ mrb_ary_new(mrb_state *mrb)
*
* See also https://togetter.com/li/462898 (Japanese)
*/
+/* Portable array copy function to avoid memcpy issues on some platforms */
static inline void
array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
{
@@ -93,6 +116,7 @@ array_copy(mrb_value *dst, const mrb_value *src, mrb_int size)
}
}
+/* Creates a new RArray initialized with values from an array */
static struct RArray*
ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
{
@@ -104,6 +128,17 @@ ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
return a;
}
+/**
+ * Creates a new array initialized with a given sequence of values.
+ *
+ * This function allocates an array and copies `size` elements from the `vals`
+ * pointer into the new array.
+ *
+ * @param mrb The mruby state.
+ * @param size The number of values to initialize the array with.
+ * @param vals A pointer to an array of `mrb_value`s to copy into the new array.
+ * @return A new mrb_value representing the created array.
+ */
MRB_API mrb_value
mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
{
@@ -111,6 +146,17 @@ mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals)
return mrb_obj_value(a);
}
+/**
+ * Creates a new array of size 2, typically used to represent an association (key-value pair).
+ *
+ * The first element of the array is `car` (often the key), and the second element
+ * is `cdr` (often the value).
+ *
+ * @param mrb The mruby state.
+ * @param car The first value to be placed in the array.
+ * @param cdr The second value to be placed in the array.
+ * @return A new mrb_value representing the created 2-element array.
+ */
MRB_API mrb_value
mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
{
@@ -123,6 +169,7 @@ mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr)
return mrb_obj_value(a);
}
+/* Fills array elements with nil values */
static void
ary_fill_with_nil(mrb_value *ptr, mrb_int size)
{
@@ -135,6 +182,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
#define ary_modify_check(mrb, a) mrb_check_frozen((mrb), (a))
+/* Prepares array for modification, handling shared arrays and frozen check */
static void
ary_modify(mrb_state *mrb, struct RArray *a)
{
@@ -163,6 +211,17 @@ ary_modify(mrb_state *mrb, struct RArray *a)
}
}
+/**
+ * Prepares an array for modification.
+ *
+ * This function ensures that the array is not frozen and is not shared.
+ * If the array is shared and has multiple references, this function will
+ * duplicate the array data to ensure that modifications do not affect
+ * other references. It also triggers a write barrier for the garbage collector.
+ *
+ * @param mrb The mruby state.
+ * @param a A pointer to the RArray structure to modify.
+ */
MRB_API void
mrb_ary_modify(mrb_state *mrb, struct RArray* a)
{
@@ -170,6 +229,7 @@ mrb_ary_modify(mrb_state *mrb, struct RArray* a)
ary_modify(mrb, a);
}
+/* Converts array to shared representation for copy-on-write semantics */
static void
ary_make_shared(mrb_state *mrb, struct RArray *a)
{
@@ -191,6 +251,45 @@ ary_make_shared(mrb_state *mrb, struct RArray *a)
}
}
+/* Creates a shared copy of array for temporary GC protection.
+ * Frozen arrays are returned as-is (cannot be modified).
+ * Embedded arrays get full copy (cannot be shared).
+ * Heap arrays get zero-copy shared reference.
+ */
+MRB_API mrb_value
+mrb_ary_make_shared_copy(mrb_state *mrb, mrb_value ary)
+{
+ struct RArray *orig = mrb_ary_ptr(ary);
+
+ // Frozen arrays don't need protection
+ if (mrb_frozen_p(orig)) {
+ return ary;
+ }
+
+ // Embedded arrays can't be shared - make full copy
+ if (ARY_EMBED_P(orig)) {
+ return mrb_ary_dup(mrb, ary);
+ }
+
+ // Make original array shared if not already
+ if (!ARY_SHARED_P(orig)) {
+ ary_make_shared(mrb, orig);
+ }
+
+ // Create new array that shares the buffer
+ struct RArray *shared = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
+
+ shared->as.heap.ptr = orig->as.heap.ptr;
+ shared->as.heap.len = orig->as.heap.len;
+ shared->as.heap.aux.shared = orig->as.heap.aux.shared;
+ shared->as.heap.aux.shared->refcnt++;
+ ARY_SET_SHARED_FLAG(shared);
+ mrb_write_barrier(mrb, (struct RBasic*)shared);
+
+ return mrb_obj_value(shared);
+}
+
+/* Expands array capacity to accommodate at least len elements */
static void
ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
{
@@ -231,6 +330,7 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
}
}
+/* Shrinks array capacity to save memory when array becomes much smaller */
static void
ary_shrink_capa(mrb_state *mrb, struct RArray *a)
{
@@ -255,6 +355,19 @@ ary_shrink_capa(mrb_state *mrb, struct RArray *a)
}
}
+/**
+ * Resizes an array to a new length.
+ *
+ * If `new_len` is smaller than the current length, the array is truncated.
+ * If `new_len` is larger than the current length, the array is expanded,
+ * and new elements are filled with `nil`.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) to resize.
+ * @param new_len The desired new length of the array.
+ * @return The resized array (the same mrb_value as `ary`).
+ */
MRB_API mrb_value
mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
{
@@ -276,6 +389,16 @@ mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len)
return ary;
}
+/*
+ * call-seq:
+ * Array[obj, ...] -> new_array
+ *
+ * Creates a new Array containing the given objects:
+ *
+ * Array[1, 'a', /^A/] # => [1, "a", /^A/]
+ * Array[1, 2, 3] # => [1, 2, 3]
+ * Array[] # => []
+ */
static mrb_value
mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
{
@@ -292,6 +415,42 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
static void ary_replace(mrb_state*, struct RArray*, struct RArray*);
+/*
+ * call-seq:
+ * Array.new(size=0, default=nil) -> new_array
+ * Array.new(array) -> new_array
+ * Array.new(size) {|index| ... } -> new_array
+ *
+ * Returns a new Array.
+ *
+ * With no block and no arguments, returns a new empty Array object.
+ *
+ * With no block and a single `size` argument, returns a new Array object
+ * of the given size whose elements are all `nil`:
+ *
+ * a = Array.new(3)
+ * a # => [nil, nil, nil]
+ * a.size # => 3
+ *
+ * With no block and arguments `size` and `default`, returns an Array object
+ * of the given size; each element is the same `default` object:
+ *
+ * a = Array.new(3, 'x')
+ * a # => ['x', 'x', 'x']
+ *
+ * With a block and argument `size`, returns an Array object of the given size;
+ * the block is called with each successive integer `index`;
+ * the element for that `index` is the return value from the block:
+ *
+ * a = Array.new(3) {|index| "Element #{index}" }
+ * a # => ["Element 0", "Element 1", "Element 2"]
+ *
+ * With a single Array argument `array`, returns a new Array formed from `array`:
+ *
+ * a = Array.new([:foo, 'bar', 2])
+ * a.class # => Array
+ * a # => [:foo, "bar", 2]
+ */
static mrb_value
mrb_ary_init(mrb_state *mrb, mrb_value ary)
{
@@ -328,6 +487,7 @@ mrb_ary_init(mrb_state *mrb, mrb_value ary)
return ary;
}
+/* Internal helper to concatenate two arrays */
static void
ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
{
@@ -351,6 +511,16 @@ ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
ARY_SET_LEN(a, newlen);
}
+/**
+ * Concatenates one array to another.
+ *
+ * Appends all elements from the `other` array to the `self` array.
+ * This function modifies the `self` array in place.
+ *
+ * @param mrb The mruby state.
+ * @param self The array (mrb_value) to which elements will be added.
+ * @param other The array (mrb_value) whose elements will be appended.
+ */
MRB_API void
mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
{
@@ -363,7 +533,7 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other)
* call-seq:
* array.concat(*other_arrays) -> self
*
- * Adds to +array+ all elements from each \Array in +other_arrays+; returns +self+:
+ * Adds to `array` all elements from each \Array in `other_arrays`; returns `self`:
*
* a = [0, 1]
* a.concat([2, 3], [4, 5]) # => [0, 1, 2, 3, 4, 5]
@@ -385,6 +555,16 @@ mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
return self;
}
+/*
+ * call-seq:
+ * array + other_array -> new_array
+ *
+ * Returns a new Array containing all elements of `array`
+ * followed by all elements of `other_array`:
+ *
+ * a = [0, 1] + [2, 3]
+ * a # => [0, 1, 2, 3]
+ */
static mrb_value
mrb_ary_plus(mrb_state *mrb, mrb_value self)
{
@@ -405,6 +585,7 @@ mrb_ary_plus(mrb_state *mrb, mrb_value self)
#define ARY_REPLACE_SHARED_MIN 20
+/* Internal helper to replace array contents with another array */
static void
ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
{
@@ -446,6 +627,16 @@ ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
ARY_SET_LEN(a, len);
}
+/**
+ * Replaces the contents of an array with the contents of another array.
+ *
+ * After this operation, the `self` array will contain the same elements
+ * as the `other` array. This function modifies the `self` array in place.
+ *
+ * @param mrb The mruby state.
+ * @param self The array (mrb_value) whose contents will be replaced.
+ * @param other The array (mrb_value) from which to copy the elements.
+ */
MRB_API void
mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
{
@@ -457,6 +648,18 @@ mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
}
}
+/*
+ * call-seq:
+ * array.replace(other_array) -> self
+ * array.initialize_copy(other_array) -> self
+ *
+ * Replaces the contents of `self` with the contents of `other_array`;
+ * returns `self`:
+ *
+ * a = [0, 1, 2]
+ * a.replace(['foo', 'bar']) # => ["foo", "bar"]
+ * a # => ["foo", "bar"]
+ */
static mrb_value
mrb_ary_replace_m(mrb_state *mrb, mrb_value self)
{
@@ -468,6 +671,22 @@ mrb_ary_replace_m(mrb_state *mrb, mrb_value self)
return self;
}
+/*
+ * call-seq:
+ * array * int -> new_array
+ * array * str -> new_string
+ *
+ * When the argument is an Integer `n`,
+ * returns a new Array built by concatenating `n` copies of `self`:
+ *
+ * a = ['x', 'y']
+ * a * 3 # => ["x", "y", "x", "y", "x", "y"]
+ *
+ * When the argument is a String `separator`,
+ * equivalent to `array.join(separator)`:
+ *
+ * [1, 2, 3] * '|' # => "1|2|3"
+ */
static mrb_value
mrb_ary_times(mrb_state *mrb, mrb_value self)
{
@@ -501,6 +720,16 @@ mrb_ary_times(mrb_state *mrb, mrb_value self)
return mrb_obj_value(a2);
}
+/*
+ * call-seq:
+ * array.reverse! -> self
+ *
+ * Reverses `self` in place:
+ *
+ * a = ['foo', 'bar', 'two']
+ * a.reverse! # => ["two", "bar", "foo"]
+ * a # => ["two", "bar", "foo"]
+ */
static mrb_value
mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
{
@@ -522,6 +751,17 @@ mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self)
return self;
}
+/*
+ * call-seq:
+ * array.reverse -> new_array
+ *
+ * Returns a new Array with the elements of `self` in reverse order:
+ *
+ * a = ['foo', 'bar', 'two']
+ * a1 = a.reverse
+ * a1 # => ["two", "bar", "foo"]
+ * a # => ["foo", "bar", "two"]
+ */
static mrb_value
mrb_ary_reverse(mrb_state *mrb, mrb_value self)
{
@@ -540,6 +780,17 @@ mrb_ary_reverse(mrb_state *mrb, mrb_value self)
return mrb_obj_value(b);
}
+/**
+ * Pushes an element onto the end of an array.
+ *
+ * This function appends `elem` to the `ary` array, increasing its length by one.
+ * The array capacity may be expanded if necessary.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) to push the element onto.
+ * @param elem The mrb_value to append to the array.
+ */
MRB_API void
mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
{
@@ -554,6 +805,23 @@ mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem)
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem);
}
+/*
+ * call-seq:
+ * array.push(*objects) -> self
+ * array << object -> self
+ *
+ * Appends trailing elements.
+ *
+ * Appends each argument in `objects` to `self`; returns `self`:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
+ *
+ * Appends `object` to `self`; returns `self`:
+ *
+ * a = [:foo, 'bar', 2]
+ * a << :baz # => [:foo, "bar", 2, :baz]
+ */
static mrb_value
mrb_ary_push_m(mrb_state *mrb, mrb_value self)
{
@@ -579,6 +847,16 @@ mrb_ary_push_m(mrb_state *mrb, mrb_value self)
return self;
}
+/**
+ * Removes and returns the last element from an array.
+ *
+ * If the array is empty, returns `nil`.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) from which to pop the element.
+ * @return The last element of the array, or `nil` if the array is empty.
+ */
MRB_API mrb_value
mrb_ary_pop(mrb_state *mrb, mrb_value ary)
{
@@ -593,6 +871,17 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary)
#define ARY_SHIFT_SHARED_MIN 10
+/**
+ * Removes and returns the first element from an array.
+ *
+ * If the array is empty, returns `nil`.
+ * All other elements are shifted down by one index.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param self The array (mrb_value) from which to shift the element.
+ * @return The first element of the array, or `nil` if the array is empty.
+ */
MRB_API mrb_value
mrb_ary_shift(mrb_state *mrb, mrb_value self)
{
@@ -625,6 +914,27 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self)
}
}
+/*
+ * call-seq:
+ * array.shift -> object or nil
+ * array.shift(n) -> new_array
+ *
+ * Removes and returns leading elements.
+ *
+ * When no argument is given, removes and returns the first element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.shift # => :foo
+ * a # => ["bar", 2]
+ *
+ * Returns `nil` if `self` is empty.
+ *
+ * When argument `n` is given, removes and returns the first `n` elements in a new Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.shift(2) # => [:foo, "bar"]
+ * a # => [2]
+ */
static mrb_value
mrb_ary_shift_m(mrb_state *mrb, mrb_value self)
{
@@ -672,6 +982,19 @@ mrb_ary_shift_m(mrb_state *mrb, mrb_value self)
item = 0
self.unshift item
p self #=> [0, 1, 2, 3] */
+/**
+ * Prepends an element to the beginning of an array.
+ *
+ * This function adds `item` to the front of the `self` array,
+ * shifting all existing elements up by one index.
+ * The array capacity may be expanded if necessary.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param self The array (mrb_value) to unshift the element onto.
+ * @param item The mrb_value to prepend to the array.
+ * @return The modified array (the same mrb_value as `self`).
+ */
MRB_API mrb_value
mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
{
@@ -704,7 +1027,7 @@ mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item)
* call-seq:
* array.unshift(*objects) -> self
*
- * Prepends the given +objects+ to +self+:
+ * Prepends the given `objects` to `self`:
*
* a = [:foo, 'bar', 2]
* a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
@@ -756,6 +1079,22 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self)
return self;
}
+/**
+ * Sets the element at a given index in an array.
+ *
+ * If `n` is within the current bounds of the array, the element at that index
+ * is replaced with `val`.
+ * If `n` is beyond the current bounds, the array is expanded to accommodate
+ * the new element, and any intermediate elements are filled with `nil`.
+ * If `n` is negative, it counts from the end of the array.
+ * An IndexError is raised if a negative index points past the beginning of the array.
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) to modify.
+ * @param n The index at which to set the element.
+ * @param val The mrb_value to set at the specified index.
+ */
MRB_API void
mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
{
@@ -784,6 +1123,7 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val)
mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val);
}
+/* Creates a duplicate of an array */
static struct RArray*
ary_dup(mrb_state *mrb, struct RArray *a)
{
@@ -791,13 +1131,36 @@ ary_dup(mrb_state *mrb, struct RArray *a)
}
MRB_API mrb_value
+mrb_ary_dup(mrb_state *mrb, mrb_value ary)
+{
+ return mrb_obj_value(ary_dup(mrb, mrb_ary_ptr(ary)));
+}
+
+/**
+ * Replaces a portion of an array with elements from another array or a single value.
+ *
+ * Removes `len` elements from `ary` starting at `head` index, and inserts
+ * the elements from `rpl` (if `rpl` is an array) or `rpl` itself (if it's not an array)
+ * at that position.
+ * If `head` is negative, it counts from the end of the array.
+ * If `len` is negative, an IndexError is raised.
+ * If `rpl` is `mrb_undef_p()`, then the elements are removed without replacement.
+ * This function modifies the `ary` array in place.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) to modify.
+ * @param head The starting index for the splice operation.
+ * @param len The number of elements to remove.
+ * @param rpl The mrb_value to insert (can be an array or a single value, or mrb_undef_p()).
+ * @return The modified array (the same mrb_value as `ary`).
+ */
+MRB_API mrb_value
mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl)
{
struct RArray *a = mrb_ary_ptr(ary);
mrb_int alen = ARY_LEN(a);
const mrb_value *argv;
mrb_int argc;
- mrb_int tail;
ary_modify(mrb, a);
@@ -813,7 +1176,8 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
out_of_range:
mrb_raisef(mrb, E_INDEX_ERROR, "index %i is out of array", head);
}
- tail = head + len;
+
+ mrb_int tail = head + len;
if (alen < len || alen < tail) {
len = alen - head;
tail = head + len;
@@ -854,7 +1218,6 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val
ARY_SET_LEN(a, len);
}
else {
-
if (alen - len > ARY_MAX_SIZE - argc) {
head = alen + argc - len;
goto out_of_range;
@@ -887,6 +1250,7 @@ mrb_ary_decref(mrb_state *mrb, mrb_shared_array *shared)
}
}
+/* Creates a subsequence array, using shared storage when appropriate */
static mrb_value
ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
{
@@ -906,6 +1270,19 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
return mrb_obj_value(b);
}
+/**
+ * Creates a new array that is a subsequence of an existing array.
+ *
+ * The new array contains `len` elements, starting from index `beg` of the
+ * original `ary`.
+ * This function attempts to create a shared array if appropriate for efficiency.
+ *
+ * @param mrb The mruby state.
+ * @param ary The original array (mrb_value).
+ * @param beg The starting index of the subsequence.
+ * @param len The length of the subsequence.
+ * @return A new mrb_value representing the subsequence array.
+ */
mrb_value
mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len)
{
@@ -913,6 +1290,7 @@ mrb_ary_subseq(mrb_state *mrb, mrb_value ary, mrb_int beg, mrb_int len)
return ary_subseq(mrb, a, beg, len);
}
+/* Converts various types to array index integer */
static mrb_int
aget_index(mrb_state *mrb, mrb_value index)
{
@@ -942,16 +1320,16 @@ aget_index(mrb_state *mrb, mrb_value index)
* 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.
+ * 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
+ * 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.
+ * Returns `nil` if the index (or starting index) are out of range.
*
* a = [ "a", "b", "c", "d", "e" ]
* a[1] => "b"
@@ -1003,16 +1381,16 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self)
* ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil
* ary[range] = obj or other_ary or nil -> obj or other_ary or nil
*
- * Element Assignment --- Sets the element at +index+, or replaces a subarray
- * from the +start+ index for +length+ elements, or replaces a subarray
- * specified by the +range+ of indices.
+ * Element Assignment --- Sets the element at `index`, or replaces a subarray
+ * from the `start` index for `length` elements, or replaces a subarray
+ * specified by the `range` of indices.
*
* If indices are greater than the current capacity of the array, the array
- * grows automatically. Elements are inserted into the array at +start+ if
- * +length+ is zero.
+ * grows automatically. Elements are inserted into the array at `start` if
+ * `length` is zero.
*
* Negative indices will count backward from the end of the array. For
- * +start+ and +range+ cases the starting index is just before an element.
+ * `start` and `range` cases the starting index is just before an element.
*
* An IndexError is raised if a negative index points past the beginning of
* the array.
@@ -1090,6 +1468,27 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self)
return val;
}
+/*
+ * call-seq:
+ * array.first -> object or nil
+ * array.first(n) -> new_array
+ *
+ * Returns elements from the beginning of `self`.
+ *
+ * When no argument is given, returns the first element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first # => :foo
+ * a # => [:foo, "bar", 2]
+ *
+ * If `self` is empty, returns `nil`.
+ *
+ * When non-negative Integer argument `n` is given,
+ * returns the first `n` elements in a new Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(2) # => [:foo, "bar"]
+ */
static mrb_value
mrb_ary_first(mrb_state *mrb, mrb_value self)
{
@@ -1113,6 +1512,27 @@ mrb_ary_first(mrb_state *mrb, mrb_value self)
return mrb_ary_new_from_values(mrb, size, ARY_PTR(a));
}
+/*
+ * call-seq:
+ * array.last -> object or nil
+ * array.last(n) -> new_array
+ *
+ * Returns elements from the end of `self`.
+ *
+ * When no argument is given, returns the last element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last # => 2
+ * a # => [:foo, "bar", 2]
+ *
+ * If `self` is empty, returns `nil`.
+ *
+ * When non-negative Integer argument `n` is given,
+ * returns the last `n` elements in a new Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(2) # => ["bar", 2]
+ */
static mrb_value
mrb_ary_last(mrb_state *mrb, mrb_value self)
{
@@ -1141,11 +1561,11 @@ mrb_ary_last(mrb_state *mrb, mrb_value self)
* 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+.
+ * 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
+ * first object for which the block returns `true`. Returns `nil` if no
* match is found.
*
* ISO 15.2.12.5.14
@@ -1183,11 +1603,11 @@ mrb_ary_index_m(mrb_state *mrb, mrb_value self)
* 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+.
+ * 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
+ * first object for which the block returns `true`. Returns `nil` if no
* match is found.
*
* ISO 15.2.12.5.26
@@ -1219,6 +1639,20 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self)
return mrb_nil_value();
}
+/**
+ * Creates a new array from a given value, performing a "splat" operation.
+ *
+ * If `v` is already an array, a duplicate of `v` is returned.
+ * If `v` responds to `to_a`, it is called, and if the result is an array,
+ * a duplicate of that result is returned. If `to_a` returns `nil` or something
+ * other than an array, `v` itself is wrapped in a new, single-element array.
+ * Otherwise (if `v` is not an array and does not respond to `to_a`),
+ * `v` itself is wrapped in a new, single-element array.
+ *
+ * @param mrb The mruby state.
+ * @param v The mrb_value to convert into an array.
+ * @return A new mrb_value representing the "splatted" array.
+ */
MRB_API mrb_value
mrb_ary_splat(mrb_state *mrb, mrb_value v)
{
@@ -1243,6 +1677,16 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v)
return mrb_obj_value(a);
}
+/*
+ * call-seq:
+ * array.size -> integer
+ * array.length -> integer
+ *
+ * Returns the count of elements in `self`:
+ *
+ * [0, 1, 2].size # => 3
+ * [].size # => 0
+ */
static mrb_value
mrb_ary_size(mrb_state *mrb, mrb_value self)
{
@@ -1251,6 +1695,15 @@ mrb_ary_size(mrb_state *mrb, mrb_value self)
return mrb_int_value(mrb, ARY_LEN(a));
}
+/**
+ * Removes all elements from an array, making it empty.
+ *
+ * This function modifies the array in place.
+ *
+ * @param mrb The mruby state.
+ * @param self The array (mrb_value) to clear.
+ * @return The cleared (now empty) array (the same mrb_value as `self`).
+ */
MRB_API mrb_value
mrb_ary_clear(mrb_state *mrb, mrb_value self)
{
@@ -1275,6 +1728,16 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self)
return self;
}
+/*
+ * call-seq:
+ * array.empty? -> true or false
+ *
+ * Returns `true` if the count of elements in `self` is zero,
+ * `false` otherwise:
+ *
+ * [].empty? # => true
+ * [0].empty? # => false
+ */
static mrb_value
mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
{
@@ -1283,6 +1746,19 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self)
return mrb_bool_value(ARY_LEN(a) == 0);
}
+/**
+ * Retrieves an element from an array at a specific index.
+ * This is a direct (unsafe) equivalent of `RARRAY_PTR(ary)[n]`.
+ *
+ * If `n` is negative, it counts from the end of the array.
+ * Returns `nil` if the index is out of bounds.
+ * This function does not perform a bounds check before accessing the element if the index is positive.
+ * Prefer using `mrb_ary_ref` for safe access or ensure `n` is within bounds.
+ *
+ * @param ary The array (mrb_value) from which to retrieve the element.
+ * @param n The index of the element to retrieve.
+ * @return The mrb_value at the specified index, or `nil` if out of bounds.
+ */
MRB_API mrb_value
mrb_ary_entry(mrb_value ary, mrb_int n)
{
@@ -1351,6 +1827,20 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
return result;
}
+/**
+ * Joins the elements of an array into a string, separated by a given separator.
+ *
+ * Each element of `ary` is converted to a string. These strings are then
+ * concatenated, with the string representation of `sep` inserted between
+ * adjacent elements.
+ * If `sep` is `nil`, no separator is used.
+ * This function handles recursive array joins by raising an E_ARGUMENT_ERROR.
+ *
+ * @param mrb The mruby state.
+ * @param ary The array (mrb_value) whose elements are to be joined.
+ * @param sep The separator (mrb_value) to use between elements. Can be `nil`.
+ * @return A new mrb_value string representing the joined array elements.
+ */
MRB_API mrb_value
mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
{
@@ -1365,7 +1855,7 @@ mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
* ary.join(sep="") -> str
*
* Returns a string created by converting each element of the array to
- * a string, separated by <i>sep</i>.
+ * a string, separated by *sep*.
*
* [ "a", "b", "c" ].join #=> "abc"
* [ "a", "b", "c" ].join("-") #=> "a-b-c"
@@ -1393,7 +1883,7 @@ mrb_ary_to_s(mrb_state *mrb, mrb_value self)
mrb->c->ci->mid = MRB_SYM(inspect);
mrb_value ret = mrb_str_new_lit(mrb, "[");
int ai = mrb_gc_arena_save(mrb);
- if (mrb_inspect_recursive_p(mrb, self)) {
+ if (MRB_RECURSIVE_UNARY_P(mrb, MRB_SYM(inspect), self)) {
mrb_str_cat_lit(mrb, ret, "...]");
return ret;
}
@@ -1407,7 +1897,7 @@ mrb_ary_to_s(mrb_state *mrb, mrb_value self)
return ret;
}
-/* check array equality: 1=equal,0=not_equal,-1=need_elments_check */
+/* check array equality: 1=equal,0=not_equal,-1=need_elements_check */
static mrb_int
ary_eq(mrb_state *mrb, mrb_value ary1, mrb_value ary2)
{
@@ -1436,6 +1926,11 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
if (n == 1) return mrb_true_value();
if (n == 0) return mrb_false_value();
+ /* Check for recursion */
+ if (MRB_RECURSIVE_BINARY_FUNC_P(mrb, MRB_OPSYM(eq), ary1, ary2)) {
+ return mrb_false_value();
+ }
+
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i=0; i<RARRAY_LEN(ary1); i++) {
mrb_value eq = mrb_funcall_id(mrb, mrb_ary_entry(ary1, i), MRB_OPSYM(eq), 1, mrb_ary_entry(ary2, i));
@@ -1449,7 +1944,7 @@ mrb_ary_eq(mrb_state *mrb, mrb_value ary1)
* call-seq:
* array.eql? other_array -> true or false
*
- * Returns <code>true</code> if +self+ and _other_ are the same object,
+ * Returns `true` if `self` and _other_ are the same object,
* or are both arrays with the same content.
*
*/
@@ -1462,6 +1957,11 @@ mrb_ary_eql(mrb_state *mrb, mrb_value ary1)
if (n == 1) return mrb_true_value();
if (n == 0) return mrb_false_value();
+ /* Check for recursion */
+ if (MRB_RECURSIVE_BINARY_FUNC_P(mrb, MRB_SYM_Q(eql), ary1, ary2)) {
+ return mrb_false_value();
+ }
+
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i=0; i<RARRAY_LEN(ary1); i++) {
mrb_value eq = mrb_funcall_id(mrb, mrb_ary_entry(ary1, i), MRB_SYM_Q(eql), 1, mrb_ary_entry(ary2, i));
@@ -1476,12 +1976,12 @@ mrb_ary_eql(mrb_state *mrb, mrb_value ary1)
* array <=> other_array -> -1, 0, or 1
*
* Comparison---Returns an integer (-1, 0, or +1)
- * if this array is less than, equal to, or greater than <i>other_ary</i>.
+ * if this array is less than, equal to, or greater than *other_ary*.
* Each object in each array is compared (using <=>). If any value isn't
* equal, then that inequality is the return value. If all the
* values found are equal, then the return is based on a
* comparison of the array lengths. Thus, two arrays are
- * "equal" according to <code>Array*<=></code> if and only if they have
+ * "equal" according to `Array#<=>` if and only if they have
* the same length and the value of each element is equal to the
* value of the corresponding element in the other array.
*/
@@ -1578,31 +2078,60 @@ mrb_ary_delete(mrb_state *mrb, mrb_value self)
return ret;
}
-static mrb_noreturn void
-cmp_failed(mrb_state *mrb, mrb_int a, mrb_int b)
-{
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison failed (element %d and %d)", a, b);
-}
+
+#define SMALL_ARRAY_SORT_THRESHOLD 16
+
static mrb_bool
-sort_cmp(mrb_state *mrb, mrb_value ary, mrb_value *p, mrb_int a, mrb_int b, mrb_value blk)
+sort_cmp(mrb_state *mrb, mrb_value ary, mrb_value a_val, mrb_value b_val, mrb_value blk)
{
+ mrb_value *p = RARRAY_PTR(ary);
+ mrb_int n = RARRAY_LEN(ary);
+
mrb_int cmp;
+ int ai = mrb_gc_arena_save(mrb);
if (mrb_nil_p(blk)) {
- cmp = mrb_cmp(mrb, p[a], p[b]);
- if (cmp == -2) cmp_failed(mrb, a, b);
+ enum mrb_vtype type_a = mrb_type(a_val);
+ enum mrb_vtype type_b = mrb_type(b_val);
+
+ if (type_a == type_b) {
+ switch (type_a) {
+ case MRB_TT_FIXNUM:
+ cmp = (mrb_fixnum(a_val) > mrb_fixnum(b_val)) ? 1 : (mrb_fixnum(a_val) < mrb_fixnum(b_val)) ? -1 : 0;
+ break;
+#ifndef MRB_NO_FLOAT
+ case MRB_TT_FLOAT:
+ cmp = (mrb_float(a_val) > mrb_float(b_val)) ? 1 : (mrb_float(a_val) < mrb_float(b_val)) ? -1 : 0;
+ break;
+#endif
+ case MRB_TT_STRING:
+ cmp = mrb_str_cmp(mrb, a_val, b_val);
+ break;
+ default:
+ cmp = mrb_cmp(mrb, a_val, b_val);
+ break;
+ }
+ }
+ else {
+ cmp = mrb_cmp(mrb, a_val, b_val);
+ }
}
else {
- mrb_value args[2] = {p[a], p[b]};
+ mrb_value args[2] = {a_val, b_val};
mrb_value c = mrb_yield_argv(mrb, blk, 2, args);
if (mrb_nil_p(c) || !mrb_fixnum_p(c)) {
- cmp_failed(mrb, a, b);
+ cmp = -2;
}
- cmp = mrb_fixnum(c);
+ else {
+ cmp = mrb_fixnum(c);
+ }
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ if (cmp == -2) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "comparison failed");
}
- mrb_int size = RARRAY_LEN(ary);
- if (RARRAY_PTR(ary) != p || size < a || size < b) {
+ if (RARRAY_PTR(ary) != p || RARRAY_LEN(ary) != n) {
mrb_raise(mrb, E_RUNTIME_ERROR, "array modified during sort");
}
return cmp > 0;
@@ -1611,20 +2140,52 @@ sort_cmp(mrb_state *mrb, mrb_value ary, mrb_value *p, mrb_int a, mrb_int b, mrb_
static void
heapify(mrb_state *mrb, mrb_value ary, mrb_value *a, mrb_int index, mrb_int size, mrb_value blk)
{
- mrb_int max = index;
- mrb_int left_index = 2 * index + 1;
- mrb_int right_index = left_index + 1;
- if (left_index < size && sort_cmp(mrb, ary, a, left_index, max, blk)) {
- max = left_index;
- }
- if (right_index < size && sort_cmp(mrb, ary, a, right_index, max, blk)) {
- max = right_index;
- }
- if (max != index) {
+ /* Iterative heapify to avoid stack overflow on memory-constrained devices */
+ while (1) {
+ mrb_int max = index;
+ mrb_int left_index = 2 * index + 1;
+ mrb_int right_index = left_index + 1;
+
+ if (left_index < size && sort_cmp(mrb, ary, a[left_index], a[max], blk)) {
+ max = left_index;
+ }
+ if (right_index < size && sort_cmp(mrb, ary, a[right_index], a[max], blk)) {
+ max = right_index;
+ }
+
+ if (max == index) {
+ /* Heap property satisfied, no more swaps needed */
+ break;
+ }
+
+ /* Swap elements and continue heapifying down the affected subtree */
mrb_value tmp = a[max];
a[max] = a[index];
a[index] = tmp;
- heapify(mrb, ary, a, max, size, blk);
+
+ /* Continue with the affected child subtree */
+ index = max;
+ }
+}
+
+static void
+insertion_sort(mrb_state *mrb, mrb_value ary, mrb_value *a, mrb_int size, mrb_value blk)
+{
+ int ai = mrb_gc_arena_save(mrb);
+ for (mrb_int i = 1; i < size; i++) {
+ mrb_value key = a[i];
+ mrb_int j = i - 1;
+
+ /* Protect key from GC - it's temporarily out of the array during sort */
+ mrb_gc_protect(mrb, key);
+
+ /* Move elements that are greater than key to one position ahead */
+ while (j >= 0 && sort_cmp(mrb, ary, a[j], key, blk)) {
+ a[j + 1] = a[j];
+ j--;
+ }
+ a[j + 1] = key;
+ mrb_gc_arena_restore(mrb, ai);
}
}
@@ -1633,7 +2194,7 @@ heapify(mrb_state *mrb, mrb_value ary, mrb_value *a, mrb_int index, mrb_int size
* array.sort! -> self
* array.sort! {|a, b| ... } -> self
*
- * Sort all elements and replace +self+ with these
+ * Sort all elements and replace `self` with these
* elements.
*/
static mrb_value
@@ -1648,18 +2209,84 @@ mrb_ary_sort_bang(mrb_state *mrb, mrb_value ary)
mrb_get_args(mrb, "&", &blk);
mrb_value *a = RARRAY_PTR(ary);
- for (mrb_int i = n / 2 - 1; i > -1; i--) {
- heapify(mrb, ary, a, i, n, blk);
+
+ /* Algorithm selection based on array size */
+ if (n <= SMALL_ARRAY_SORT_THRESHOLD) {
+ /* Use insertion sort for small arrays */
+ insertion_sort(mrb, ary, a, n, blk);
}
- for (mrb_int i = n - 1; i > 0; i--) {
- mrb_value tmp = a[0];
- a[0] = a[i];
- a[i] = tmp;
- heapify(mrb, ary, a, 0, i, blk);
+ else {
+ /* Use heap sort for larger arrays */
+ for (mrb_int i = n / 2 - 1; i >= 0; i--) {
+ heapify(mrb, ary, a, i, n, blk);
+ }
+ for (mrb_int i = n - 1; i > 0; i--) {
+ mrb_value tmp = a[0];
+ a[0] = a[i];
+ a[i] = tmp;
+ heapify(mrb, ary, a, 0, i, blk);
+ }
}
return ary;
}
+/*
+ * call-seq:
+ * array.to_a -> self
+ *
+ * Returns self. If called on a subclass of Array, converts
+ * the receiver to an Array object.
+ */
+static mrb_value
+mrb_ary_to_a(mrb_state *mrb, mrb_value self)
+{
+ if (mrb_obj_class(mrb, self) != mrb->array_class) {
+ /* Convert subclass to Array */
+ return mrb_ary_dup(mrb, self);
+ }
+ return self;
+}
+
+/* ---------------------------*/
+static const mrb_mt_entry array_rom_entries[] = {
+ MRB_MT_ENTRY(mrb_ary_plus, MRB_OPSYM(add), MRB_ARGS_REQ(1)), /* 15.2.12.5.1 */
+ MRB_MT_ENTRY(mrb_ary_times, MRB_OPSYM(mul), MRB_ARGS_REQ(1)), /* 15.2.12.5.2 */
+ MRB_MT_ENTRY(mrb_ary_push_m, MRB_OPSYM(lshift), MRB_ARGS_REQ(1)), /* 15.2.12.5.3 */
+ MRB_MT_ENTRY(mrb_ary_aget, MRB_OPSYM(aref), MRB_ARGS_ARG(1,1)), /* 15.2.12.5.4 */
+ MRB_MT_ENTRY(mrb_ary_aset, MRB_OPSYM(aset), MRB_ARGS_ARG(2,1)), /* 15.2.12.5.5 */
+ MRB_MT_ENTRY(mrb_ary_clear, MRB_SYM(clear), MRB_ARGS_NONE()), /* 15.2.12.5.6 */
+ MRB_MT_ENTRY(mrb_ary_cmp, MRB_OPSYM(cmp), MRB_ARGS_REQ(1)),
+ MRB_MT_ENTRY(mrb_ary_concat_m, MRB_SYM(concat), MRB_ARGS_REQ(1)), /* 15.2.12.5.8 */
+ MRB_MT_ENTRY(mrb_ary_delete, MRB_SYM(delete), MRB_ARGS_REQ(1)),
+ MRB_MT_ENTRY(mrb_ary_delete_at, MRB_SYM(delete_at), MRB_ARGS_REQ(1)), /* 15.2.12.5.9 */
+ MRB_MT_ENTRY(mrb_ary_empty_p, MRB_SYM_Q(empty), MRB_ARGS_NONE()), /* 15.2.12.5.12 */
+ MRB_MT_ENTRY(mrb_ary_eq, MRB_OPSYM(eq), MRB_ARGS_REQ(1)),
+ MRB_MT_ENTRY(mrb_ary_eql, MRB_SYM_Q(eql), MRB_ARGS_REQ(1)),
+ MRB_MT_ENTRY(mrb_ary_first, MRB_SYM(first), MRB_ARGS_OPT(1)), /* 15.2.12.5.13 */
+ MRB_MT_ENTRY(mrb_ary_index_m, MRB_SYM(index), MRB_ARGS_OPT(1)), /* 15.2.12.5.14 */
+ MRB_MT_ENTRY(mrb_ary_init, MRB_SYM(initialize), MRB_ARGS_OPT(2) | MRB_MT_PRIVATE), /* 15.2.12.5.15 */
+ MRB_MT_ENTRY(mrb_ary_replace_m, MRB_SYM(initialize_copy), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), /* 15.2.12.5.16 */
+ MRB_MT_ENTRY(mrb_ary_join_m, MRB_SYM(join), MRB_ARGS_OPT(1)), /* 15.2.12.5.17 */
+ MRB_MT_ENTRY(mrb_ary_last, MRB_SYM(last), MRB_ARGS_OPT(1)), /* 15.2.12.5.18 */
+ MRB_MT_ENTRY(mrb_ary_size, MRB_SYM(length), MRB_ARGS_NONE()), /* 15.2.12.5.19 */
+ MRB_MT_ENTRY(mrb_ary_pop, MRB_SYM(pop), MRB_ARGS_NONE()), /* 15.2.12.5.21 */
+ MRB_MT_ENTRY(mrb_ary_push_m, MRB_SYM(push), MRB_ARGS_ANY()), /* 15.2.12.5.22 */
+ MRB_MT_ENTRY(mrb_ary_replace_m, MRB_SYM(replace), MRB_ARGS_REQ(1)), /* 15.2.12.5.23 */
+ MRB_MT_ENTRY(mrb_ary_reverse, MRB_SYM(reverse), MRB_ARGS_NONE()), /* 15.2.12.5.24 */
+ MRB_MT_ENTRY(mrb_ary_reverse_bang, MRB_SYM_B(reverse), MRB_ARGS_NONE()), /* 15.2.12.5.25 */
+ MRB_MT_ENTRY(mrb_ary_rindex_m, MRB_SYM(rindex), MRB_ARGS_OPT(1)), /* 15.2.12.5.26 */
+ MRB_MT_ENTRY(mrb_ary_shift_m, MRB_SYM(shift), MRB_ARGS_OPT(1)), /* 15.2.12.5.27 */
+ MRB_MT_ENTRY(mrb_ary_size, MRB_SYM(size), MRB_ARGS_NONE()), /* 15.2.12.5.28 */
+ MRB_MT_ENTRY(mrb_ary_aget, MRB_SYM(slice), MRB_ARGS_ARG(1,1)), /* 15.2.12.5.29 */
+ MRB_MT_ENTRY(mrb_ary_unshift_m, MRB_SYM(unshift), MRB_ARGS_ANY()), /* 15.2.12.5.30 */
+ MRB_MT_ENTRY(mrb_ary_to_a, MRB_SYM(to_a), MRB_ARGS_NONE()),
+ MRB_MT_ENTRY(mrb_ary_to_a, MRB_SYM(entries), MRB_ARGS_NONE()),
+ MRB_MT_ENTRY(mrb_ary_to_s, MRB_SYM(to_s), MRB_ARGS_NONE()),
+ MRB_MT_ENTRY(mrb_ary_to_s, MRB_SYM(inspect), MRB_ARGS_NONE()),
+ MRB_MT_ENTRY(mrb_ary_sort_bang, MRB_SYM_B(sort), MRB_ARGS_NONE()),
+ MRB_MT_ENTRY(mrb_ary_svalue, MRB_SYM(__svalue), MRB_ARGS_NONE()),
+};
+
void
mrb_init_array(mrb_state *mrb)
{
@@ -1670,39 +2297,5 @@ mrb_init_array(mrb_state *mrb)
mrb_define_class_method_id(mrb, a, MRB_OPSYM(aref), mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(add), mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(mul), mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(lshift), mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(aref), mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(aset), mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */
- mrb_define_method_id(mrb, a, MRB_SYM(clear), mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(cmp), mrb_ary_cmp, MRB_ARGS_REQ(1));
- mrb_define_method_id(mrb, a, MRB_SYM(concat), mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */
- mrb_define_method_id(mrb, a, MRB_SYM(delete), mrb_ary_delete, MRB_ARGS_REQ(1));
- mrb_define_method_id(mrb, a, MRB_SYM(delete_at), mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */
- mrb_define_method_id(mrb, a, MRB_SYM_Q(empty), mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */
- mrb_define_method_id(mrb, a, MRB_OPSYM(eq), mrb_ary_eq, MRB_ARGS_REQ(1));
- mrb_define_method_id(mrb, a, MRB_SYM_Q(eql), mrb_ary_eql, MRB_ARGS_REQ(1));
- mrb_define_method_id(mrb, a, MRB_SYM(first), mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */
- mrb_define_method_id(mrb, a, MRB_SYM(index), mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */
- mrb_define_method_id(mrb, a, MRB_SYM(initialize), mrb_ary_init, MRB_ARGS_OPT(2)); /* 15.2.12.5.15 */
- mrb_define_method_id(mrb, a, MRB_SYM(initialize_copy), mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */
- mrb_define_method_id(mrb, a, MRB_SYM(join), mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */
- mrb_define_method_id(mrb, a, MRB_SYM(last), mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */
- mrb_define_method_id(mrb, a, MRB_SYM(length), mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
- mrb_define_method_id(mrb, a, MRB_SYM(pop), mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
- mrb_define_method_id(mrb, a, MRB_SYM(push), mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
- mrb_define_method_id(mrb, a, MRB_SYM(replace), mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
- mrb_define_method_id(mrb, a, MRB_SYM(reverse), mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
- mrb_define_method_id(mrb, a, MRB_SYM_B(reverse), mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
- mrb_define_method_id(mrb, a, MRB_SYM(rindex), mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */
- mrb_define_method_id(mrb, a, MRB_SYM(shift), mrb_ary_shift_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.27 */
- mrb_define_method_id(mrb, a, MRB_SYM(size), mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
- mrb_define_method_id(mrb, a, MRB_SYM(slice), mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */
- mrb_define_method_id(mrb, a, MRB_SYM(unshift), mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
- mrb_define_method_id(mrb, a, MRB_SYM(to_s), mrb_ary_to_s, MRB_ARGS_NONE());
- 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(__svalue), mrb_ary_svalue, MRB_ARGS_NONE());
+ MRB_MT_INIT_ROM(mrb, a, array_rom_entries);
}