summaryrefslogtreecommitdiffhomepage
path: root/src/array.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/array.c')
-rw-r--r--src/array.c192
1 files changed, 135 insertions, 57 deletions
diff --git a/src/array.c b/src/array.c
index 966d4956c..9fe11bee0 100644
--- a/src/array.c
+++ b/src/array.c
@@ -4,16 +4,11 @@
** See Copyright Notice in mruby.h
*/
-#ifndef SIZE_MAX
- /* Some versions of VC++
- * has SIZE_MAX in stdint.h
- */
-# include <limits.h>
-#endif
#include "mruby.h"
#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
@@ -309,7 +304,7 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
a1 = RARRAY(ary1); a2 = RARRAY(ary2);
if (a1->len == a2->len && a1->ptr == a2->ptr) return mrb_fixnum_value(0);
else {
- mrb_sym cmp = mrb_intern2(mrb, "<=>", 3);
+ mrb_sym cmp = mrb_intern_lit(mrb, "<=>");
len = RARRAY_LEN(ary1);
if (len > RARRAY_LEN(ary2)) {
@@ -318,7 +313,7 @@ mrb_ary_cmp(mrb_state *mrb, mrb_value ary1)
for (i=0; i<len; i++) {
mrb_value v = ary_elt(ary2, i);
r = mrb_funcall_argv(mrb, ary_elt(ary1, i), cmp, 1, &v);
- if (mrb_type(r) != MRB_TT_FIXNUM || mrb_fixnum(r) != 0) return r;
+ if (!mrb_fixnum_p(r) || mrb_fixnum(r) != 0) return r;
}
}
len = a1->len - a2->len;
@@ -683,63 +678,144 @@ 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_type(argv[0]) != MRB_TT_FIXNUM) {
- 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)) {
+ /* a[n..m] */
+ case MRB_TT_RANGE:
+ if (mrb_range_beg_len(mrb, index, &i, &len, a->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);
}
+/*
+ * call-seq:
+ * ary[index] = obj -> obj
+ * 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.
+ *
+ * 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.
+ *
+ * Negative indices will count backward from the end of the array. For
+ * +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.
+ *
+ * See also Array#push, and Array#unshift.
+ *
+ * a = Array.new
+ * a[4] = "4"; #=> [nil, nil, nil, nil, "4"]
+ * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
+ * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"]
+ * a[0, 2] = "?" #=> ["?", 2, nil, "4"]
+ * a[0..2] = "A" #=> ["A", "4"]
+ * a[-1] = "Z" #=> ["A", "Z"]
+ * a[1..-1] = nil #=> ["A", nil]
+ * a[1..-1] = [] #=> ["A"]
+ * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"]
+ * a[3, 0] = "B" #=> [1, 2, "A", "B"]
+ */
+
mrb_value
mrb_ary_aset(mrb_state *mrb, mrb_value self)
{
- mrb_value *argv;
- int argc;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- switch(argc) {
- case 2:
- if (!mrb_fixnum_p(argv[0])) {
- /* Should we support Range object for 1st arg ? */
- mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum for 1st argument");
- }
- mrb_ary_set(mrb, self, mrb_fixnum(argv[0]), argv[1]);
- return argv[1];
-
- case 3:
- mrb_ary_splice(mrb, self, mrb_fixnum(argv[0]), mrb_fixnum(argv[1]), argv[2]);
- return argv[2];
+ mrb_value v1, v2, v3;
+ mrb_int i, len;
- default:
- mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
- return mrb_nil_value();
+ if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) {
+ switch (mrb_type(v1)) {
+ /* a[n..m] = v */
+ case MRB_TT_RANGE:
+ if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) {
+ mrb_ary_splice(mrb, self, i, len, v2);
+ }
+ break;
+ /* a[n] = v */
+ case MRB_TT_FIXNUM:
+ mrb_ary_set(mrb, self, mrb_fixnum(v1), v2);
+ break;
+ default:
+ mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
+ break;
+ }
+ return v2;
}
+
+ /* a[n,m] = v */
+ mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3);
+ return v3;
}
mrb_value
@@ -854,6 +930,9 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v)
if (mrb_array_p(v)) {
return v;
}
+ if (mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) {
+ return mrb_funcall(mrb, v, "to_a", 0);
+ }
else {
return mrb_ary_new_from_values(mrb, 1, &v);
}
@@ -916,7 +995,7 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
/* check recursive */
for(i=0; i<RARRAY_LEN(list); i++) {
if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
- return mrb_str_new(mrb, "[...]", 5);
+ return mrb_str_new_lit(mrb, "[...]");
}
}
@@ -959,7 +1038,7 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
static mrb_value
mrb_ary_inspect(mrb_state *mrb, mrb_value ary)
{
- if (RARRAY_LEN(ary) == 0) return mrb_str_new(mrb, "[]", 2);
+ if (RARRAY_LEN(ary) == 0) return mrb_str_new_lit(mrb, "[]");
return inspect_ary(mrb, ary, mrb_ary_new(mrb));
}
@@ -1070,7 +1149,7 @@ mrb_ary_equal(mrb_state *mrb, mrb_value ary1)
if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
if (mrb_special_const_p(ary2)) return mrb_false_value();
if (!mrb_array_p(ary2)) {
- if (!mrb_respond_to(mrb, ary2, mrb_intern2(mrb, "to_ary", 6))) {
+ if (!mrb_respond_to(mrb, ary2, mrb_intern_lit(mrb, "to_ary"))) {
return mrb_false_value();
}
else {
@@ -1120,12 +1199,11 @@ mrb_init_array(mrb_state *mrb)
a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class);
MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY);
- mrb_include_module(mrb, a, mrb_class_get(mrb, "Enumerable"));
mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
- mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
- mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
+ mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
+ mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */
mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */