source: EcnlProtoTool/trunk/mruby-1.3.0/src/array.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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