Index: EcnlProtoTool/trunk/mruby-1.3.0/src/array.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/src/array.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/src/array.c	(revision 331)
@@ -5,9 +5,9 @@
 */
 
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/string.h"
-#include "mruby/range.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/string.h>
+#include <mruby/range.h>
 #include "value_array.h"
 
@@ -17,18 +17,9 @@
 #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
 
-static inline mrb_value
-ary_elt(mrb_value ary, mrb_int offset)
-{
-  if (offset < 0 || RARRAY_LEN(ary) <= offset) {
-    return mrb_nil_value();
-  }
-  return RARRAY_PTR(ary)[offset];
-}
-
 static struct RArray*
 ary_new_capa(mrb_state *mrb, mrb_int capa)
 {
   struct RArray *a;
-  mrb_int blen;
+  size_t blen;
 
   if (capa > ARY_MAX_SIZE) {
@@ -36,7 +27,4 @@
   }
   blen = capa * sizeof(mrb_value);
-  if (blen < capa) {
-    mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
-  }
 
   a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
@@ -121,4 +109,8 @@
 ary_modify(mrb_state *mrb, struct RArray *a)
 {
+  if (MRB_FROZEN_P(a)) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
+  }
+
   if (ARY_SHARED_P(a)) {
     mrb_shared_array *shared = a->aux.shared;
@@ -179,4 +171,5 @@
 
   if (len > ARY_MAX_SIZE) {
+  size_error:
     mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
   }
@@ -186,8 +179,14 @@
   }
   while (capa < len) {
-    capa *= 2;
-  }
-
-  if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
+    if (capa <= ARY_MAX_SIZE / 2) {
+      capa *= 2;
+    }
+    else {
+      capa = len;
+    }
+  }
+  if (capa < len || capa > ARY_MAX_SIZE) {
+    goto size_error;
+  }
 
   if (capa > a->aux.capa) {
@@ -244,22 +243,34 @@
 
 static mrb_value
-mrb_ary_s_create(mrb_state *mrb, mrb_value self)
-{
+mrb_ary_s_create(mrb_state *mrb, mrb_value klass)
+{
+  mrb_value ary;
   mrb_value *vals;
   mrb_int len;
+  struct RArray *a;
 
   mrb_get_args(mrb, "*", &vals, &len);
-
-  return mrb_ary_new_from_values(mrb, len, vals);
+  ary = mrb_ary_new_from_values(mrb, len, vals);
+  a = mrb_ary_ptr(ary);
+  a->c = mrb_class_ptr(klass);
+
+  return ary;
 }
 
 static void
-ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen)
-{
-  mrb_int len = a->len + blen;
+ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2)
+{
+  mrb_int len;
+
+  if (a2->len > ARY_MAX_SIZE - a->len) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+  }
+  len = a->len + a2->len;
 
   ary_modify(mrb, a);
-  if (a->aux.capa < len) ary_expand_capa(mrb, a, len);
-  array_copy(a->ptr+a->len, ptr, blen);
+  if (a->aux.capa < len) {
+    ary_expand_capa(mrb, a, len);
+  }
+  array_copy(a->ptr+a->len, a2->ptr, a2->len);
   mrb_write_barrier(mrb, (struct RBasic*)a);
   a->len = len;
@@ -271,5 +282,5 @@
   struct RArray *a2 = mrb_ary_ptr(other);
 
-  ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
+  ary_concat(mrb, mrb_ary_ptr(self), a2);
 }
 
@@ -277,9 +288,8 @@
 mrb_ary_concat_m(mrb_state *mrb, mrb_value self)
 {
-  mrb_value *ptr;
-  mrb_int blen;
-
-  mrb_get_args(mrb, "a", &ptr, &blen);
-  ary_concat(mrb, mrb_ary_ptr(self), ptr, blen);
+  mrb_value ary;
+
+  mrb_get_args(mrb, "A", &ary);
+  mrb_ary_concat(mrb, self, ary);
   return self;
 }
@@ -319,7 +329,10 @@
 mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other)
 {
+  struct RArray *a1 = mrb_ary_ptr(self);
   struct RArray *a2 = mrb_ary_ptr(other);
 
-  ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
+  if (a1 != a2) {
+    ary_replace(mrb, a1, a2->ptr, a2->len);
+  }
 }
 
@@ -433,4 +446,5 @@
   struct RArray *a = mrb_ary_ptr(ary);
 
+  ary_modify(mrb, a);
   if (a->len == 0) return mrb_nil_value();
   return a->ptr[--a->len];
@@ -445,4 +459,5 @@
   mrb_value val;
 
+  ary_modify(mrb, a);
   if (a->len == 0) return mrb_nil_value();
   if (ARY_SHARED_P(a)) {
@@ -507,4 +522,7 @@
 
   mrb_get_args(mrb, "*", &vals, &len);
+  if (len > ARY_MAX_SIZE - a->len) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
+  }
   if (ARY_SHARED_P(a)
       && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
@@ -564,11 +582,20 @@
 }
 
+static struct RArray*
+ary_dup(mrb_state *mrb, struct RArray *a)
+{
+  struct RArray *d = ary_new_capa(mrb, a->len);
+
+  ary_replace(mrb, d, a->ptr, a->len);
+  return d;
+}
+
 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 tail, size;
   const mrb_value *argv;
-  mrb_int i, argc;
+  mrb_int argc;
+  mrb_int tail;
 
   ary_modify(mrb, a);
@@ -584,8 +611,8 @@
     }
   }
-  if (a->len < len || a->len < head + len) {
+  tail = head + len;
+  if (a->len < len || a->len < tail) {
     len = a->len - head;
   }
-  tail = head + len;
 
   /* size check */
@@ -593,4 +620,13 @@
     argc = RARRAY_LEN(rpl);
     argv = RARRAY_PTR(rpl);
+    if (argv == a->ptr) {
+      struct RArray *r;
+
+      if (argc > 32767) {
+        mrb_raise(mrb, E_ARGUMENT_ERROR, "too big recursive splice");
+      }
+      r = ary_dup(mrb, a);
+      argv = r->ptr;
+    }
   }
   else {
@@ -598,24 +634,39 @@
     argv = &rpl;
   }
-  size = head + argc;
-
-  if (tail < a->len) size += a->len - tail;
-  if (size > a->aux.capa)
-    ary_expand_capa(mrb, a, size);
-
-  if (head > a->len) {
+  if (head >= a->len) {
+    if (head > ARY_MAX_SIZE - argc) {
+      mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head));
+    }
+    len = head + argc;
+    if (len > a->aux.capa) {
+      ary_expand_capa(mrb, a, head + argc);
+    }
     ary_fill_with_nil(a->ptr + a->len, head - a->len);
-  }
-  else if (head < a->len) {
-    value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
-  }
-
-  for (i = 0; i < argc; i++) {
-    *(a->ptr + head + i) = *(argv + i);
-    mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]);
-  }
-
-  a->len = size;
-
+    if (argc > 0) {
+      array_copy(a->ptr + head, argv, argc);
+    }
+    a->len = len;
+  }
+  else {
+    mrb_int alen;
+
+    if (a->len - len > ARY_MAX_SIZE - argc) {
+      mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len));
+    }
+    alen = a->len + argc - len;
+    if (alen > a->aux.capa) {
+      ary_expand_capa(mrb, a, alen);
+    }
+
+    if (len != argc) {
+      tail = head + len;
+      value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
+      a->len = alen;
+    }
+    if (argc > 0) {
+      value_move(a->ptr + head, argv, argc);
+    }
+  }
+  mrb_write_barrier(mrb, (struct RBasic*)a);
   return ary;
 }
@@ -703,5 +754,5 @@
       /* a[n..m] */
     case MRB_TT_RANGE:
-      if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) {
+      if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
         return ary_subseq(mrb, a, i, len);
       }
@@ -767,18 +818,16 @@
   mrb_int i, len;
 
+  mrb_ary_modify(mrb, mrb_ary_ptr(self));
   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);
-      }
+    switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) {
+    case 0:                   /* not range */
+      mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
       break;
-    /* a[n] = v */
-    case MRB_TT_FIXNUM:
-      mrb_ary_set(mrb, self, mrb_fixnum(v1), v2);
+    case 1:                   /* range */
+      mrb_ary_splice(mrb, self, i, len, v2);
       break;
-    default:
-      mrb_ary_set(mrb, self, aget_index(mrb, v1), v2);
+    case 2:                   /* out of range */
+      mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1);
       break;
     }
@@ -878,5 +927,5 @@
 {
   mrb_value obj;
-  mrb_int i;
+  mrb_int i, len;
 
   mrb_get_args(mrb, "o", &obj);
@@ -885,4 +934,7 @@
       return mrb_fixnum_value(i);
     }
+    if (i > (len = RARRAY_LEN(self))) {
+      i = len;
+    }
   }
   return mrb_nil_value();
@@ -892,12 +944,30 @@
 mrb_ary_splat(mrb_state *mrb, mrb_value v)
 {
+  mrb_value a, recv_class;
+
   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);
+
+  if (!mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) {
+    return mrb_ary_new_from_values(mrb, 1, &v);
+  }
+
+  a = mrb_funcall(mrb, v, "to_a", 0);
+  if (mrb_array_p(a)) {
+    return a;
+  }
+  else if (mrb_nil_p(a)) {
+    return mrb_ary_new_from_values(mrb, 1, &v);
   }
   else {
-    return mrb_ary_new_from_values(mrb, 1, &v);
+    recv_class = mrb_obj_value(mrb_obj_class(mrb, v));
+    mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)",
+      recv_class,
+      recv_class,
+      mrb_obj_value(mrb_obj_class(mrb, a))
+    );
+    /* not reached */
+    return mrb_undef_value();
   }
 }
@@ -916,4 +986,5 @@
   struct RArray *a = mrb_ary_ptr(self);
 
+  ary_modify(mrb, a);
   if (ARY_SHARED_P(a)) {
     mrb_ary_decref(mrb, a->aux.shared);
@@ -988,13 +1059,15 @@
 
     default:
-      tmp = mrb_check_string_type(mrb, val);
-      if (!mrb_nil_p(tmp)) {
-        val = tmp;
-        goto str_join;
-      }
-      tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
-      if (!mrb_nil_p(tmp)) {
-        val = tmp;
-        goto ary_join;
+      if (!mrb_immediate_p(val)) {
+        tmp = mrb_check_string_type(mrb, val);
+        if (!mrb_nil_p(tmp)) {
+          val = tmp;
+          goto str_join;
+        }
+        tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
+        if (!mrb_nil_p(tmp)) {
+          val = tmp;
+          goto ary_join;
+        }
       }
       val = mrb_obj_as_string(mrb, val);
@@ -1011,5 +1084,7 @@
 mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
 {
-  sep = mrb_obj_as_string(mrb, sep);
+  if (!mrb_nil_p(sep)) {
+    sep = mrb_obj_as_string(mrb, sep);
+  }
   return join_ary(mrb, ary, sep, mrb_ary_new(mrb));
 }
@@ -1091,4 +1166,5 @@
   mrb_define_method(mrb, a, "pop",             mrb_ary_pop,          MRB_ARGS_NONE()); /* 15.2.12.5.21 */
   mrb_define_method(mrb, a, "push",            mrb_ary_push_m,       MRB_ARGS_ANY());  /* 15.2.12.5.22 */
+  mrb_define_method(mrb, a, "append",          mrb_ary_push_m,       MRB_ARGS_ANY());
   mrb_define_method(mrb, a, "replace",         mrb_ary_replace_m,    MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
   mrb_define_method(mrb, a, "reverse",         mrb_ary_reverse,      MRB_ARGS_NONE()); /* 15.2.12.5.24 */
@@ -1099,4 +1175,5 @@
   mrb_define_method(mrb, a, "slice",           mrb_ary_aget,         MRB_ARGS_ANY());  /* 15.2.12.5.29 */
   mrb_define_method(mrb, a, "unshift",         mrb_ary_unshift_m,    MRB_ARGS_ANY());  /* 15.2.12.5.30 */
+  mrb_define_method(mrb, a, "prepend",         mrb_ary_unshift_m,    MRB_ARGS_ANY());
 
   mrb_define_method(mrb, a, "__ary_eq",        mrb_ary_eq,           MRB_ARGS_REQ(1));
