Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
array.c
Go to the documentation of this file.
1 /*
2 ** array.c - Array class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6 
7 #ifndef SIZE_MAX
8  /* Some versions of VC++
9  * has SIZE_MAX in stdint.h
10  */
11 # include <limits.h>
12 #endif
13 #include "mruby.h"
14 #include "mruby/array.h"
15 #include "mruby/class.h"
16 #include "mruby/string.h"
17 #include "value_array.h"
18 
19 #define ARY_DEFAULT_LEN 4
20 #define ARY_SHRINK_RATIO 5 /* must be larger than 2 */
21 #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value))
22 #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1)
23 
24 static inline mrb_value
25 ary_elt(mrb_value ary, mrb_int offset)
26 {
27  if (RARRAY_LEN(ary) == 0) return mrb_nil_value();
28  if (offset < 0 || RARRAY_LEN(ary) <= offset) {
29  return mrb_nil_value();
30  }
31  return RARRAY_PTR(ary)[offset];
32 }
33 
34 static struct RArray*
35 ary_new_capa(mrb_state *mrb, mrb_int capa)
36 {
37  struct RArray *a;
38  mrb_int blen;
39 
40  if (capa > ARY_MAX_SIZE) {
41  mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
42  }
43  blen = capa * sizeof(mrb_value);
44  if (blen < capa) {
45  mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
46  }
47 
48  a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
49  a->ptr = (mrb_value *)mrb_malloc(mrb, blen);
50  a->aux.capa = capa;
51  a->len = 0;
52 
53  return a;
54 }
55 
58 {
59  struct RArray *a = ary_new_capa(mrb, capa);
60  return mrb_obj_value(a);
61 }
62 
65 {
66  return mrb_ary_new_capa(mrb, 0);
67 }
68 
69 /*
70  * to copy array, use this instead of memcpy because of portability
71  * * gcc on ARM may fail optimization of memcpy
72  * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html
73  * * gcc on MIPS also fail
74  * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755
75  * * memcpy doesn't exist on freestanding environment
76  *
77  * If you optimize for binary size, use memcpy instead of this at your own risk
78  * of above portability issue.
79  *
80  * see also http://togetter.com/li/462898
81  *
82  */
83 static inline void
84 array_copy(mrb_value *dst, const mrb_value *src, size_t size)
85 {
86  size_t i;
87 
88  for (i = 0; i < size; i++) {
89  dst[i] = src[i];
90  }
91 }
92 
95 {
96  mrb_value arv[2];
97  arv[0] = car;
98  arv[1] = cdr;
99  return mrb_ary_new_from_values(mrb, 2, arv);
100 }
101 
102 static void
103 ary_fill_with_nil(mrb_value *ptr, mrb_int size)
104 {
105  mrb_value nil = mrb_nil_value();
106 
107  while ((int)(size--)) {
108  *ptr++ = nil;
109  }
110 }
111 
112 static void
113 ary_modify(mrb_state *mrb, struct RArray *a)
114 {
115  if (a->flags & MRB_ARY_SHARED) {
117 
118  if (shared->refcnt == 1 && a->ptr == shared->ptr) {
119  a->ptr = shared->ptr;
120  a->aux.capa = a->len;
121  mrb_free(mrb, shared);
122  }
123  else {
124  mrb_value *ptr, *p;
125  mrb_int len;
126 
127  p = a->ptr;
128  len = a->len * sizeof(mrb_value);
129  ptr = (mrb_value *)mrb_malloc(mrb, len);
130  if (p) {
131  array_copy(ptr, p, a->len);
132  }
133  a->ptr = ptr;
134  a->aux.capa = a->len;
135  mrb_ary_decref(mrb, shared);
136  }
137  a->flags &= ~MRB_ARY_SHARED;
138  }
139 }
140 
141 static void
142 ary_make_shared(mrb_state *mrb, struct RArray *a)
143 {
144  if (!(a->flags & MRB_ARY_SHARED)) {
146 
147  shared->refcnt = 1;
148  if (a->aux.capa > a->len) {
149  a->ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*a->len+1);
150  }
151  else {
152  shared->ptr = a->ptr;
153  }
154  shared->len = a->len;
155  a->aux.shared = shared;
156  a->flags |= MRB_ARY_SHARED;
157  }
158 }
159 
160 static void
161 ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
162 {
163  mrb_int capa = a->aux.capa;
164 
165  if (len > ARY_MAX_SIZE) {
166  mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big");
167  }
168 
169  while (capa < len) {
170  if (capa == 0) {
171  capa = ARY_DEFAULT_LEN;
172  }
173  else {
174  capa *= 2;
175  }
176  }
177 
178  if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */
179 
180  if (capa > a->aux.capa) {
181  mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
182 
183  if (!expanded_ptr) {
184  mrb_raise(mrb, E_RUNTIME_ERROR, "out of memory");
185  }
186 
187  a->aux.capa = capa;
188  a->ptr = expanded_ptr;
189  }
190 }
191 
192 static void
193 ary_shrink_capa(mrb_state *mrb, struct RArray *a)
194 {
195  mrb_int capa = a->aux.capa;
196 
197  if (capa < ARY_DEFAULT_LEN * 2) return;
198  if (capa <= a->len * ARY_SHRINK_RATIO) return;
199 
200  do {
201  capa /= 2;
202  if (capa < ARY_DEFAULT_LEN) {
203  capa = ARY_DEFAULT_LEN;
204  break;
205  }
206  } while (capa > a->len * ARY_SHRINK_RATIO);
207 
208  if (capa > a->len && capa < a->aux.capa) {
209  a->aux.capa = capa;
210  a->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa);
211  }
212 }
213 
214 mrb_value
216 {
217  mrb_value *vals;
218  int len;
219 
220  mrb_get_args(mrb, "*", &vals, &len);
221  return mrb_ary_new_from_values(mrb, len, vals);
222 }
223 
224 static void
225 ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen)
226 {
227  mrb_int len = a->len + blen;
228 
229  ary_modify(mrb, a);
230  if (a->aux.capa < len) ary_expand_capa(mrb, a, len);
231  array_copy(a->ptr+a->len, ptr, blen);
232  mrb_write_barrier(mrb, (struct RBasic*)a);
233  a->len = len;
234 }
235 
236 void
238 {
239  struct RArray *a2 = mrb_ary_ptr(other);
240 
241  ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
242 }
243 
244 mrb_value
246 {
247  mrb_value *ptr;
248  mrb_int blen;
249 
250  mrb_get_args(mrb, "a", &ptr, &blen);
251  ary_concat(mrb, mrb_ary_ptr(self), ptr, blen);
252  return self;
253 }
254 
255 mrb_value
257 {
258  struct RArray *a1 = mrb_ary_ptr(self);
259  struct RArray *a2;
260  mrb_value ary;
261  mrb_value *ptr;
262  mrb_int blen;
263 
264  mrb_get_args(mrb, "a", &ptr, &blen);
265  ary = mrb_ary_new_capa(mrb, a1->len + blen);
266  a2 = mrb_ary_ptr(ary);
267  array_copy(a2->ptr, a1->ptr, a1->len);
268  array_copy(a2->ptr + a1->len, ptr, blen);
269  a2->len = a1->len + blen;
270 
271  return ary;
272 }
273 
274 /*
275  * call-seq:
276  * ary <=> other_ary -> -1, 0, +1 or nil
277  *
278  * Comparison---Returns an integer (-1, 0, or +1)
279  * if this array is less than, equal to, or greater than <i>other_ary</i>.
280  * Each object in each array is compared (using <=>). If any value isn't
281  * equal, then that inequality is the return value. If all the
282  * values found are equal, then the return is based on a
283  * comparison of the array lengths. Thus, two arrays are
284  * ``equal'' according to <code>Array#<=></code> if and only if they have
285  * the same length and the value of each element is equal to the
286  * value of the corresponding element in the other array.
287  *
288  * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1
289  * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1
290  *
291  */
292 mrb_value
294 {
295  mrb_value ary2;
296  struct RArray *a1, *a2;
297  mrb_value r;
298  mrb_int i, len;
299 
300  mrb_get_args(mrb, "o", &ary2);
301  if (!mrb_array_p(ary2)) return mrb_nil_value();
302  a1 = RARRAY(ary1); a2 = RARRAY(ary2);
303  if (a1->len == a2->len && a1->ptr == a2->ptr) return mrb_fixnum_value(0);
304  else {
305  mrb_sym cmp = mrb_intern2(mrb, "<=>", 3);
306 
307  len = RARRAY_LEN(ary1);
308  if (len > RARRAY_LEN(ary2)) {
309  len = RARRAY_LEN(ary2);
310  }
311  for (i=0; i<len; i++) {
312  mrb_value v = ary_elt(ary2, i);
313  r = mrb_funcall_argv(mrb, ary_elt(ary1, i), cmp, 1, &v);
314  if (mrb_type(r) != MRB_TT_FIXNUM || mrb_fixnum(r) != 0) return r;
315  }
316  }
317  len = a1->len - a2->len;
318  return mrb_fixnum_value((len == 0)? 0: (len > 0)? 1: -1);
319 }
320 
321 static void
322 ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len)
323 {
324  ary_modify(mrb, a);
325  if (a->aux.capa < len)
326  ary_expand_capa(mrb, a, len);
327  array_copy(a->ptr, argv, len);
328  mrb_write_barrier(mrb, (struct RBasic*)a);
329  a->len = len;
330 }
331 
332 void
334 {
335  struct RArray *a2 = mrb_ary_ptr(other);
336 
337  ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len);
338 }
339 
340 mrb_value
342 {
343  mrb_value other;
344 
345  mrb_get_args(mrb, "A", &other);
346  mrb_ary_replace(mrb, self, other);
347 
348  return self;
349 }
350 
351 mrb_value
353 {
354  struct RArray *a1 = mrb_ary_ptr(self);
355  struct RArray *a2;
356  mrb_value ary;
357  mrb_value *ptr;
358  mrb_int times;
359 
360  mrb_get_args(mrb, "i", &times);
361  if (times < 0) {
362  mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument");
363  }
364  if (times == 0) return mrb_ary_new(mrb);
365 
366  ary = mrb_ary_new_capa(mrb, a1->len * times);
367  a2 = mrb_ary_ptr(ary);
368  ptr = a2->ptr;
369  while (times--) {
370  array_copy(ptr, a1->ptr, a1->len);
371  ptr += a1->len;
372  a2->len += a1->len;
373  }
374 
375  return ary;
376 }
377 
378 mrb_value
380 {
381  struct RArray *a = mrb_ary_ptr(self);
382 
383  if (a->len > 1) {
384  mrb_value *p1, *p2;
385 
386  ary_modify(mrb, a);
387  p1 = a->ptr;
388  p2 = a->ptr + a->len - 1;
389 
390  while (p1 < p2) {
391  mrb_value tmp = *p1;
392  *p1++ = *p2;
393  *p2-- = tmp;
394  }
395  }
396  return self;
397 }
398 
399 mrb_value
401 {
402  struct RArray *a = mrb_ary_ptr(self), *b;
403  mrb_value ary;
404 
405  ary = mrb_ary_new_capa(mrb, a->len);
406  b = mrb_ary_ptr(ary);
407  if (a->len > 0) {
408  mrb_value *p1, *p2, *e;
409 
410  p1 = a->ptr;
411  e = p1 + a->len;
412  p2 = b->ptr + a->len - 1;
413  while (p1 < e) {
414  *p2-- = *p1++;
415  }
416  b->len = a->len;
417  }
418  return ary;
419 }
420 
421 mrb_value
423 {
424  mrb_value ary;
425  struct RArray *a;
426 
427  ary = mrb_ary_new_capa(mrb, size);
428  a = mrb_ary_ptr(ary);
429  array_copy(a->ptr, vals, size);
430  a->len = size;
431 
432  return ary;
433 }
434 
435 void
436 mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) /* mrb_ary_push */
437 {
438  struct RArray *a = mrb_ary_ptr(ary);
439 
440  ary_modify(mrb, a);
441  if (a->len == a->aux.capa)
442  ary_expand_capa(mrb, a, a->len + 1);
443  a->ptr[a->len++] = elem;
444  mrb_write_barrier(mrb, (struct RBasic*)a);
445 }
446 
447 mrb_value
449 {
450  mrb_value *argv;
451  int len;
452 
453  mrb_get_args(mrb, "*", &argv, &len);
454  while (len--) {
455  mrb_ary_push(mrb, self, *argv++);
456  }
457 
458  return self;
459 }
460 
461 mrb_value
463 {
464  struct RArray *a = mrb_ary_ptr(ary);
465 
466  if (a->len == 0) return mrb_nil_value();
467  return a->ptr[--a->len];
468 }
469 
470 #define ARY_SHIFT_SHARED_MIN 10
471 
472 mrb_value
474 {
475  struct RArray *a = mrb_ary_ptr(self);
476  mrb_value val;
477 
478  if (a->len == 0) return mrb_nil_value();
479  if (a->flags & MRB_ARY_SHARED) {
480  L_SHIFT:
481  val = a->ptr[0];
482  a->ptr++;
483  a->len--;
484  return val;
485  }
486  if (a->len > ARY_SHIFT_SHARED_MIN) {
487  ary_make_shared(mrb, a);
488  goto L_SHIFT;
489  }
490  else {
491  mrb_value *ptr = a->ptr;
492  mrb_int size = a->len;
493 
494  val = *ptr;
495  while ((int)(--size)) {
496  *ptr = *(ptr+1);
497  ++ptr;
498  }
499  --a->len;
500  }
501  return val;
502 }
503 
504 /* self = [1,2,3]
505  item = 0
506  self.unshift item
507  p self #=> [0, 1, 2, 3] */
508 mrb_value
510 {
511  struct RArray *a = mrb_ary_ptr(self);
512 
513  if ((a->flags & MRB_ARY_SHARED)
514  && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
515  && a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ {
516  a->ptr--;
517  a->ptr[0] = item;
518  }
519  else {
520  ary_modify(mrb, a);
521  if (a->aux.capa < a->len + 1)
522  ary_expand_capa(mrb, a, a->len + 1);
523  value_move(a->ptr + 1, a->ptr, a->len);
524  a->ptr[0] = item;
525  }
526  a->len++;
527  mrb_write_barrier(mrb, (struct RBasic*)a);
528 
529  return self;
530 }
531 
532 mrb_value
534 {
535  struct RArray *a = mrb_ary_ptr(self);
536  mrb_value *vals;
537  int len;
538 
539  mrb_get_args(mrb, "*", &vals, &len);
540  if ((a->flags & MRB_ARY_SHARED)
541  && a->aux.shared->refcnt == 1 /* shared only referenced from this array */
542  && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ {
543  a->ptr -= len;
544  }
545  else {
546  ary_modify(mrb, a);
547  if (len == 0) return self;
548  if (a->aux.capa < a->len + len)
549  ary_expand_capa(mrb, a, a->len + len);
550  value_move(a->ptr + len, a->ptr, a->len);
551  }
552  array_copy(a->ptr, vals, len);
553  a->len += len;
554  mrb_write_barrier(mrb, (struct RBasic*)a);
555 
556  return self;
557 }
558 
559 mrb_value
561 {
562  struct RArray *a = mrb_ary_ptr(ary);
563 
564  /* range check */
565  if (n < 0) n += a->len;
566  if (n < 0 || a->len <= (int)n) return mrb_nil_value();
567 
568  return a->ptr[n];
569 }
570 
571 void
572 mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) /* rb_ary_store */
573 {
574  struct RArray *a = mrb_ary_ptr(ary);
575 
576  ary_modify(mrb, a);
577  /* range check */
578  if (n < 0) {
579  n += a->len;
580  if (n < 0) {
581  mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - a->len));
582  }
583  }
584  if (a->len <= (int)n) {
585  if (a->aux.capa <= (int)n)
586  ary_expand_capa(mrb, a, n + 1);
587  ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len);
588  a->len = n + 1;
589  }
590 
591  a->ptr[n] = val;
592  mrb_write_barrier(mrb, (struct RBasic*)a);
593 }
594 
595 mrb_value
597 {
598  struct RArray *a = mrb_ary_ptr(ary);
599  mrb_int tail, size;
600  mrb_value *argv;
601  mrb_int i, argc;
602 
603  ary_modify(mrb, a);
604  /* range check */
605  if (head < 0) {
606  head += a->len;
607  if (head < 0) {
608  mrb_raise(mrb, E_INDEX_ERROR, "index is out of array");
609  }
610  }
611  if (a->len < len || a->len < head + len) {
612  len = a->len - head;
613  }
614  tail = head + len;
615 
616  /* size check */
617  if (mrb_array_p(rpl)) {
618  argc = RARRAY_LEN(rpl);
619  argv = RARRAY_PTR(rpl);
620  }
621  else {
622  argc = 1;
623  argv = &rpl;
624  }
625  size = head + argc;
626 
627  if (tail < a->len) size += a->len - tail;
628  if (size > a->aux.capa)
629  ary_expand_capa(mrb, a, size);
630 
631  if (head > a->len) {
632  ary_fill_with_nil(a->ptr + a->len, (int)(head - a->len));
633  }
634  else if (head < a->len) {
635  value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail);
636  }
637 
638  for(i = 0; i < argc; i++) {
639  *(a->ptr + head + i) = *(argv + i);
640  }
641 
642  a->len = size;
643 
644  return ary;
645 }
646 
647 mrb_int
649 {
650  return RARRAY_LEN(ary);
651 }
652 
653 void
655 {
656  shared->refcnt--;
657  if (shared->refcnt == 0) {
658  mrb_free(mrb, shared->ptr);
659  mrb_free(mrb, shared);
660  }
661 }
662 
663 static mrb_value
664 ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
665 {
666  struct RArray *b;
667 
668  ary_make_shared(mrb, a);
669  b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class);
670  b->ptr = a->ptr + beg;
671  b->len = len;
672  b->aux.shared = a->aux.shared;
673  b->aux.shared->refcnt++;
674  b->flags |= MRB_ARY_SHARED;
675 
676  return mrb_obj_value(b);
677 }
678 
679 mrb_value
681 {
682  struct RArray *a = mrb_ary_ptr(self);
683  mrb_int index, len;
684  mrb_value *argv;
685  int size;
686 
687  mrb_get_args(mrb, "i*", &index, &argv, &size);
688  switch(size) {
689  case 0:
690  return mrb_ary_ref(mrb, self, index);
691 
692  case 1:
693  if (mrb_type(argv[0]) != MRB_TT_FIXNUM) {
694  mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum");
695  }
696  if (index < 0) index += a->len;
697  if (index < 0 || a->len < (int)index) return mrb_nil_value();
698  len = mrb_fixnum(argv[0]);
699  if (len < 0) return mrb_nil_value();
700  if (a->len == (int)index) return mrb_ary_new(mrb);
701  if (len > a->len - index) len = a->len - index;
702  return ary_subseq(mrb, a, index, len);
703 
704  default:
705  mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
706  break;
707  }
708 
709  return mrb_nil_value(); /* dummy to avoid warning : not reach here */
710 }
711 
712 mrb_value
714 {
715  mrb_value *argv;
716  int argc;
717 
718  mrb_get_args(mrb, "*", &argv, &argc);
719  switch(argc) {
720  case 2:
721  if (!mrb_fixnum_p(argv[0])) {
722  /* Should we support Range object for 1st arg ? */
723  mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum for 1st argument");
724  }
725  mrb_ary_set(mrb, self, mrb_fixnum(argv[0]), argv[1]);
726  return argv[1];
727 
728  case 3:
729  mrb_ary_splice(mrb, self, mrb_fixnum(argv[0]), mrb_fixnum(argv[1]), argv[2]);
730  return argv[2];
731 
732  default:
733  mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
734  return mrb_nil_value();
735  }
736 }
737 
738 mrb_value
740 {
741  struct RArray *a = mrb_ary_ptr(self);
742  mrb_int index;
743  mrb_value val;
744  mrb_value *ptr;
745  mrb_int len;
746 
747  mrb_get_args(mrb, "i", &index);
748  if (index < 0) index += a->len;
749  if (index < 0 || a->len <= (int)index) return mrb_nil_value();
750 
751  ary_modify(mrb, a);
752  val = a->ptr[index];
753 
754  ptr = a->ptr + index;
755  len = a->len - index;
756  while ((int)(--len)) {
757  *ptr = *(ptr+1);
758  ++ptr;
759  }
760  --a->len;
761 
762  ary_shrink_capa(mrb, a);
763 
764  return val;
765 }
766 
767 mrb_value
769 {
770  struct RArray *a = mrb_ary_ptr(self);
771  mrb_int size;
772 
773  if (mrb_get_args(mrb, "|i", &size) == 0) {
774  return (a->len > 0)? a->ptr[0]: mrb_nil_value();
775  }
776  if (size < 0) {
777  mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
778  }
779 
780  if (size > a->len) size = a->len;
781  if (a->flags & MRB_ARY_SHARED) {
782  return ary_subseq(mrb, a, 0, size);
783  }
784  return mrb_ary_new_from_values(mrb, size, a->ptr);
785 }
786 
787 mrb_value
789 {
790  struct RArray *a = mrb_ary_ptr(self);
791  mrb_int size;
792  mrb_value *vals;
793  int len;
794 
795  mrb_get_args(mrb, "*", &vals, &len);
796  if (len > 1) {
797  mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
798  }
799 
800  if (len == 0) return (a->len > 0)? a->ptr[a->len - 1]: mrb_nil_value();
801 
802  /* len == 1 */
803  size = mrb_fixnum(*vals);
804  if (size < 0) {
805  mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size");
806  }
807  if (size > a->len) size = a->len;
808  if ((a->flags & MRB_ARY_SHARED) || size > ARY_DEFAULT_LEN) {
809  return ary_subseq(mrb, a, a->len - size, size);
810  }
811  return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size);
812 }
813 
814 mrb_value
816 {
817  mrb_value obj;
818  mrb_int i;
819 
820  mrb_get_args(mrb, "o", &obj);
821  for (i = 0; i < RARRAY_LEN(self); i++) {
822  if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
823  return mrb_fixnum_value(i);
824  }
825  }
826  return mrb_nil_value();
827 }
828 
829 mrb_value
831 {
832  mrb_value obj;
833  mrb_int i;
834 
835  mrb_get_args(mrb, "o", &obj);
836  for (i = RARRAY_LEN(self) - 1; i >= 0; i--) {
837  if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) {
838  return mrb_fixnum_value(i);
839  }
840  }
841  return mrb_nil_value();
842 }
843 
844 mrb_value
846 {
847  if (mrb_array_p(v)) {
848  return v;
849  }
850  else {
851  return mrb_ary_new_from_values(mrb, 1, &v);
852  }
853 }
854 
855 static mrb_value
856 mrb_ary_size(mrb_state *mrb, mrb_value self)
857 {
858  struct RArray *a = mrb_ary_ptr(self);
859 
860  return mrb_fixnum_value(a->len);
861 }
862 
863 mrb_value
865 {
866  struct RArray *a = mrb_ary_ptr(self);
867 
868  ary_modify(mrb, a);
869  a->len = 0;
870  a->aux.capa = 0;
871  mrb_free(mrb, a->ptr);
872  a->ptr = 0;
873 
874  return self;
875 }
876 
877 mrb_value
879 {
880  struct RArray *a = mrb_ary_ptr(self);
881 
882  return mrb_bool_value(a->len == 0);
883 }
884 
885 mrb_value
887 {
888  return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary");
889 }
890 
891 mrb_value
893 {
894  if (offset < 0) {
895  offset += RARRAY_LEN(ary);
896  }
897  return ary_elt(ary, offset);
898 }
899 
900 static mrb_value
901 inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
902 {
903  mrb_int i;
904  mrb_value s, arystr;
905  char head[] = { '[' };
906  char sep[] = { ',', ' ' };
907  char tail[] = { ']' };
908 
909  /* check recursive */
910  for(i=0; i<RARRAY_LEN(list); i++) {
911  if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
912  return mrb_str_new(mrb, "[...]", 5);
913  }
914  }
915 
916  mrb_ary_push(mrb, list, ary);
917 
918  arystr = mrb_str_buf_new(mrb, 64);
919  mrb_str_buf_cat(mrb, arystr, head, sizeof(head));
920 
921  for(i=0; i<RARRAY_LEN(ary); i++) {
922  int ai = mrb_gc_arena_save(mrb);
923 
924  if (i > 0) {
925  mrb_str_buf_cat(mrb, arystr, sep, sizeof(sep));
926  }
927  if (mrb_array_p(RARRAY_PTR(ary)[i])) {
928  s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list);
929  }
930  else {
931  s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]);
932  }
933  mrb_str_buf_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
934  mrb_gc_arena_restore(mrb, ai);
935  }
936 
937  mrb_str_buf_cat(mrb, arystr, tail, sizeof(tail));
938  mrb_ary_pop(mrb, list);
939 
940  return arystr;
941 }
942 
943 /* 15.2.12.5.31 (x) */
944 /*
945  * call-seq:
946  * ary.to_s -> string
947  * ary.inspect -> string
948  *
949  * Creates a string representation of +self+.
950  */
951 
952 static mrb_value
953 mrb_ary_inspect(mrb_state *mrb, mrb_value ary)
954 {
955  if (RARRAY_LEN(ary) == 0) return mrb_str_new(mrb, "[]", 2);
956  return inspect_ary(mrb, ary, mrb_ary_new(mrb));
957 }
958 
959 static mrb_value
960 join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
961 {
962  mrb_int i;
963  mrb_value result, val, tmp;
964 
965  /* check recursive */
966  for(i=0; i<RARRAY_LEN(list); i++) {
967  if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
968  mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join");
969  }
970  }
971 
972  mrb_ary_push(mrb, list, ary);
973 
974  result = mrb_str_buf_new(mrb, 64);
975 
976  for(i=0; i<RARRAY_LEN(ary); i++) {
977  if (i > 0 && !mrb_nil_p(sep)) {
978  mrb_str_buf_cat(mrb, result, RSTRING_PTR(sep), RSTRING_LEN(sep));
979  }
980 
981  val = RARRAY_PTR(ary)[i];
982  switch(mrb_type(val)) {
983  case MRB_TT_ARRAY:
984  ary_join:
985  val = join_ary(mrb, val, sep, list);
986  /* fall through */
987 
988  case MRB_TT_STRING:
989  str_join:
990  mrb_str_buf_cat(mrb, result, RSTRING_PTR(val), RSTRING_LEN(val));
991  break;
992 
993  default:
994  tmp = mrb_check_string_type(mrb, val);
995  if (!mrb_nil_p(tmp)) {
996  val = tmp;
997  goto str_join;
998  }
999  tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
1000  if (!mrb_nil_p(tmp)) {
1001  val = tmp;
1002  goto ary_join;
1003  }
1004  val = mrb_obj_as_string(mrb, val);
1005  goto str_join;
1006  }
1007  }
1008 
1009  mrb_ary_pop(mrb, list);
1010 
1011  return result;
1012 }
1013 
1014 mrb_value
1016 {
1017  sep = mrb_obj_as_string(mrb, sep);
1018  return join_ary(mrb, ary, sep, mrb_ary_new(mrb));
1019 }
1020 
1021 /*
1022  * call-seq:
1023  * ary.join(sep="") -> str
1024  *
1025  * Returns a string created by converting each element of the array to
1026  * a string, separated by <i>sep</i>.
1027  *
1028  * [ "a", "b", "c" ].join #=> "abc"
1029  * [ "a", "b", "c" ].join("-") #=> "a-b-c"
1030  */
1031 
1032 static mrb_value
1033 mrb_ary_join_m(mrb_state *mrb, mrb_value ary)
1034 {
1035  mrb_value sep = mrb_nil_value();
1036 
1037  mrb_get_args(mrb, "|S", &sep);
1038  return mrb_ary_join(mrb, ary, sep);
1039 }
1040 
1041 /* 15.2.12.5.33 (x) */
1042 /*
1043  * call-seq:
1044  * ary == other_ary -> bool
1045  *
1046  * Equality---Two arrays are equal if they contain the same number
1047  * of elements and if each element is equal to (according to
1048  * Object.==) the corresponding element in the other array.
1049  *
1050  * [ "a", "c" ] == [ "a", "c", 7 ] #=> false
1051  * [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true
1052  * [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false
1053  *
1054  */
1055 
1056 static mrb_value
1057 mrb_ary_equal(mrb_state *mrb, mrb_value ary1)
1058 {
1059  mrb_value ary2;
1060  mrb_int i;
1061 
1062  mrb_get_args(mrb, "o", &ary2);
1063  if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
1064  if (mrb_special_const_p(ary2)) return mrb_false_value();
1065  if (!mrb_array_p(ary2)) {
1066  if (!mrb_respond_to(mrb, ary2, mrb_intern2(mrb, "to_ary", 6))) {
1067  return mrb_false_value();
1068  }
1069  else {
1070  return mrb_bool_value(mrb_equal(mrb, ary2, ary1));
1071  }
1072  }
1073  if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value();
1074  for (i=0; i<RARRAY_LEN(ary1); i++) {
1075  if (!mrb_equal(mrb, ary_elt(ary1, i), ary_elt(ary2, i))) {
1076  return mrb_false_value();
1077  }
1078  }
1079  return mrb_true_value();
1080 }
1081 
1082 /* 15.2.12.5.34 (x) */
1083 /*
1084  * call-seq:
1085  * ary.eql?(other) -> true or false
1086  *
1087  * Returns <code>true</code> if +self+ and _other_ are the same object,
1088  * or are both arrays with the same content.
1089  */
1090 
1091 static mrb_value
1092 mrb_ary_eql(mrb_state *mrb, mrb_value ary1)
1093 {
1094  mrb_value ary2;
1095  mrb_int i;
1096 
1097  mrb_get_args(mrb, "o", &ary2);
1098  if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value();
1099  if (!mrb_array_p(ary2)) return mrb_false_value();
1100  if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value();
1101  for (i=0; i<RARRAY_LEN(ary1); i++) {
1102  if (!mrb_eql(mrb, ary_elt(ary1, i), ary_elt(ary2, i))) {
1103  return mrb_false_value();
1104  }
1105  }
1106  return mrb_true_value();
1107 }
1108 
1109 void
1111 {
1112  struct RClass *a;
1113 
1114  a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class);
1116  mrb_include_module(mrb, a, mrb_class_get(mrb, "Enumerable"));
1117 
1118  mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */
1119 
1120  mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */
1121  mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */
1122  mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */
1123  mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */
1124  mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */
1125  mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */
1126  mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */
1127  mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */
1128  mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */
1129  mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */
1130  mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */
1131  mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */
1132  mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */
1133  mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */
1134  mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */
1135  mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */
1136  mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */
1137  mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */
1138  mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */
1139  mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */
1140  mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */
1141  mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */
1142  mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */
1143  mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */
1144  mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */
1145 
1146  mrb_define_method(mrb, a, "inspect", mrb_ary_inspect, MRB_ARGS_NONE()); /* 15.2.12.5.31 (x) */
1147  mrb_define_alias(mrb, a, "to_s", "inspect"); /* 15.2.12.5.32 (x) */
1148  mrb_define_method(mrb, a, "==", mrb_ary_equal, MRB_ARGS_REQ(1)); /* 15.2.12.5.33 (x) */
1149  mrb_define_method(mrb, a, "eql?", mrb_ary_eql, MRB_ARGS_REQ(1)); /* 15.2.12.5.34 (x) */
1150  mrb_define_method(mrb, a, "<=>", mrb_ary_cmp, MRB_ARGS_REQ(1)); /* 15.2.12.5.36 (x) */
1151 }