[DOC] Tweaks for Array#delete_at
[ruby.git] / array.c
blobdd49c3b4f8a954b57bebb84223e61d9dffff7fd3
1 /**********************************************************************
3 array.c -
5 $Author$
6 created at: Fri Aug 6 09:46:12 JST 1993
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 **********************************************************************/
14 #include "debug_counter.h"
15 #include "id.h"
16 #include "internal.h"
17 #include "internal/array.h"
18 #include "internal/compar.h"
19 #include "internal/enum.h"
20 #include "internal/gc.h"
21 #include "internal/hash.h"
22 #include "internal/numeric.h"
23 #include "internal/object.h"
24 #include "internal/proc.h"
25 #include "internal/rational.h"
26 #include "internal/vm.h"
27 #include "probes.h"
28 #include "ruby/encoding.h"
29 #include "ruby/st.h"
30 #include "ruby/util.h"
31 #include "vm_core.h"
32 #include "builtin.h"
34 #if !ARRAY_DEBUG
35 # undef NDEBUG
36 # define NDEBUG
37 #endif
38 #include "ruby_assert.h"
40 VALUE rb_cArray;
41 VALUE rb_cArray_empty_frozen;
43 /* Flags of RArray
45 * 1: RARRAY_EMBED_FLAG
46 * The array is embedded (its contents follow the header, rather than
47 * being on a separately allocated buffer).
48 * 2: RARRAY_SHARED_FLAG (equal to ELTS_SHARED)
49 * The array is shared. The buffer this array points to is owned by
50 * another array (the shared root).
51 * 3-9: RARRAY_EMBED_LEN
52 * The length of the array when RARRAY_EMBED_FLAG is set.
53 * 12: RARRAY_SHARED_ROOT_FLAG
54 * The array is a shared root that does reference counting. The buffer
55 * this array points to is owned by this array but may be pointed to
56 * by other arrays.
57 * Note: Frozen arrays may be a shared root without this flag being
58 * set. Frozen arrays do not have reference counting because
59 * they cannot be modified. Not updating the reference count
60 * improves copy-on-write performance. Their reference count is
61 * assumed to be infinity.
62 * 14: RARRAY_PTR_IN_USE_FLAG
63 * The buffer of the array is in use. This is only used during
64 * debugging.
67 /* for OPTIMIZED_CMP: */
68 #define id_cmp idCmp
70 #define ARY_DEFAULT_SIZE 16
71 #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE))
72 #define SMALL_ARRAY_LEN 16
74 RBIMPL_ATTR_MAYBE_UNUSED()
75 static int
76 should_be_T_ARRAY(VALUE ary)
78 return RB_TYPE_P(ary, T_ARRAY);
81 #define ARY_HEAP_PTR(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
82 #define ARY_HEAP_LEN(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
83 #define ARY_HEAP_CAPA(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RUBY_ASSERT(!ARY_SHARED_ROOT_P(a)), \
84 RARRAY(a)->as.heap.aux.capa)
86 #define ARY_EMBED_PTR(a) (RUBY_ASSERT(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
87 #define ARY_EMBED_LEN(a) \
88 (RUBY_ASSERT(ARY_EMBED_P(a)), \
89 (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
90 (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
91 #define ARY_HEAP_SIZE(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RUBY_ASSERT(ARY_OWNS_HEAP_P(a)), ARY_CAPA(a) * sizeof(VALUE))
93 #define ARY_OWNS_HEAP_P(a) (RUBY_ASSERT(should_be_T_ARRAY((VALUE)(a))), \
94 !FL_TEST_RAW((a), RARRAY_SHARED_FLAG|RARRAY_EMBED_FLAG))
96 #define FL_SET_EMBED(a) do { \
97 RUBY_ASSERT(!ARY_SHARED_P(a)); \
98 FL_SET((a), RARRAY_EMBED_FLAG); \
99 ary_verify(a); \
100 } while (0)
102 #define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
103 #define FL_SET_SHARED(ary) do { \
104 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
105 FL_SET((ary), RARRAY_SHARED_FLAG); \
106 } while (0)
107 #define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG)
109 #define ARY_SET_PTR(ary, p) do { \
110 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
111 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
112 RARRAY(ary)->as.heap.ptr = (p); \
113 } while (0)
114 #define ARY_SET_EMBED_LEN(ary, n) do { \
115 long tmp_n = (n); \
116 RUBY_ASSERT(ARY_EMBED_P(ary)); \
117 RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
118 RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
119 } while (0)
120 #define ARY_SET_HEAP_LEN(ary, n) do { \
121 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
122 RARRAY(ary)->as.heap.len = (n); \
123 } while (0)
124 #define ARY_SET_LEN(ary, n) do { \
125 if (ARY_EMBED_P(ary)) { \
126 ARY_SET_EMBED_LEN((ary), (n)); \
128 else { \
129 ARY_SET_HEAP_LEN((ary), (n)); \
131 RUBY_ASSERT(RARRAY_LEN(ary) == (n)); \
132 } while (0)
133 #define ARY_INCREASE_PTR(ary, n) do { \
134 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
135 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
136 RARRAY(ary)->as.heap.ptr += (n); \
137 } while (0)
138 #define ARY_INCREASE_LEN(ary, n) do { \
139 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
140 if (ARY_EMBED_P(ary)) { \
141 ARY_SET_EMBED_LEN((ary), RARRAY_LEN(ary)+(n)); \
143 else { \
144 RARRAY(ary)->as.heap.len += (n); \
146 } while (0)
148 #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? ary_embed_capa(ary) : \
149 ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary))
150 #define ARY_SET_CAPA(ary, n) do { \
151 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
152 RUBY_ASSERT(!ARY_SHARED_P(ary)); \
153 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
154 RARRAY(ary)->as.heap.aux.capa = (n); \
155 } while (0)
157 #define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
158 #define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \
159 RUBY_ASSERT(ARY_SHARED_ROOT_P(ary)); \
160 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
161 RUBY_ASSERT((value) >= 0); \
162 RARRAY(ary)->as.heap.aux.capa = (value); \
163 } while (0)
164 #define FL_SET_SHARED_ROOT(ary) do { \
165 RUBY_ASSERT(!OBJ_FROZEN(ary)); \
166 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
167 FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
168 } while (0)
170 static inline void
171 ARY_SET(VALUE a, long i, VALUE v)
173 RUBY_ASSERT(!ARY_SHARED_P(a));
174 RUBY_ASSERT(!OBJ_FROZEN(a));
176 RARRAY_ASET(a, i, v);
178 #undef RARRAY_ASET
180 static long
181 ary_embed_capa(VALUE ary)
183 size_t size = rb_gc_obj_slot_size(ary) - offsetof(struct RArray, as.ary);
184 RUBY_ASSERT(size % sizeof(VALUE) == 0);
185 return size / sizeof(VALUE);
188 static size_t
189 ary_embed_size(long capa)
191 return offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa);
194 static bool
195 ary_embeddable_p(long capa)
197 return rb_gc_size_allocatable_p(ary_embed_size(capa));
200 bool
201 rb_ary_embeddable_p(VALUE ary)
203 /* An array cannot be turned embeddable when the array is:
204 * - Shared root: other objects may point to the buffer of this array
205 * so we cannot make it embedded.
206 * - Frozen: this array may also be a shared root without the shared root
207 * flag.
208 * - Shared: we don't want to re-embed an array that points to a shared
209 * root (to save memory).
211 return !(ARY_SHARED_ROOT_P(ary) || OBJ_FROZEN(ary) || ARY_SHARED_P(ary));
214 size_t
215 rb_ary_size_as_embedded(VALUE ary)
217 size_t real_size;
219 if (ARY_EMBED_P(ary)) {
220 real_size = ary_embed_size(ARY_EMBED_LEN(ary));
222 else if (rb_ary_embeddable_p(ary)) {
223 real_size = ary_embed_size(ARY_HEAP_CAPA(ary));
225 else {
226 real_size = sizeof(struct RArray);
228 return real_size;
232 #if ARRAY_DEBUG
233 #define ary_verify(ary) ary_verify_(ary, __FILE__, __LINE__)
235 static VALUE
236 ary_verify_(VALUE ary, const char *file, int line)
238 RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
240 if (ARY_SHARED_P(ary)) {
241 VALUE root = ARY_SHARED_ROOT(ary);
242 const VALUE *ptr = ARY_HEAP_PTR(ary);
243 const VALUE *root_ptr = RARRAY_CONST_PTR(root);
244 long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root);
245 RUBY_ASSERT(ARY_SHARED_ROOT_P(root) || OBJ_FROZEN(root));
246 RUBY_ASSERT(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
247 ary_verify(root);
249 else if (ARY_EMBED_P(ary)) {
250 RUBY_ASSERT(!ARY_SHARED_P(ary));
251 RUBY_ASSERT(RARRAY_LEN(ary) <= ary_embed_capa(ary));
253 else {
254 const VALUE *ptr = RARRAY_CONST_PTR(ary);
255 long i, len = RARRAY_LEN(ary);
256 volatile VALUE v;
257 if (len > 1) len = 1; /* check only HEAD */
258 for (i=0; i<len; i++) {
259 v = ptr[i]; /* access check */
261 v = v;
264 return ary;
267 void
268 rb_ary_verify(VALUE ary)
270 ary_verify(ary);
272 #else
273 #define ary_verify(ary) ((void)0)
274 #endif
276 VALUE *
277 rb_ary_ptr_use_start(VALUE ary)
279 #if ARRAY_DEBUG
280 FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
281 #endif
282 return (VALUE *)RARRAY_CONST_PTR(ary);
285 void
286 rb_ary_ptr_use_end(VALUE ary)
288 #if ARRAY_DEBUG
289 FL_UNSET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
290 #endif
293 void
294 rb_mem_clear(VALUE *mem, long size)
296 while (size--) {
297 *mem++ = Qnil;
301 static void
302 ary_mem_clear(VALUE ary, long beg, long size)
304 RARRAY_PTR_USE(ary, ptr, {
305 rb_mem_clear(ptr + beg, size);
309 static inline void
310 memfill(register VALUE *mem, register long size, register VALUE val)
312 while (size--) {
313 *mem++ = val;
317 static void
318 ary_memfill(VALUE ary, long beg, long size, VALUE val)
320 RARRAY_PTR_USE(ary, ptr, {
321 memfill(ptr + beg, size, val);
322 RB_OBJ_WRITTEN(ary, Qundef, val);
326 static void
327 ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary)
329 RUBY_ASSERT(!ARY_SHARED_P(buff_owner_ary));
331 if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
332 rb_gc_writebarrier_remember(buff_owner_ary);
333 RARRAY_PTR_USE(ary, ptr, {
334 MEMCPY(ptr+beg, argv, VALUE, argc);
337 else {
338 int i;
339 RARRAY_PTR_USE(ary, ptr, {
340 for (i=0; i<argc; i++) {
341 RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]);
347 static void
348 ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
350 ary_memcpy0(ary, beg, argc, argv, ary);
353 static VALUE *
354 ary_heap_alloc_buffer(size_t capa)
356 return ALLOC_N(VALUE, capa);
359 static void
360 ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
362 ruby_sized_xfree((void *)ptr, size);
365 static void
366 ary_heap_free(VALUE ary)
368 ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
371 static size_t
372 ary_heap_realloc(VALUE ary, size_t new_capa)
374 RUBY_ASSERT(!OBJ_FROZEN(ary));
375 SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, ARY_HEAP_CAPA(ary));
376 ary_verify(ary);
378 return new_capa;
381 void
382 rb_ary_make_embedded(VALUE ary)
384 RUBY_ASSERT(rb_ary_embeddable_p(ary));
385 if (!ARY_EMBED_P(ary)) {
386 const VALUE *buf = ARY_HEAP_PTR(ary);
387 long len = ARY_HEAP_LEN(ary);
389 FL_SET_EMBED(ary);
390 ARY_SET_EMBED_LEN(ary, len);
392 MEMCPY((void *)ARY_EMBED_PTR(ary), (void *)buf, VALUE, len);
394 ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
398 static void
399 ary_resize_capa(VALUE ary, long capacity)
401 RUBY_ASSERT(RARRAY_LEN(ary) <= capacity);
402 RUBY_ASSERT(!OBJ_FROZEN(ary));
403 RUBY_ASSERT(!ARY_SHARED_P(ary));
405 if (capacity > ary_embed_capa(ary)) {
406 size_t new_capa = capacity;
407 if (ARY_EMBED_P(ary)) {
408 long len = ARY_EMBED_LEN(ary);
409 VALUE *ptr = ary_heap_alloc_buffer(capacity);
411 MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
412 FL_UNSET_EMBED(ary);
413 ARY_SET_PTR(ary, ptr);
414 ARY_SET_HEAP_LEN(ary, len);
416 else {
417 new_capa = ary_heap_realloc(ary, capacity);
419 ARY_SET_CAPA(ary, new_capa);
421 else {
422 if (!ARY_EMBED_P(ary)) {
423 long len = ARY_HEAP_LEN(ary);
424 long old_capa = ARY_HEAP_CAPA(ary);
425 const VALUE *ptr = ARY_HEAP_PTR(ary);
427 if (len > capacity) len = capacity;
428 MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len);
429 ary_heap_free_ptr(ary, ptr, old_capa);
431 FL_SET_EMBED(ary);
432 ARY_SET_LEN(ary, len);
436 ary_verify(ary);
439 static inline void
440 ary_shrink_capa(VALUE ary)
442 long capacity = ARY_HEAP_LEN(ary);
443 long old_capa = ARY_HEAP_CAPA(ary);
444 RUBY_ASSERT(!ARY_SHARED_P(ary));
445 RUBY_ASSERT(old_capa >= capacity);
446 if (old_capa > capacity) {
447 size_t new_capa = ary_heap_realloc(ary, capacity);
448 ARY_SET_CAPA(ary, new_capa);
451 ary_verify(ary);
454 static void
455 ary_double_capa(VALUE ary, long min)
457 long new_capa = ARY_CAPA(ary) / 2;
459 if (new_capa < ARY_DEFAULT_SIZE) {
460 new_capa = ARY_DEFAULT_SIZE;
462 if (new_capa >= ARY_MAX_SIZE - min) {
463 new_capa = (ARY_MAX_SIZE - min) / 2;
465 new_capa += min;
466 ary_resize_capa(ary, new_capa);
468 ary_verify(ary);
471 static void
472 rb_ary_decrement_share(VALUE shared_root)
474 if (!OBJ_FROZEN(shared_root)) {
475 long num = ARY_SHARED_ROOT_REFCNT(shared_root);
476 ARY_SET_SHARED_ROOT_REFCNT(shared_root, num - 1);
480 static void
481 rb_ary_unshare(VALUE ary)
483 VALUE shared_root = ARY_SHARED_ROOT(ary);
484 rb_ary_decrement_share(shared_root);
485 FL_UNSET_SHARED(ary);
488 static void
489 rb_ary_reset(VALUE ary)
491 if (ARY_OWNS_HEAP_P(ary)) {
492 ary_heap_free(ary);
494 else if (ARY_SHARED_P(ary)) {
495 rb_ary_unshare(ary);
498 FL_SET_EMBED(ary);
499 ARY_SET_EMBED_LEN(ary, 0);
502 static VALUE
503 rb_ary_increment_share(VALUE shared_root)
505 if (!OBJ_FROZEN(shared_root)) {
506 long num = ARY_SHARED_ROOT_REFCNT(shared_root);
507 RUBY_ASSERT(num >= 0);
508 ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1);
510 return shared_root;
513 static void
514 rb_ary_set_shared(VALUE ary, VALUE shared_root)
516 RUBY_ASSERT(!ARY_EMBED_P(ary));
517 RUBY_ASSERT(!OBJ_FROZEN(ary));
518 RUBY_ASSERT(ARY_SHARED_ROOT_P(shared_root) || OBJ_FROZEN(shared_root));
520 rb_ary_increment_share(shared_root);
521 FL_SET_SHARED(ary);
522 RB_OBJ_WRITE(ary, &RARRAY(ary)->as.heap.aux.shared_root, shared_root);
524 RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
527 static inline void
528 rb_ary_modify_check(VALUE ary)
530 rb_check_frozen(ary);
531 ary_verify(ary);
534 void
535 rb_ary_cancel_sharing(VALUE ary)
537 if (ARY_SHARED_P(ary)) {
538 long shared_len, len = RARRAY_LEN(ary);
539 VALUE shared_root = ARY_SHARED_ROOT(ary);
541 ary_verify(shared_root);
543 if (len <= ary_embed_capa(ary)) {
544 const VALUE *ptr = ARY_HEAP_PTR(ary);
545 FL_UNSET_SHARED(ary);
546 FL_SET_EMBED(ary);
547 MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len);
548 rb_ary_decrement_share(shared_root);
549 ARY_SET_EMBED_LEN(ary, len);
551 else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
552 long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared_root);
553 FL_UNSET_SHARED(ary);
554 ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared_root));
555 ARY_SET_CAPA(ary, shared_len);
556 RARRAY_PTR_USE(ary, ptr, {
557 MEMMOVE(ptr, ptr+shift, VALUE, len);
559 FL_SET_EMBED(shared_root);
560 rb_ary_decrement_share(shared_root);
562 else {
563 VALUE *ptr = ary_heap_alloc_buffer(len);
564 MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
565 rb_ary_unshare(ary);
566 ARY_SET_CAPA(ary, len);
567 ARY_SET_PTR(ary, ptr);
570 rb_gc_writebarrier_remember(ary);
572 ary_verify(ary);
575 void
576 rb_ary_modify(VALUE ary)
578 rb_ary_modify_check(ary);
579 rb_ary_cancel_sharing(ary);
582 static VALUE
583 ary_ensure_room_for_push(VALUE ary, long add_len)
585 long old_len = RARRAY_LEN(ary);
586 long new_len = old_len + add_len;
587 long capa;
589 if (old_len > ARY_MAX_SIZE - add_len) {
590 rb_raise(rb_eIndexError, "index %ld too big", new_len);
592 if (ARY_SHARED_P(ary)) {
593 if (new_len > ary_embed_capa(ary)) {
594 VALUE shared_root = ARY_SHARED_ROOT(ary);
595 if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
596 if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
597 rb_ary_modify_check(ary);
599 ary_verify(ary);
600 ary_verify(shared_root);
601 return shared_root;
603 else {
604 /* if array is shared, then it is likely it participate in push/shift pattern */
605 rb_ary_modify(ary);
606 capa = ARY_CAPA(ary);
607 if (new_len > capa - (capa >> 6)) {
608 ary_double_capa(ary, new_len);
610 ary_verify(ary);
611 return ary;
615 ary_verify(ary);
616 rb_ary_modify(ary);
618 else {
619 rb_ary_modify_check(ary);
621 capa = ARY_CAPA(ary);
622 if (new_len > capa) {
623 ary_double_capa(ary, new_len);
626 ary_verify(ary);
627 return ary;
631 * call-seq:
632 * array.freeze -> self
634 * Freezes +self+; returns +self+:
636 * a = []
637 * a.frozen? # => false
638 * a.freeze
639 * a.frozen? # => true
641 * An attempt to modify a frozen +Array+ raises FrozenError.
644 VALUE
645 rb_ary_freeze(VALUE ary)
647 RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
649 if (OBJ_FROZEN(ary)) return ary;
651 if (!ARY_EMBED_P(ary) && !ARY_SHARED_P(ary) && !ARY_SHARED_ROOT_P(ary)) {
652 ary_shrink_capa(ary);
655 return rb_obj_freeze(ary);
658 /* This can be used to take a snapshot of an array (with
659 e.g. rb_ary_replace) and check later whether the array has been
660 modified from the snapshot. The snapshot is cheap, though if
661 something does modify the array it will pay the cost of copying
662 it. If Array#pop or Array#shift has been called, the array will
663 be still shared with the snapshot, but the array length will
664 differ. */
665 VALUE
666 rb_ary_shared_with_p(VALUE ary1, VALUE ary2)
668 if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) &&
669 !ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) &&
670 ARY_SHARED_ROOT(ary1) == ARY_SHARED_ROOT(ary2) &&
671 ARY_HEAP_LEN(ary1) == ARY_HEAP_LEN(ary2)) {
672 return Qtrue;
674 return Qfalse;
677 static VALUE
678 ary_alloc_embed(VALUE klass, long capa)
680 size_t size = ary_embed_size(capa);
681 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
682 NEWOBJ_OF(ary, struct RArray, klass,
683 T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
684 size, 0);
685 /* Created array is:
686 * FL_SET_EMBED((VALUE)ary);
687 * ARY_SET_EMBED_LEN((VALUE)ary, 0);
689 return (VALUE)ary;
692 static VALUE
693 ary_alloc_heap(VALUE klass)
695 NEWOBJ_OF(ary, struct RArray, klass,
696 T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
697 sizeof(struct RArray), 0);
698 return (VALUE)ary;
701 static VALUE
702 empty_ary_alloc(VALUE klass)
704 RUBY_DTRACE_CREATE_HOOK(ARRAY, 0);
705 return ary_alloc_embed(klass, 0);
708 static VALUE
709 ary_new(VALUE klass, long capa)
711 VALUE ary;
713 if (capa < 0) {
714 rb_raise(rb_eArgError, "negative array size (or size too big)");
716 if (capa > ARY_MAX_SIZE) {
717 rb_raise(rb_eArgError, "array size too big");
720 RUBY_DTRACE_CREATE_HOOK(ARRAY, capa);
722 if (ary_embeddable_p(capa)) {
723 ary = ary_alloc_embed(klass, capa);
725 else {
726 ary = ary_alloc_heap(klass);
727 ARY_SET_CAPA(ary, capa);
728 RUBY_ASSERT(!ARY_EMBED_P(ary));
730 ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
731 ARY_SET_HEAP_LEN(ary, 0);
734 return ary;
737 VALUE
738 rb_ary_new_capa(long capa)
740 return ary_new(rb_cArray, capa);
743 VALUE
744 rb_ary_new(void)
746 return rb_ary_new_capa(0);
749 VALUE
750 (rb_ary_new_from_args)(long n, ...)
752 va_list ar;
753 VALUE ary;
754 long i;
756 ary = rb_ary_new2(n);
758 va_start(ar, n);
759 for (i=0; i<n; i++) {
760 ARY_SET(ary, i, va_arg(ar, VALUE));
762 va_end(ar);
764 ARY_SET_LEN(ary, n);
765 return ary;
768 VALUE
769 rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts)
771 VALUE ary;
773 ary = ary_new(klass, n);
774 if (n > 0 && elts) {
775 ary_memcpy(ary, 0, n, elts);
776 ARY_SET_LEN(ary, n);
779 return ary;
782 VALUE
783 rb_ary_new_from_values(long n, const VALUE *elts)
785 return rb_ary_tmp_new_from_values(rb_cArray, n, elts);
788 static VALUE
789 ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
791 size_t size = ary_embed_size(capa);
792 RUBY_ASSERT(rb_gc_size_allocatable_p(size));
793 NEWOBJ_OF(ary, struct RArray, klass,
794 T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
795 size, ec);
796 /* Created array is:
797 * FL_SET_EMBED((VALUE)ary);
798 * ARY_SET_EMBED_LEN((VALUE)ary, 0);
800 return (VALUE)ary;
803 static VALUE
804 ec_ary_alloc_heap(rb_execution_context_t *ec, VALUE klass)
806 NEWOBJ_OF(ary, struct RArray, klass,
807 T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
808 sizeof(struct RArray), ec);
809 return (VALUE)ary;
812 static VALUE
813 ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
815 VALUE ary;
817 if (capa < 0) {
818 rb_raise(rb_eArgError, "negative array size (or size too big)");
820 if (capa > ARY_MAX_SIZE) {
821 rb_raise(rb_eArgError, "array size too big");
824 RUBY_DTRACE_CREATE_HOOK(ARRAY, capa);
826 if (ary_embeddable_p(capa)) {
827 ary = ec_ary_alloc_embed(ec, klass, capa);
829 else {
830 ary = ec_ary_alloc_heap(ec, klass);
831 ARY_SET_CAPA(ary, capa);
832 RUBY_ASSERT(!ARY_EMBED_P(ary));
834 ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
835 ARY_SET_HEAP_LEN(ary, 0);
838 return ary;
841 VALUE
842 rb_ec_ary_new_from_values(rb_execution_context_t *ec, long n, const VALUE *elts)
844 VALUE ary;
846 ary = ec_ary_new(ec, rb_cArray, n);
847 if (n > 0 && elts) {
848 ary_memcpy(ary, 0, n, elts);
849 ARY_SET_LEN(ary, n);
852 return ary;
855 VALUE
856 rb_ary_hidden_new(long capa)
858 VALUE ary = ary_new(0, capa);
859 return ary;
862 VALUE
863 rb_ary_hidden_new_fill(long capa)
865 VALUE ary = rb_ary_hidden_new(capa);
866 ary_memfill(ary, 0, capa, Qnil);
867 ARY_SET_LEN(ary, capa);
868 return ary;
871 void
872 rb_ary_free(VALUE ary)
874 if (ARY_OWNS_HEAP_P(ary)) {
875 if (USE_DEBUG_COUNTER &&
876 !ARY_SHARED_ROOT_P(ary) &&
877 ARY_HEAP_CAPA(ary) > RARRAY_LEN(ary)) {
878 RB_DEBUG_COUNTER_INC(obj_ary_extracapa);
881 RB_DEBUG_COUNTER_INC(obj_ary_ptr);
882 ary_heap_free(ary);
884 else {
885 RB_DEBUG_COUNTER_INC(obj_ary_embed);
888 if (ARY_SHARED_P(ary)) {
889 RB_DEBUG_COUNTER_INC(obj_ary_shared);
891 if (ARY_SHARED_ROOT_P(ary) && ARY_SHARED_ROOT_OCCUPIED(ary)) {
892 RB_DEBUG_COUNTER_INC(obj_ary_shared_root_occupied);
896 static VALUE fake_ary_flags;
898 static VALUE
899 init_fake_ary_flags(void)
901 struct RArray fake_ary = {0};
902 fake_ary.basic.flags = T_ARRAY;
903 VALUE ary = (VALUE)&fake_ary;
904 rb_ary_freeze(ary);
905 return fake_ary.basic.flags;
908 VALUE
909 rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len)
911 fake_ary->basic.flags = fake_ary_flags;
912 RBASIC_CLEAR_CLASS((VALUE)fake_ary);
914 // bypass frozen checks
915 fake_ary->as.heap.ptr = list;
916 fake_ary->as.heap.len = len;
917 fake_ary->as.heap.aux.capa = len;
918 return (VALUE)fake_ary;
921 size_t
922 rb_ary_memsize(VALUE ary)
924 if (ARY_OWNS_HEAP_P(ary)) {
925 return ARY_CAPA(ary) * sizeof(VALUE);
927 else {
928 return 0;
932 static VALUE
933 ary_make_shared(VALUE ary)
935 ary_verify(ary);
937 if (ARY_SHARED_P(ary)) {
938 return ARY_SHARED_ROOT(ary);
940 else if (ARY_SHARED_ROOT_P(ary)) {
941 return ary;
943 else if (OBJ_FROZEN(ary)) {
944 return ary;
946 else {
947 long capa = ARY_CAPA(ary);
948 long len = RARRAY_LEN(ary);
950 /* Shared roots cannot be embedded because the reference count
951 * (refcnt) is stored in as.heap.aux.capa. */
952 VALUE shared = ary_alloc_heap(0);
953 FL_SET_SHARED_ROOT(shared);
955 if (ARY_EMBED_P(ary)) {
956 VALUE *ptr = ary_heap_alloc_buffer(capa);
957 ARY_SET_PTR(shared, ptr);
958 ary_memcpy(shared, 0, len, RARRAY_CONST_PTR(ary));
960 FL_UNSET_EMBED(ary);
961 ARY_SET_HEAP_LEN(ary, len);
962 ARY_SET_PTR(ary, ptr);
964 else {
965 ARY_SET_PTR(shared, RARRAY_CONST_PTR(ary));
968 ARY_SET_LEN(shared, capa);
969 ary_mem_clear(shared, len, capa - len);
970 rb_ary_set_shared(ary, shared);
972 ary_verify(shared);
973 ary_verify(ary);
975 return shared;
979 static VALUE
980 ary_make_substitution(VALUE ary)
982 long len = RARRAY_LEN(ary);
984 if (ary_embeddable_p(len)) {
985 VALUE subst = rb_ary_new_capa(len);
986 RUBY_ASSERT(ARY_EMBED_P(subst));
988 ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary));
989 ARY_SET_EMBED_LEN(subst, len);
990 return subst;
992 else {
993 return rb_ary_increment_share(ary_make_shared(ary));
997 VALUE
998 rb_assoc_new(VALUE car, VALUE cdr)
1000 return rb_ary_new3(2, car, cdr);
1003 VALUE
1004 rb_to_array_type(VALUE ary)
1006 return rb_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
1008 #define to_ary rb_to_array_type
1010 VALUE
1011 rb_check_array_type(VALUE ary)
1013 return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
1016 VALUE
1017 rb_check_to_array(VALUE ary)
1019 return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
1022 VALUE
1023 rb_to_array(VALUE ary)
1025 return rb_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
1029 * call-seq:
1030 * Array.try_convert(object) -> object, new_array, or nil
1032 * Attempts to return an array, based on the given +object+.
1034 * If +object+ is an array, returns +object+.
1036 * Otherwise if +object+ responds to <tt>:to_ary</tt>.
1037 * calls <tt>object.to_ary</tt>:
1038 * if the return value is an array or +nil+, returns that value;
1039 * if not, raises TypeError.
1041 * Otherwise returns +nil+.
1043 * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
1046 static VALUE
1047 rb_ary_s_try_convert(VALUE dummy, VALUE ary)
1049 return rb_check_array_type(ary);
1052 /* :nodoc: */
1053 static VALUE
1054 rb_ary_s_new(int argc, VALUE *argv, VALUE klass)
1056 VALUE ary;
1058 if (klass == rb_cArray) {
1059 long size = 0;
1060 if (argc > 0 && FIXNUM_P(argv[0])) {
1061 size = FIX2LONG(argv[0]);
1062 if (size < 0) size = 0;
1065 ary = ary_new(klass, size);
1067 rb_obj_call_init_kw(ary, argc, argv, RB_PASS_CALLED_KEYWORDS);
1069 else {
1070 ary = rb_class_new_instance_pass_kw(argc, argv, klass);
1073 return ary;
1077 * call-seq:
1078 * Array.new -> new_empty_array
1079 * Array.new(array) -> new_array
1080 * Array.new(size, default_value = nil) -> new_array
1081 * Array.new(size = 0) {|index| ... } -> new_array
1083 * Returns a new array.
1085 * With no block and no argument given, returns a new empty array:
1087 * Array.new # => []
1089 * With no block and array argument given, returns a new array with the same elements:
1091 * Array.new([:foo, 'bar', 2]) # => [:foo, "bar", 2]
1093 * With no block and integer argument given, returns a new array containing
1094 * that many instances of the given +default_value+:
1096 * Array.new(0) # => []
1097 * Array.new(3) # => [nil, nil, nil]
1098 * Array.new(2, 3) # => [3, 3]
1100 * With a block given, returns an array of the given +size+;
1101 * calls the block with each +index+ in the range <tt>(0...size)</tt>;
1102 * the element at that +index+ in the returned array is the blocks return value:
1104 * Array.new(3) {|index| "Element #{index}" } # => ["Element 0", "Element 1", "Element 2"]
1106 * A common pitfall for new Rubyists is providing an expression as +default_value+:
1108 * array = Array.new(2, {})
1109 * array # => [{}, {}]
1110 * array[0][:a] = 1
1111 * array # => [{a: 1}, {a: 1}], as array[0] and array[1] are same object
1113 * If you want the elements of the array to be distinct, you should pass a block:
1115 * array = Array.new(2) { {} }
1116 * array # => [{}, {}]
1117 * array[0][:a] = 1
1118 * array # => [{a: 1}, {}], as array[0] and array[1] are different objects
1120 * Raises TypeError if the first argument is not either an array
1121 * or an {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]).
1122 * Raises ArgumentError if the first argument is a negative integer.
1124 * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
1127 static VALUE
1128 rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
1130 long len;
1131 VALUE size, val;
1133 rb_ary_modify(ary);
1134 if (argc == 0) {
1135 rb_ary_reset(ary);
1136 RUBY_ASSERT(ARY_EMBED_P(ary));
1137 RUBY_ASSERT(ARY_EMBED_LEN(ary) == 0);
1138 if (rb_block_given_p()) {
1139 rb_warning("given block not used");
1141 return ary;
1143 rb_scan_args(argc, argv, "02", &size, &val);
1144 if (argc == 1 && !FIXNUM_P(size)) {
1145 val = rb_check_array_type(size);
1146 if (!NIL_P(val)) {
1147 rb_ary_replace(ary, val);
1148 return ary;
1152 len = NUM2LONG(size);
1153 /* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */
1154 if (len < 0) {
1155 rb_raise(rb_eArgError, "negative array size");
1157 if (len > ARY_MAX_SIZE) {
1158 rb_raise(rb_eArgError, "array size too big");
1160 /* recheck after argument conversion */
1161 rb_ary_modify(ary);
1162 ary_resize_capa(ary, len);
1163 if (rb_block_given_p()) {
1164 long i;
1166 if (argc == 2) {
1167 rb_warn("block supersedes default value argument");
1169 for (i=0; i<len; i++) {
1170 rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
1171 ARY_SET_LEN(ary, i + 1);
1174 else {
1175 ary_memfill(ary, 0, len, val);
1176 ARY_SET_LEN(ary, len);
1178 return ary;
1182 * Returns a new array, populated with the given objects:
1184 * Array[1, 'a', /^A/] # => [1, "a", /^A/]
1185 * Array[] # => []
1186 * Array.[](1, 'a', /^A/) # => [1, "a", /^A/]
1188 * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
1191 static VALUE
1192 rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
1194 VALUE ary = ary_new(klass, argc);
1195 if (argc > 0 && argv) {
1196 ary_memcpy(ary, 0, argc, argv);
1197 ARY_SET_LEN(ary, argc);
1200 return ary;
1203 void
1204 rb_ary_store(VALUE ary, long idx, VALUE val)
1206 long len = RARRAY_LEN(ary);
1208 if (idx < 0) {
1209 idx += len;
1210 if (idx < 0) {
1211 rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
1212 idx - len, -len);
1215 else if (idx >= ARY_MAX_SIZE) {
1216 rb_raise(rb_eIndexError, "index %ld too big", idx);
1219 rb_ary_modify(ary);
1220 if (idx >= ARY_CAPA(ary)) {
1221 ary_double_capa(ary, idx);
1223 if (idx > len) {
1224 ary_mem_clear(ary, len, idx - len + 1);
1227 if (idx >= len) {
1228 ARY_SET_LEN(ary, idx + 1);
1230 ARY_SET(ary, idx, val);
1233 static VALUE
1234 ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
1236 RUBY_ASSERT(offset >= 0);
1237 RUBY_ASSERT(len >= 0);
1238 RUBY_ASSERT(offset+len <= RARRAY_LEN(ary));
1240 VALUE result = ary_alloc_heap(klass);
1241 size_t embed_capa = ary_embed_capa(result);
1242 if ((size_t)len <= embed_capa) {
1243 FL_SET_EMBED(result);
1244 ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset);
1245 ARY_SET_EMBED_LEN(result, len);
1247 else {
1248 VALUE shared = ary_make_shared(ary);
1250 /* The ary_make_shared call may allocate, which can trigger a GC
1251 * compaction. This can cause the array to be embedded because it has
1252 * a length of 0. */
1253 FL_UNSET_EMBED(result);
1255 ARY_SET_PTR(result, RARRAY_CONST_PTR(ary));
1256 ARY_SET_LEN(result, RARRAY_LEN(ary));
1257 rb_ary_set_shared(result, shared);
1259 ARY_INCREASE_PTR(result, offset);
1260 ARY_SET_LEN(result, len);
1262 ary_verify(shared);
1265 ary_verify(result);
1266 return result;
1269 static VALUE
1270 ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
1272 RUBY_ASSERT(offset >= 0);
1273 RUBY_ASSERT(len >= 0);
1274 RUBY_ASSERT(offset+len <= RARRAY_LEN(ary));
1275 RUBY_ASSERT(step != 0);
1277 const long orig_len = len;
1279 if (step > 0 && step >= len) {
1280 VALUE result = ary_new(klass, 1);
1281 VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
1282 const VALUE *values = RARRAY_CONST_PTR(ary);
1284 RB_OBJ_WRITE(result, ptr, values[offset]);
1285 ARY_SET_EMBED_LEN(result, 1);
1286 return result;
1288 else if (step < 0 && step < -len) {
1289 step = -len;
1292 long ustep = (step < 0) ? -step : step;
1293 len = roomof(len, ustep);
1295 long i;
1296 long j = offset + ((step > 0) ? 0 : (orig_len - 1));
1298 VALUE result = ary_new(klass, len);
1299 if (ARY_EMBED_P(result)) {
1300 VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
1301 const VALUE *values = RARRAY_CONST_PTR(ary);
1303 for (i = 0; i < len; ++i) {
1304 RB_OBJ_WRITE(result, ptr+i, values[j]);
1305 j += step;
1307 ARY_SET_EMBED_LEN(result, len);
1309 else {
1310 const VALUE *values = RARRAY_CONST_PTR(ary);
1312 RARRAY_PTR_USE(result, ptr, {
1313 for (i = 0; i < len; ++i) {
1314 RB_OBJ_WRITE(result, ptr+i, values[j]);
1315 j += step;
1318 ARY_SET_LEN(result, len);
1321 return result;
1324 static VALUE
1325 ary_make_shared_copy(VALUE ary)
1327 return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary));
1330 enum ary_take_pos_flags
1332 ARY_TAKE_FIRST = 0,
1333 ARY_TAKE_LAST = 1
1336 static VALUE
1337 ary_take_first_or_last_n(VALUE ary, long n, enum ary_take_pos_flags last)
1339 long len = RARRAY_LEN(ary);
1340 long offset = 0;
1342 if (n > len) {
1343 n = len;
1345 else if (n < 0) {
1346 rb_raise(rb_eArgError, "negative array size");
1348 if (last) {
1349 offset = len - n;
1351 return ary_make_partial(ary, rb_cArray, offset, n);
1354 static VALUE
1355 ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
1357 argc = rb_check_arity(argc, 0, 1);
1358 /* the case optional argument is omitted should be handled in
1359 * callers of this function. if another arity case is added,
1360 * this arity check needs to rewrite. */
1361 RUBY_ASSERT_ALWAYS(argc == 1);
1362 return ary_take_first_or_last_n(ary, NUM2LONG(argv[0]), last);
1366 * call-seq:
1367 * self << object -> self
1369 * Appends +object+ as the last element in +self+; returns +self+:
1371 * [:foo, 'bar', 2] << :baz # => [:foo, "bar", 2, :baz]
1373 * Appends +object+ as a single element, even if it is another array:
1375 * [:foo, 'bar', 2] << [3, 4] # => [:foo, "bar", 2, [3, 4]]
1377 * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
1380 VALUE
1381 rb_ary_push(VALUE ary, VALUE item)
1383 long idx = RARRAY_LEN((ary_verify(ary), ary));
1384 VALUE target_ary = ary_ensure_room_for_push(ary, 1);
1385 RARRAY_PTR_USE(ary, ptr, {
1386 RB_OBJ_WRITE(target_ary, &ptr[idx], item);
1388 ARY_SET_LEN(ary, idx + 1);
1389 ary_verify(ary);
1390 return ary;
1393 VALUE
1394 rb_ary_cat(VALUE ary, const VALUE *argv, long len)
1396 long oldlen = RARRAY_LEN(ary);
1397 VALUE target_ary = ary_ensure_room_for_push(ary, len);
1398 ary_memcpy0(ary, oldlen, len, argv, target_ary);
1399 ARY_SET_LEN(ary, oldlen + len);
1400 return ary;
1404 * call-seq:
1405 * push(*objects) -> self
1406 * append(*objects) -> self
1408 * Appends each argument in +objects+ to +self+; returns +self+:
1410 * a = [:foo, 'bar', 2] # => [:foo, "bar", 2]
1411 * a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
1413 * Appends each argument as a single element, even if it is another array:
1415 * a = [:foo, 'bar', 2] # => [:foo, "bar", 2]
1416 a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
1418 * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
1421 static VALUE
1422 rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
1424 return rb_ary_cat(ary, argv, argc);
1427 VALUE
1428 rb_ary_pop(VALUE ary)
1430 long n;
1431 rb_ary_modify_check(ary);
1432 n = RARRAY_LEN(ary);
1433 if (n == 0) return Qnil;
1434 if (ARY_OWNS_HEAP_P(ary) &&
1435 n * 3 < ARY_CAPA(ary) &&
1436 ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
1438 ary_resize_capa(ary, n * 2);
1440 --n;
1441 ARY_SET_LEN(ary, n);
1442 ary_verify(ary);
1443 return RARRAY_AREF(ary, n);
1447 * call-seq:
1448 * array.pop -> object or nil
1449 * array.pop(n) -> new_array
1451 * Removes and returns trailing elements.
1453 * When no argument is given and +self+ is not empty,
1454 * removes and returns the last element:
1456 * a = [:foo, 'bar', 2]
1457 * a.pop # => 2
1458 * a # => [:foo, "bar"]
1460 * Returns +nil+ if the array is empty.
1462 * When a non-negative Integer argument +n+ is given and is in range,
1464 * removes and returns the last +n+ elements in a new +Array+:
1465 * a = [:foo, 'bar', 2]
1466 * a.pop(2) # => ["bar", 2]
1468 * If +n+ is positive and out of range,
1469 * removes and returns all elements:
1471 * a = [:foo, 'bar', 2]
1472 * a.pop(50) # => [:foo, "bar", 2]
1474 * Related: #push, #shift, #unshift.
1477 static VALUE
1478 rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
1480 VALUE result;
1482 if (argc == 0) {
1483 return rb_ary_pop(ary);
1486 rb_ary_modify_check(ary);
1487 result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
1488 ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
1489 ary_verify(ary);
1490 return result;
1493 VALUE
1494 rb_ary_shift(VALUE ary)
1496 VALUE top;
1497 long len = RARRAY_LEN(ary);
1499 if (len == 0) {
1500 rb_ary_modify_check(ary);
1501 return Qnil;
1504 top = RARRAY_AREF(ary, 0);
1506 rb_ary_behead(ary, 1);
1508 return top;
1512 * call-seq:
1513 * array.shift -> object or nil
1514 * array.shift(n) -> new_array
1516 * Removes and returns leading elements.
1518 * When no argument is given, removes and returns the first element:
1520 * a = [:foo, 'bar', 2]
1521 * a.shift # => :foo
1522 * a # => ['bar', 2]
1524 * Returns +nil+ if +self+ is empty.
1526 * When positive Integer argument +n+ is given, removes the first +n+ elements;
1527 * returns those elements in a new +Array+:
1529 * a = [:foo, 'bar', 2]
1530 * a.shift(2) # => [:foo, 'bar']
1531 * a # => [2]
1533 * If +n+ is as large as or larger than <tt>self.length</tt>,
1534 * removes all elements; returns those elements in a new +Array+:
1536 * a = [:foo, 'bar', 2]
1537 * a.shift(3) # => [:foo, 'bar', 2]
1539 * If +n+ is zero, returns a new empty +Array+; +self+ is unmodified.
1541 * Related: #push, #pop, #unshift.
1544 static VALUE
1545 rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
1547 VALUE result;
1548 long n;
1550 if (argc == 0) {
1551 return rb_ary_shift(ary);
1554 rb_ary_modify_check(ary);
1555 result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
1556 n = RARRAY_LEN(result);
1557 rb_ary_behead(ary,n);
1559 return result;
1562 VALUE
1563 rb_ary_behead(VALUE ary, long n)
1565 if (n <= 0) {
1566 return ary;
1569 rb_ary_modify_check(ary);
1571 if (!ARY_SHARED_P(ary)) {
1572 if (ARY_EMBED_P(ary) || RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
1573 RARRAY_PTR_USE(ary, ptr, {
1574 MEMMOVE(ptr, ptr + n, VALUE, RARRAY_LEN(ary) - n);
1575 }); /* WB: no new reference */
1576 ARY_INCREASE_LEN(ary, -n);
1577 ary_verify(ary);
1578 return ary;
1581 ary_mem_clear(ary, 0, n);
1582 ary_make_shared(ary);
1584 else if (ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))) {
1585 ary_mem_clear(ary, 0, n);
1588 ARY_INCREASE_PTR(ary, n);
1589 ARY_INCREASE_LEN(ary, -n);
1590 ary_verify(ary);
1592 return ary;
1595 static VALUE
1596 make_room_for_unshift(VALUE ary, const VALUE *head, VALUE *sharedp, int argc, long capa, long len)
1598 if (head - sharedp < argc) {
1599 long room = capa - len - argc;
1601 room -= room >> 4;
1602 MEMMOVE((VALUE *)sharedp + argc + room, head, VALUE, len);
1603 head = sharedp + argc + room;
1605 ARY_SET_PTR(ary, head - argc);
1606 RUBY_ASSERT(ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary)));
1608 ary_verify(ary);
1609 return ARY_SHARED_ROOT(ary);
1612 static VALUE
1613 ary_modify_for_unshift(VALUE ary, int argc)
1615 long len = RARRAY_LEN(ary);
1616 long new_len = len + argc;
1617 long capa;
1618 const VALUE *head, *sharedp;
1620 rb_ary_modify(ary);
1621 capa = ARY_CAPA(ary);
1622 if (capa - (capa >> 6) <= new_len) {
1623 ary_double_capa(ary, new_len);
1626 /* use shared array for big "queues" */
1627 if (new_len > ARY_DEFAULT_SIZE * 4 && !ARY_EMBED_P(ary)) {
1628 ary_verify(ary);
1630 /* make a room for unshifted items */
1631 capa = ARY_CAPA(ary);
1632 ary_make_shared(ary);
1634 head = sharedp = RARRAY_CONST_PTR(ary);
1635 return make_room_for_unshift(ary, head, (void *)sharedp, argc, capa, len);
1637 else {
1638 /* sliding items */
1639 RARRAY_PTR_USE(ary, ptr, {
1640 MEMMOVE(ptr + argc, ptr, VALUE, len);
1643 ary_verify(ary);
1644 return ary;
1648 static VALUE
1649 ary_ensure_room_for_unshift(VALUE ary, int argc)
1651 long len = RARRAY_LEN(ary);
1652 long new_len = len + argc;
1654 if (len > ARY_MAX_SIZE - argc) {
1655 rb_raise(rb_eIndexError, "index %ld too big", new_len);
1657 else if (! ARY_SHARED_P(ary)) {
1658 return ary_modify_for_unshift(ary, argc);
1660 else {
1661 VALUE shared_root = ARY_SHARED_ROOT(ary);
1662 long capa = RARRAY_LEN(shared_root);
1664 if (! ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
1665 return ary_modify_for_unshift(ary, argc);
1667 else if (new_len > capa) {
1668 return ary_modify_for_unshift(ary, argc);
1670 else {
1671 const VALUE * head = RARRAY_CONST_PTR(ary);
1672 void *sharedp = (void *)RARRAY_CONST_PTR(shared_root);
1674 rb_ary_modify_check(ary);
1675 return make_room_for_unshift(ary, head, sharedp, argc, capa, len);
1681 * call-seq:
1682 * array.unshift(*objects) -> self
1684 * Prepends the given +objects+ to +self+:
1686 * a = [:foo, 'bar', 2]
1687 * a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
1689 * Related: #push, #pop, #shift.
1692 VALUE
1693 rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
1695 long len = RARRAY_LEN(ary);
1696 VALUE target_ary;
1698 if (argc == 0) {
1699 rb_ary_modify_check(ary);
1700 return ary;
1703 target_ary = ary_ensure_room_for_unshift(ary, argc);
1704 ary_memcpy0(ary, 0, argc, argv, target_ary);
1705 ARY_SET_LEN(ary, len + argc);
1706 return ary;
1709 VALUE
1710 rb_ary_unshift(VALUE ary, VALUE item)
1712 return rb_ary_unshift_m(1, &item, ary);
1715 /* faster version - use this if you don't need to treat negative offset */
1716 static inline VALUE
1717 rb_ary_elt(VALUE ary, long offset)
1719 long len = RARRAY_LEN(ary);
1720 if (len == 0) return Qnil;
1721 if (offset < 0 || len <= offset) {
1722 return Qnil;
1724 return RARRAY_AREF(ary, offset);
1727 VALUE
1728 rb_ary_entry(VALUE ary, long offset)
1730 return rb_ary_entry_internal(ary, offset);
1733 VALUE
1734 rb_ary_subseq_step(VALUE ary, long beg, long len, long step)
1736 VALUE klass;
1737 long alen = RARRAY_LEN(ary);
1739 if (beg > alen) return Qnil;
1740 if (beg < 0 || len < 0) return Qnil;
1742 if (alen < len || alen < beg + len) {
1743 len = alen - beg;
1745 klass = rb_cArray;
1746 if (len == 0) return ary_new(klass, 0);
1747 if (step == 0)
1748 rb_raise(rb_eArgError, "slice step cannot be zero");
1749 if (step == 1)
1750 return ary_make_partial(ary, klass, beg, len);
1751 else
1752 return ary_make_partial_step(ary, klass, beg, len, step);
1755 VALUE
1756 rb_ary_subseq(VALUE ary, long beg, long len)
1758 return rb_ary_subseq_step(ary, beg, len, 1);
1761 static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
1764 * call-seq:
1765 * self[index] -> object or nil
1766 * self[start, length] -> object or nil
1767 * self[range] -> object or nil
1768 * self[aseq] -> object or nil
1769 * slice(index) -> object or nil
1770 * slice(start, length) -> object or nil
1771 * slice(range) -> object or nil
1772 * slice(aseq) -> object or nil
1774 * Returns elements from +self+; does not modify +self+.
1776 * In brief:
1778 * a = [:foo, 'bar', 2]
1780 * # Single argument index: returns one element.
1781 * a[0] # => :foo # Zero-based index.
1782 * a[-1] # => 2 # Negative index counts backwards from end.
1784 * # Arguments start and length: returns an array.
1785 * a[1, 2] # => ["bar", 2]
1786 * a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end.
1788 * # Single argument range: returns an array.
1789 * a[0..1] # => [:foo, "bar"]
1790 * a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end.
1791 * a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
1793 * When a single integer argument +index+ is given, returns the element at offset +index+:
1795 * a = [:foo, 'bar', 2]
1796 * a[0] # => :foo
1797 * a[2] # => 2
1798 * a # => [:foo, "bar", 2]
1800 * If +index+ is negative, counts backwards from the end of +self+:
1802 * a = [:foo, 'bar', 2]
1803 * a[-1] # => 2
1804 * a[-2] # => "bar"
1806 * If +index+ is out of range, returns +nil+.
1808 * When two Integer arguments +start+ and +length+ are given,
1809 * returns a new +Array+ of size +length+ containing successive elements beginning at offset +start+:
1811 * a = [:foo, 'bar', 2]
1812 * a[0, 2] # => [:foo, "bar"]
1813 * a[1, 2] # => ["bar", 2]
1815 * If <tt>start + length</tt> is greater than <tt>self.length</tt>,
1816 * returns all elements from offset +start+ to the end:
1818 * a = [:foo, 'bar', 2]
1819 * a[0, 4] # => [:foo, "bar", 2]
1820 * a[1, 3] # => ["bar", 2]
1821 * a[2, 2] # => [2]
1823 * If <tt>start == self.size</tt> and <tt>length >= 0</tt>,
1824 * returns a new empty +Array+.
1826 * If +length+ is negative, returns +nil+.
1828 * When a single Range argument +range+ is given,
1829 * treats <tt>range.min</tt> as +start+ above
1830 * and <tt>range.size</tt> as +length+ above:
1832 * a = [:foo, 'bar', 2]
1833 * a[0..1] # => [:foo, "bar"]
1834 * a[1..2] # => ["bar", 2]
1836 * Special case: If <tt>range.start == a.size</tt>, returns a new empty +Array+.
1838 * If <tt>range.end</tt> is negative, calculates the end index from the end:
1840 * a = [:foo, 'bar', 2]
1841 * a[0..-1] # => [:foo, "bar", 2]
1842 * a[0..-2] # => [:foo, "bar"]
1843 * a[0..-3] # => [:foo]
1845 * If <tt>range.start</tt> is negative, calculates the start index from the end:
1847 * a = [:foo, 'bar', 2]
1848 * a[-1..2] # => [2]
1849 * a[-2..2] # => ["bar", 2]
1850 * a[-3..2] # => [:foo, "bar", 2]
1852 * If <tt>range.start</tt> is larger than the array size, returns +nil+.
1854 * a = [:foo, 'bar', 2]
1855 * a[4..1] # => nil
1856 * a[4..0] # => nil
1857 * a[4..-1] # => nil
1859 * When a single Enumerator::ArithmeticSequence argument +aseq+ is given,
1860 * returns an +Array+ of elements corresponding to the indexes produced by
1861 * the sequence.
1863 * a = ['--', 'data1', '--', 'data2', '--', 'data3']
1864 * a[(1..).step(2)] # => ["data1", "data2", "data3"]
1866 * Unlike slicing with range, if the start or the end of the arithmetic sequence
1867 * is larger than array size, throws RangeError.
1869 * a = ['--', 'data1', '--', 'data2', '--', 'data3']
1870 * a[(1..11).step(2)]
1871 * # RangeError (((1..11).step(2)) out of range)
1872 * a[(7..).step(2)]
1873 * # RangeError (((7..).step(2)) out of range)
1875 * If given a single argument, and its type is not one of the listed, tries to
1876 * convert it to Integer, and raises if it is impossible:
1878 * a = [:foo, 'bar', 2]
1879 * # Raises TypeError (no implicit conversion of Symbol into Integer):
1880 * a[:foo]
1882 * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
1885 VALUE
1886 rb_ary_aref(int argc, const VALUE *argv, VALUE ary)
1888 rb_check_arity(argc, 1, 2);
1889 if (argc == 2) {
1890 return rb_ary_aref2(ary, argv[0], argv[1]);
1892 return rb_ary_aref1(ary, argv[0]);
1895 static VALUE
1896 rb_ary_aref2(VALUE ary, VALUE b, VALUE e)
1898 long beg = NUM2LONG(b);
1899 long len = NUM2LONG(e);
1900 if (beg < 0) {
1901 beg += RARRAY_LEN(ary);
1903 return rb_ary_subseq(ary, beg, len);
1906 VALUE
1907 rb_ary_aref1(VALUE ary, VALUE arg)
1909 long beg, len, step;
1911 /* special case - speeding up */
1912 if (FIXNUM_P(arg)) {
1913 return rb_ary_entry(ary, FIX2LONG(arg));
1915 /* check if idx is Range or ArithmeticSequence */
1916 switch (rb_arithmetic_sequence_beg_len_step(arg, &beg, &len, &step, RARRAY_LEN(ary), 0)) {
1917 case Qfalse:
1918 break;
1919 case Qnil:
1920 return Qnil;
1921 default:
1922 return rb_ary_subseq_step(ary, beg, len, step);
1925 return rb_ary_entry(ary, NUM2LONG(arg));
1929 * call-seq:
1930 * at(index) -> object or nil
1932 * Returns the element of +self+ specified by the given +index+
1933 * or +nil+ if there is no such element;
1934 * +index+ must be an
1935 * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
1937 * For non-negative +index+, returns the element of +self+ at offset +index+:
1939 * a = [:foo, 'bar', 2]
1940 * a.at(0) # => :foo
1941 * a.at(2) # => 2
1942 * a.at(2.0) # => 2
1944 * For negative +index+, counts backwards from the end of +self+:
1946 * a.at(-2) # => "bar"
1948 * Related: Array#[];
1949 * see also {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
1952 VALUE
1953 rb_ary_at(VALUE ary, VALUE pos)
1955 return rb_ary_entry(ary, NUM2LONG(pos));
1958 #if 0
1959 static VALUE
1960 rb_ary_first(int argc, VALUE *argv, VALUE ary)
1962 if (argc == 0) {
1963 if (RARRAY_LEN(ary) == 0) return Qnil;
1964 return RARRAY_AREF(ary, 0);
1966 else {
1967 return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
1970 #endif
1972 static VALUE
1973 ary_first(VALUE self)
1975 return (RARRAY_LEN(self) == 0) ? Qnil : RARRAY_AREF(self, 0);
1978 static VALUE
1979 ary_last(VALUE self)
1981 long len = RARRAY_LEN(self);
1982 return (len == 0) ? Qnil : RARRAY_AREF(self, len-1);
1985 VALUE
1986 rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
1988 if (argc == 0) {
1989 return ary_last(ary);
1991 else {
1992 return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
1997 * call-seq:
1998 * array.fetch(index) -> element
1999 * array.fetch(index, default_value) -> element
2000 * array.fetch(index) {|index| ... } -> element
2002 * Returns the element at offset +index+.
2004 * With the single Integer argument +index+,
2005 * returns the element at offset +index+:
2007 * a = [:foo, 'bar', 2]
2008 * a.fetch(1) # => "bar"
2010 * If +index+ is negative, counts from the end of the array:
2012 * a = [:foo, 'bar', 2]
2013 * a.fetch(-1) # => 2
2014 * a.fetch(-2) # => "bar"
2016 * With arguments +index+ and +default_value+,
2017 * returns the element at offset +index+ if index is in range,
2018 * otherwise returns +default_value+:
2020 * a = [:foo, 'bar', 2]
2021 * a.fetch(1, nil) # => "bar"
2023 * With argument +index+ and a block,
2024 * returns the element at offset +index+ if index is in range
2025 * (and the block is not called); otherwise calls the block with index and returns its return value:
2027 * a = [:foo, 'bar', 2]
2028 * a.fetch(1) {|index| raise 'Cannot happen' } # => "bar"
2029 * a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
2033 static VALUE
2034 rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
2036 VALUE pos, ifnone;
2037 long block_given;
2038 long idx;
2040 rb_scan_args(argc, argv, "11", &pos, &ifnone);
2041 block_given = rb_block_given_p();
2042 if (block_given && argc == 2) {
2043 rb_warn("block supersedes default value argument");
2045 idx = NUM2LONG(pos);
2047 if (idx < 0) {
2048 idx += RARRAY_LEN(ary);
2050 if (idx < 0 || RARRAY_LEN(ary) <= idx) {
2051 if (block_given) return rb_yield(pos);
2052 if (argc == 1) {
2053 rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld",
2054 idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary));
2056 return ifnone;
2058 return RARRAY_AREF(ary, idx);
2062 * call-seq:
2063 * array.index(object) -> integer or nil
2064 * array.index {|element| ... } -> integer or nil
2065 * array.index -> new_enumerator
2067 * Returns the index of a specified element.
2069 * When argument +object+ is given but no block,
2070 * returns the index of the first element +element+
2071 * for which <tt>object == element</tt>:
2073 * a = [:foo, 'bar', 2, 'bar']
2074 * a.index('bar') # => 1
2076 * Returns +nil+ if no such element found.
2078 * When both argument +object+ and a block are given,
2079 * calls the block with each successive element;
2080 * returns the index of the first element for which the block returns a truthy value:
2082 * a = [:foo, 'bar', 2, 'bar']
2083 * a.index {|element| element == 'bar' } # => 1
2085 * Returns +nil+ if the block never returns a truthy value.
2087 * When neither an argument nor a block is given, returns a new Enumerator:
2089 * a = [:foo, 'bar', 2]
2090 * e = a.index
2091 * e # => #<Enumerator: [:foo, "bar", 2]:index>
2092 * e.each {|element| element == 'bar' } # => 1
2094 * Related: #rindex.
2097 static VALUE
2098 rb_ary_index(int argc, VALUE *argv, VALUE ary)
2100 VALUE val;
2101 long i;
2103 if (argc == 0) {
2104 RETURN_ENUMERATOR(ary, 0, 0);
2105 for (i=0; i<RARRAY_LEN(ary); i++) {
2106 if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
2107 return LONG2NUM(i);
2110 return Qnil;
2112 rb_check_arity(argc, 0, 1);
2113 val = argv[0];
2114 if (rb_block_given_p())
2115 rb_warn("given block not used");
2116 for (i=0; i<RARRAY_LEN(ary); i++) {
2117 VALUE e = RARRAY_AREF(ary, i);
2118 if (rb_equal(e, val)) {
2119 return LONG2NUM(i);
2122 return Qnil;
2126 * call-seq:
2127 * array.rindex(object) -> integer or nil
2128 * array.rindex {|element| ... } -> integer or nil
2129 * array.rindex -> new_enumerator
2131 * Returns the index of the last element for which <tt>object == element</tt>.
2133 * When argument +object+ is given but no block, returns the index of the last such element found:
2135 * a = [:foo, 'bar', 2, 'bar']
2136 * a.rindex('bar') # => 3
2138 * Returns +nil+ if no such object found.
2140 * When a block is given but no argument, calls the block with each successive element;
2141 * returns the index of the last element for which the block returns a truthy value:
2143 * a = [:foo, 'bar', 2, 'bar']
2144 * a.rindex {|element| element == 'bar' } # => 3
2146 * Returns +nil+ if the block never returns a truthy value.
2148 * When neither an argument nor a block is given, returns a new Enumerator:
2150 * a = [:foo, 'bar', 2, 'bar']
2151 * e = a.rindex
2152 * e # => #<Enumerator: [:foo, "bar", 2, "bar"]:rindex>
2153 * e.each {|element| element == 'bar' } # => 3
2155 * Related: #index.
2158 static VALUE
2159 rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
2161 VALUE val;
2162 long i = RARRAY_LEN(ary), len;
2164 if (argc == 0) {
2165 RETURN_ENUMERATOR(ary, 0, 0);
2166 while (i--) {
2167 if (RTEST(rb_yield(RARRAY_AREF(ary, i))))
2168 return LONG2NUM(i);
2169 if (i > (len = RARRAY_LEN(ary))) {
2170 i = len;
2173 return Qnil;
2175 rb_check_arity(argc, 0, 1);
2176 val = argv[0];
2177 if (rb_block_given_p())
2178 rb_warn("given block not used");
2179 while (i--) {
2180 VALUE e = RARRAY_AREF(ary, i);
2181 if (rb_equal(e, val)) {
2182 return LONG2NUM(i);
2184 if (i > RARRAY_LEN(ary)) {
2185 break;
2188 return Qnil;
2191 VALUE
2192 rb_ary_to_ary(VALUE obj)
2194 VALUE tmp = rb_check_array_type(obj);
2196 if (!NIL_P(tmp)) return tmp;
2197 return rb_ary_new3(1, obj);
2200 static void
2201 rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
2203 long olen;
2204 long rofs;
2206 if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
2207 olen = RARRAY_LEN(ary);
2208 if (beg < 0) {
2209 beg += olen;
2210 if (beg < 0) {
2211 rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
2212 beg - olen, -olen);
2215 if (olen < len || olen < beg + len) {
2216 len = olen - beg;
2220 const VALUE *optr = RARRAY_CONST_PTR(ary);
2221 rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1;
2224 if (beg >= olen) {
2225 VALUE target_ary;
2226 if (beg > ARY_MAX_SIZE - rlen) {
2227 rb_raise(rb_eIndexError, "index %ld too big", beg);
2229 target_ary = ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */
2230 len = beg + rlen;
2231 ary_mem_clear(ary, olen, beg - olen);
2232 if (rlen > 0) {
2233 if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs;
2234 ary_memcpy0(ary, beg, rlen, rptr, target_ary);
2236 ARY_SET_LEN(ary, len);
2238 else {
2239 long alen;
2241 if (olen - len > ARY_MAX_SIZE - rlen) {
2242 rb_raise(rb_eIndexError, "index %ld too big", olen + rlen - len);
2244 rb_ary_modify(ary);
2245 alen = olen + rlen - len;
2246 if (alen >= ARY_CAPA(ary)) {
2247 ary_double_capa(ary, alen);
2250 if (len != rlen) {
2251 RARRAY_PTR_USE(ary, ptr,
2252 MEMMOVE(ptr + beg + rlen, ptr + beg + len,
2253 VALUE, olen - (beg + len)));
2254 ARY_SET_LEN(ary, alen);
2256 if (rlen > 0) {
2257 if (rofs == -1) {
2258 rb_gc_writebarrier_remember(ary);
2260 else {
2261 /* In this case, we're copying from a region in this array, so
2262 * we don't need to fire the write barrier. */
2263 rptr = RARRAY_CONST_PTR(ary) + rofs;
2266 /* do not use RARRAY_PTR() because it can causes GC.
2267 * ary can contain T_NONE object because it is not cleared.
2269 RARRAY_PTR_USE(ary, ptr,
2270 MEMMOVE(ptr + beg, rptr, VALUE, rlen));
2275 void
2276 rb_ary_set_len(VALUE ary, long len)
2278 long capa;
2280 rb_ary_modify_check(ary);
2281 if (ARY_SHARED_P(ary)) {
2282 rb_raise(rb_eRuntimeError, "can't set length of shared ");
2284 if (len > (capa = (long)ARY_CAPA(ary))) {
2285 rb_bug("probable buffer overflow: %ld for %ld", len, capa);
2287 ARY_SET_LEN(ary, len);
2290 VALUE
2291 rb_ary_resize(VALUE ary, long len)
2293 long olen;
2295 rb_ary_modify(ary);
2296 olen = RARRAY_LEN(ary);
2297 if (len == olen) return ary;
2298 if (len > ARY_MAX_SIZE) {
2299 rb_raise(rb_eIndexError, "index %ld too big", len);
2301 if (len > olen) {
2302 if (len >= ARY_CAPA(ary)) {
2303 ary_double_capa(ary, len);
2305 ary_mem_clear(ary, olen, len - olen);
2306 ARY_SET_LEN(ary, len);
2308 else if (ARY_EMBED_P(ary)) {
2309 ARY_SET_EMBED_LEN(ary, len);
2311 else if (len <= ary_embed_capa(ary)) {
2312 const VALUE *ptr = ARY_HEAP_PTR(ary);
2313 long ptr_capa = ARY_HEAP_SIZE(ary);
2314 bool is_malloc_ptr = !ARY_SHARED_P(ary);
2316 FL_SET_EMBED(ary);
2318 MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */
2319 ARY_SET_EMBED_LEN(ary, len);
2321 if (is_malloc_ptr) ruby_sized_xfree((void *)ptr, ptr_capa);
2323 else {
2324 if (olen > len + ARY_DEFAULT_SIZE) {
2325 size_t new_capa = ary_heap_realloc(ary, len);
2326 ARY_SET_CAPA(ary, new_capa);
2328 ARY_SET_HEAP_LEN(ary, len);
2330 ary_verify(ary);
2331 return ary;
2334 static VALUE
2335 ary_aset_by_rb_ary_store(VALUE ary, long key, VALUE val)
2337 rb_ary_store(ary, key, val);
2338 return val;
2341 static VALUE
2342 ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
2344 VALUE rpl = rb_ary_to_ary(val);
2345 rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl));
2346 RB_GC_GUARD(rpl);
2347 return val;
2351 * call-seq:
2352 * self[index] = object -> object
2353 * self[start, length] = object -> object
2354 * self[range] = object -> object
2356 * Assigns elements in +self+, based on the given +object+; returns +object+.
2358 * In brief:
2360 * a_orig = [:foo, 'bar', 2]
2362 * # With argument index.
2363 * a = a_orig.dup
2364 * a[0] = 'foo' # => "foo"
2365 * a # => ["foo", "bar", 2]
2366 * a = a_orig.dup
2367 * a[7] = 'foo' # => "foo"
2368 * a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
2370 * # With arguments start and length.
2371 * a = a_orig.dup
2372 * a[0, 2] = 'foo' # => "foo"
2373 * a # => ["foo", 2]
2374 * a = a_orig.dup
2375 * a[6, 50] = 'foo' # => "foo"
2376 * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
2378 * # With argument range.
2379 * a = a_orig.dup
2380 * a[0..1] = 'foo' # => "foo"
2381 * a # => ["foo", 2]
2382 * a = a_orig.dup
2383 * a[6..50] = 'foo' # => "foo"
2384 * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
2386 * When Integer argument +index+ is given, assigns +object+ to an element in +self+.
2388 * If +index+ is non-negative, assigns +object+ the element at offset +index+:
2390 * a = [:foo, 'bar', 2]
2391 * a[0] = 'foo' # => "foo"
2392 * a # => ["foo", "bar", 2]
2394 * If +index+ is greater than <tt>self.length</tt>, extends the array:
2396 * a = [:foo, 'bar', 2]
2397 * a[7] = 'foo' # => "foo"
2398 * a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
2400 * If +index+ is negative, counts backwards from the end of the array:
2402 * a = [:foo, 'bar', 2]
2403 * a[-1] = 'two' # => "two"
2404 * a # => [:foo, "bar", "two"]
2406 * When Integer arguments +start+ and +length+ are given and +object+ is not an +Array+,
2407 * removes <tt>length - 1</tt> elements beginning at offset +start+,
2408 * and assigns +object+ at offset +start+:
2410 * a = [:foo, 'bar', 2]
2411 * a[0, 2] = 'foo' # => "foo"
2412 * a # => ["foo", 2]
2414 * If +start+ is negative, counts backwards from the end of the array:
2416 * a = [:foo, 'bar', 2]
2417 * a[-2, 2] = 'foo' # => "foo"
2418 * a # => [:foo, "foo"]
2420 * If +start+ is non-negative and outside the array (<tt> >= self.size</tt>),
2421 * extends the array with +nil+, assigns +object+ at offset +start+,
2422 * and ignores +length+:
2424 * a = [:foo, 'bar', 2]
2425 * a[6, 50] = 'foo' # => "foo"
2426 * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
2428 * If +length+ is zero, shifts elements at and following offset +start+
2429 * and assigns +object+ at offset +start+:
2431 * a = [:foo, 'bar', 2]
2432 * a[1, 0] = 'foo' # => "foo"
2433 * a # => [:foo, "foo", "bar", 2]
2435 * If +length+ is too large for the existing array, does not extend the array:
2437 * a = [:foo, 'bar', 2]
2438 * a[1, 5] = 'foo' # => "foo"
2439 * a # => [:foo, "foo"]
2441 * When Range argument +range+ is given and +object+ is not an +Array+,
2442 * removes <tt>length - 1</tt> elements beginning at offset +start+,
2443 * and assigns +object+ at offset +start+:
2445 * a = [:foo, 'bar', 2]
2446 * a[0..1] = 'foo' # => "foo"
2447 * a # => ["foo", 2]
2449 * if <tt>range.begin</tt> is negative, counts backwards from the end of the array:
2451 * a = [:foo, 'bar', 2]
2452 * a[-2..2] = 'foo' # => "foo"
2453 * a # => [:foo, "foo"]
2455 * If the array length is less than <tt>range.begin</tt>,
2456 * extends the array with +nil+, assigns +object+ at offset <tt>range.begin</tt>,
2457 * and ignores +length+:
2459 * a = [:foo, 'bar', 2]
2460 * a[6..50] = 'foo' # => "foo"
2461 * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
2463 * If <tt>range.end</tt> is zero, shifts elements at and following offset +start+
2464 * and assigns +object+ at offset +start+:
2466 * a = [:foo, 'bar', 2]
2467 * a[1..0] = 'foo' # => "foo"
2468 * a # => [:foo, "foo", "bar", 2]
2470 * If <tt>range.end</tt> is negative, assigns +object+ at offset +start+,
2471 * retains <tt>range.end.abs -1</tt> elements past that, and removes those beyond:
2473 * a = [:foo, 'bar', 2]
2474 * a[1..-1] = 'foo' # => "foo"
2475 * a # => [:foo, "foo"]
2476 * a = [:foo, 'bar', 2]
2477 * a[1..-2] = 'foo' # => "foo"
2478 * a # => [:foo, "foo", 2]
2479 * a = [:foo, 'bar', 2]
2480 * a[1..-3] = 'foo' # => "foo"
2481 * a # => [:foo, "foo", "bar", 2]
2482 * a = [:foo, 'bar', 2]
2484 * If <tt>range.end</tt> is too large for the existing array,
2485 * replaces array elements, but does not extend the array with +nil+ values:
2487 * a = [:foo, 'bar', 2]
2488 * a[1..5] = 'foo' # => "foo"
2489 * a # => [:foo, "foo"]
2491 * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
2494 static VALUE
2495 rb_ary_aset(int argc, VALUE *argv, VALUE ary)
2497 long offset, beg, len;
2499 rb_check_arity(argc, 2, 3);
2500 rb_ary_modify_check(ary);
2501 if (argc == 3) {
2502 beg = NUM2LONG(argv[0]);
2503 len = NUM2LONG(argv[1]);
2504 return ary_aset_by_rb_ary_splice(ary, beg, len, argv[2]);
2506 if (FIXNUM_P(argv[0])) {
2507 offset = FIX2LONG(argv[0]);
2508 return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
2510 if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
2511 /* check if idx is Range */
2512 return ary_aset_by_rb_ary_splice(ary, beg, len, argv[1]);
2515 offset = NUM2LONG(argv[0]);
2516 return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
2520 * call-seq:
2521 * array.insert(index, *objects) -> self
2523 * Inserts given +objects+ before or after the element at Integer index +offset+;
2524 * returns +self+.
2526 * When +index+ is non-negative, inserts all given +objects+
2527 * before the element at offset +index+:
2529 * a = [:foo, 'bar', 2]
2530 * a.insert(1, :bat, :bam) # => [:foo, :bat, :bam, "bar", 2]
2532 * Extends the array if +index+ is beyond the array (<tt>index >= self.size</tt>):
2534 * a = [:foo, 'bar', 2]
2535 * a.insert(5, :bat, :bam)
2536 * a # => [:foo, "bar", 2, nil, nil, :bat, :bam]
2538 * Does nothing if no objects given:
2540 * a = [:foo, 'bar', 2]
2541 * a.insert(1)
2542 * a.insert(50)
2543 * a.insert(-50)
2544 * a # => [:foo, "bar", 2]
2546 * When +index+ is negative, inserts all given +objects+
2547 * _after_ the element at offset <tt>index+self.size</tt>:
2549 * a = [:foo, 'bar', 2]
2550 * a.insert(-2, :bat, :bam)
2551 * a # => [:foo, "bar", :bat, :bam, 2]
2555 static VALUE
2556 rb_ary_insert(int argc, VALUE *argv, VALUE ary)
2558 long pos;
2560 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
2561 rb_ary_modify_check(ary);
2562 pos = NUM2LONG(argv[0]);
2563 if (argc == 1) return ary;
2564 if (pos == -1) {
2565 pos = RARRAY_LEN(ary);
2567 else if (pos < 0) {
2568 long minpos = -RARRAY_LEN(ary) - 1;
2569 if (pos < minpos) {
2570 rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
2571 pos, minpos);
2573 pos++;
2575 rb_ary_splice(ary, pos, 0, argv + 1, argc - 1);
2576 return ary;
2579 static VALUE
2580 rb_ary_length(VALUE ary);
2582 static VALUE
2583 ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
2585 return rb_ary_length(ary);
2588 // Primitive to avoid a race condition in Array#each.
2589 // Return `true` and write `value` and `index` if the element exists.
2590 static VALUE
2591 ary_fetch_next(VALUE self, VALUE *index, VALUE *value)
2593 long i = NUM2LONG(*index);
2594 if (i >= RARRAY_LEN(self)) {
2595 return Qfalse;
2597 *value = RARRAY_AREF(self, i);
2598 *index = LONG2NUM(i + 1);
2599 return Qtrue;
2602 VALUE
2603 rb_ary_each(VALUE ary)
2605 long i;
2606 ary_verify(ary);
2607 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
2608 for (i=0; i<RARRAY_LEN(ary); i++) {
2609 rb_yield(RARRAY_AREF(ary, i));
2611 return ary;
2615 * call-seq:
2616 * array.each_index {|index| ... } -> self
2617 * array.each_index -> Enumerator
2619 * Iterates over array indexes.
2621 * When a block given, passes each successive array index to the block;
2622 * returns +self+:
2624 * a = [:foo, 'bar', 2]
2625 * a.each_index {|index| puts "#{index} #{a[index]}" }
2627 * Output:
2629 * 0 foo
2630 * 1 bar
2631 * 2 2
2633 * Allows the array to be modified during iteration:
2635 * a = [:foo, 'bar', 2]
2636 * a.each_index {|index| puts index; a.clear if index > 0 }
2638 * Output:
2643 * When no block given, returns a new Enumerator:
2645 * a = [:foo, 'bar', 2]
2646 * e = a.each_index
2647 * e # => #<Enumerator: [:foo, "bar", 2]:each_index>
2648 * a1 = e.each {|index| puts "#{index} #{a[index]}"}
2650 * Output:
2652 * 0 foo
2653 * 1 bar
2654 * 2 2
2656 * Related: #each, #reverse_each.
2659 static VALUE
2660 rb_ary_each_index(VALUE ary)
2662 long i;
2663 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
2665 for (i=0; i<RARRAY_LEN(ary); i++) {
2666 rb_yield(LONG2NUM(i));
2668 return ary;
2672 * call-seq:
2673 * array.reverse_each {|element| ... } -> self
2674 * array.reverse_each -> Enumerator
2676 * Iterates backwards over array elements.
2678 * When a block given, passes, in reverse order, each element to the block;
2679 * returns +self+:
2681 * a = [:foo, 'bar', 2]
2682 * a.reverse_each {|element| puts "#{element.class} #{element}" }
2684 * Output:
2686 * Integer 2
2687 * String bar
2688 * Symbol foo
2690 * Allows the array to be modified during iteration:
2692 * a = [:foo, 'bar', 2]
2693 * a.reverse_each {|element| puts element; a.clear if element.to_s.start_with?('b') }
2695 * Output:
2698 * bar
2700 * When no block given, returns a new Enumerator:
2702 * a = [:foo, 'bar', 2]
2703 * e = a.reverse_each
2704 * e # => #<Enumerator: [:foo, "bar", 2]:reverse_each>
2705 * a1 = e.each {|element| puts "#{element.class} #{element}" }
2707 * Output:
2709 * Integer 2
2710 * String bar
2711 * Symbol foo
2713 * Related: #each, #each_index.
2716 static VALUE
2717 rb_ary_reverse_each(VALUE ary)
2719 long len;
2721 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
2722 len = RARRAY_LEN(ary);
2723 while (len--) {
2724 long nlen;
2725 rb_yield(RARRAY_AREF(ary, len));
2726 nlen = RARRAY_LEN(ary);
2727 if (nlen < len) {
2728 len = nlen;
2731 return ary;
2735 * call-seq:
2736 * array.length -> an_integer
2738 * Returns the count of elements in +self+.
2741 static VALUE
2742 rb_ary_length(VALUE ary)
2744 long len = RARRAY_LEN(ary);
2745 return LONG2NUM(len);
2749 * call-seq:
2750 * array.empty? -> true or false
2752 * Returns +true+ if the count of elements in +self+ is zero,
2753 * +false+ otherwise.
2756 static VALUE
2757 rb_ary_empty_p(VALUE ary)
2759 return RBOOL(RARRAY_LEN(ary) == 0);
2762 VALUE
2763 rb_ary_dup(VALUE ary)
2765 long len = RARRAY_LEN(ary);
2766 VALUE dup = rb_ary_new2(len);
2767 ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary));
2768 ARY_SET_LEN(dup, len);
2770 ary_verify(ary);
2771 ary_verify(dup);
2772 return dup;
2775 VALUE
2776 rb_ary_resurrect(VALUE ary)
2778 return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary));
2781 extern VALUE rb_output_fs;
2783 static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first);
2785 static VALUE
2786 recursive_join(VALUE obj, VALUE argp, int recur)
2788 VALUE *arg = (VALUE *)argp;
2789 VALUE ary = arg[0];
2790 VALUE sep = arg[1];
2791 VALUE result = arg[2];
2792 int *first = (int *)arg[3];
2794 if (recur) {
2795 rb_raise(rb_eArgError, "recursive array join");
2797 else {
2798 ary_join_1(obj, ary, sep, 0, result, first);
2800 return Qnil;
2803 static long
2804 ary_join_0(VALUE ary, VALUE sep, long max, VALUE result)
2806 long i;
2807 VALUE val;
2809 if (max > 0) rb_enc_copy(result, RARRAY_AREF(ary, 0));
2810 for (i=0; i<max; i++) {
2811 val = RARRAY_AREF(ary, i);
2812 if (!RB_TYPE_P(val, T_STRING)) break;
2813 if (i > 0 && !NIL_P(sep))
2814 rb_str_buf_append(result, sep);
2815 rb_str_buf_append(result, val);
2817 return i;
2820 static void
2821 ary_join_1_str(VALUE dst, VALUE src, int *first)
2823 rb_str_buf_append(dst, src);
2824 if (*first) {
2825 rb_enc_copy(dst, src);
2826 *first = FALSE;
2830 static void
2831 ary_join_1_ary(VALUE obj, VALUE ary, VALUE sep, VALUE result, VALUE val, int *first)
2833 if (val == ary) {
2834 rb_raise(rb_eArgError, "recursive array join");
2836 else {
2837 VALUE args[4];
2839 *first = FALSE;
2840 args[0] = val;
2841 args[1] = sep;
2842 args[2] = result;
2843 args[3] = (VALUE)first;
2844 rb_exec_recursive(recursive_join, obj, (VALUE)args);
2848 static void
2849 ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first)
2851 VALUE val, tmp;
2853 for (; i<RARRAY_LEN(ary); i++) {
2854 if (i > 0 && !NIL_P(sep))
2855 rb_str_buf_append(result, sep);
2857 val = RARRAY_AREF(ary, i);
2858 if (RB_TYPE_P(val, T_STRING)) {
2859 ary_join_1_str(result, val, first);
2861 else if (RB_TYPE_P(val, T_ARRAY)) {
2862 ary_join_1_ary(val, ary, sep, result, val, first);
2864 else if (!NIL_P(tmp = rb_check_string_type(val))) {
2865 ary_join_1_str(result, tmp, first);
2867 else if (!NIL_P(tmp = rb_check_array_type(val))) {
2868 ary_join_1_ary(val, ary, sep, result, tmp, first);
2870 else {
2871 ary_join_1_str(result, rb_obj_as_string(val), first);
2876 VALUE
2877 rb_ary_join(VALUE ary, VALUE sep)
2879 long len = 1, i;
2880 VALUE val, tmp, result;
2882 if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0);
2884 if (!NIL_P(sep)) {
2885 StringValue(sep);
2886 len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
2888 for (i=0; i<RARRAY_LEN(ary); i++) {
2889 val = RARRAY_AREF(ary, i);
2890 tmp = rb_check_string_type(val);
2892 if (NIL_P(tmp) || tmp != val) {
2893 int first;
2894 long n = RARRAY_LEN(ary);
2895 if (i > n) i = n;
2896 result = rb_str_buf_new(len + (n-i)*10);
2897 rb_enc_associate(result, rb_usascii_encoding());
2898 i = ary_join_0(ary, sep, i, result);
2899 first = i == 0;
2900 ary_join_1(ary, ary, sep, i, result, &first);
2901 return result;
2904 len += RSTRING_LEN(tmp);
2907 result = rb_str_new(0, len);
2908 rb_str_set_len(result, 0);
2910 ary_join_0(ary, sep, RARRAY_LEN(ary), result);
2912 return result;
2916 * call-seq:
2917 * array.join ->new_string
2918 * array.join(separator = $,) -> new_string
2920 * Returns the new String formed by joining the array elements after conversion.
2921 * For each element +element+:
2923 * - Uses <tt>element.to_s</tt> if +element+ is not a <tt>kind_of?(Array)</tt>.
2924 * - Uses recursive <tt>element.join(separator)</tt> if +element+ is a <tt>kind_of?(Array)</tt>.
2926 * With no argument, joins using the output field separator, <tt>$,</tt>:
2928 * a = [:foo, 'bar', 2]
2929 * $, # => nil
2930 * a.join # => "foobar2"
2932 * With \string argument +separator+, joins using that separator:
2934 * a = [:foo, 'bar', 2]
2935 * a.join("\n") # => "foo\nbar\n2"
2937 * Joins recursively for nested Arrays:
2939 * a = [:foo, [:bar, [:baz, :bat]]]
2940 * a.join # => "foobarbazbat"
2943 static VALUE
2944 rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
2946 VALUE sep;
2948 if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) {
2949 sep = rb_output_fs;
2950 if (!NIL_P(sep)) {
2951 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
2955 return rb_ary_join(ary, sep);
2958 static VALUE
2959 inspect_ary(VALUE ary, VALUE dummy, int recur)
2961 long i;
2962 VALUE s, str;
2964 if (recur) return rb_usascii_str_new_cstr("[...]");
2965 str = rb_str_buf_new2("[");
2966 for (i=0; i<RARRAY_LEN(ary); i++) {
2967 s = rb_inspect(RARRAY_AREF(ary, i));
2968 if (i > 0) rb_str_buf_cat2(str, ", ");
2969 else rb_enc_copy(str, s);
2970 rb_str_buf_append(str, s);
2972 rb_str_buf_cat2(str, "]");
2973 return str;
2977 * call-seq:
2978 * array.inspect -> new_string
2980 * Returns the new String formed by calling method <tt>#inspect</tt>
2981 * on each array element:
2983 * a = [:foo, 'bar', 2]
2984 * a.inspect # => "[:foo, \"bar\", 2]"
2988 static VALUE
2989 rb_ary_inspect(VALUE ary)
2991 if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
2992 return rb_exec_recursive(inspect_ary, ary, 0);
2995 VALUE
2996 rb_ary_to_s(VALUE ary)
2998 return rb_ary_inspect(ary);
3002 * call-seq:
3003 * to_a -> self or new_array
3005 * When +self+ is an instance of +Array+, returns +self+:
3007 * a = [:foo, 'bar', 2]
3008 * a.to_a # => [:foo, "bar", 2]
3010 * Otherwise, returns a new +Array+ containing the elements of +self+:
3012 * class MyArray < Array; end
3013 * a = MyArray.new(['foo', 'bar', 'two'])
3014 * a.instance_of?(Array) # => false
3015 * a.kind_of?(Array) # => true
3016 * a1 = a.to_a
3017 * a1 # => ["foo", "bar", "two"]
3018 * a1.class # => Array # Not MyArray
3022 static VALUE
3023 rb_ary_to_a(VALUE ary)
3025 if (rb_obj_class(ary) != rb_cArray) {
3026 VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
3027 rb_ary_replace(dup, ary);
3028 return dup;
3030 return ary;
3034 * call-seq:
3035 * array.to_h -> new_hash
3036 * array.to_h {|item| ... } -> new_hash
3038 * Returns a new Hash formed from +self+.
3040 * When a block is given, calls the block with each array element;
3041 * the block must return a 2-element +Array+ whose two elements
3042 * form a key-value pair in the returned Hash:
3044 * a = ['foo', :bar, 1, [2, 3], {baz: 4}]
3045 * h = a.to_h {|item| [item, item] }
3046 * h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
3048 * When no block is given, +self+ must be an +Array+ of 2-element sub-arrays,
3049 * each sub-array is formed into a key-value pair in the new Hash:
3051 * [].to_h # => {}
3052 * a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
3053 * h = a.to_h
3054 * h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
3058 static VALUE
3059 rb_ary_to_h(VALUE ary)
3061 long i;
3062 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary));
3063 int block_given = rb_block_given_p();
3065 for (i=0; i<RARRAY_LEN(ary); i++) {
3066 const VALUE e = rb_ary_elt(ary, i);
3067 const VALUE elt = block_given ? rb_yield_force_blockarg(e) : e;
3068 const VALUE key_value_pair = rb_check_array_type(elt);
3069 if (NIL_P(key_value_pair)) {
3070 rb_raise(rb_eTypeError, "wrong element type %"PRIsVALUE" at %ld (expected array)",
3071 rb_obj_class(elt), i);
3073 if (RARRAY_LEN(key_value_pair) != 2) {
3074 rb_raise(rb_eArgError, "wrong array length at %ld (expected 2, was %ld)",
3075 i, RARRAY_LEN(key_value_pair));
3077 rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1));
3079 return hash;
3083 * call-seq:
3084 * array.to_ary -> self
3086 * Returns +self+.
3089 static VALUE
3090 rb_ary_to_ary_m(VALUE ary)
3092 return ary;
3095 static void
3096 ary_reverse(VALUE *p1, VALUE *p2)
3098 while (p1 < p2) {
3099 VALUE tmp = *p1;
3100 *p1++ = *p2;
3101 *p2-- = tmp;
3105 VALUE
3106 rb_ary_reverse(VALUE ary)
3108 VALUE *p2;
3109 long len = RARRAY_LEN(ary);
3111 rb_ary_modify(ary);
3112 if (len > 1) {
3113 RARRAY_PTR_USE(ary, p1, {
3114 p2 = p1 + len - 1; /* points last item */
3115 ary_reverse(p1, p2);
3116 }); /* WB: no new reference */
3118 return ary;
3122 * call-seq:
3123 * array.reverse! -> self
3125 * Reverses +self+ in place:
3127 * a = ['foo', 'bar', 'two']
3128 * a.reverse! # => ["two", "bar", "foo"]
3132 static VALUE
3133 rb_ary_reverse_bang(VALUE ary)
3135 return rb_ary_reverse(ary);
3139 * call-seq:
3140 * array.reverse -> new_array
3142 * Returns a new +Array+ with the elements of +self+ in reverse order:
3144 * a = ['foo', 'bar', 'two']
3145 * a1 = a.reverse
3146 * a1 # => ["two", "bar", "foo"]
3150 static VALUE
3151 rb_ary_reverse_m(VALUE ary)
3153 long len = RARRAY_LEN(ary);
3154 VALUE dup = rb_ary_new2(len);
3156 if (len > 0) {
3157 const VALUE *p1 = RARRAY_CONST_PTR(ary);
3158 VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1;
3159 do *p2-- = *p1++; while (--len > 0);
3161 ARY_SET_LEN(dup, RARRAY_LEN(ary));
3162 return dup;
3165 static inline long
3166 rotate_count(long cnt, long len)
3168 return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len);
3171 static void
3172 ary_rotate_ptr(VALUE *ptr, long len, long cnt)
3174 if (cnt == 1) {
3175 VALUE tmp = *ptr;
3176 memmove(ptr, ptr + 1, sizeof(VALUE)*(len - 1));
3177 *(ptr + len - 1) = tmp;
3179 else if (cnt == len - 1) {
3180 VALUE tmp = *(ptr + len - 1);
3181 memmove(ptr + 1, ptr, sizeof(VALUE)*(len - 1));
3182 *ptr = tmp;
3184 else {
3185 --len;
3186 if (cnt < len) ary_reverse(ptr + cnt, ptr + len);
3187 if (--cnt > 0) ary_reverse(ptr, ptr + cnt);
3188 if (len > 0) ary_reverse(ptr, ptr + len);
3192 VALUE
3193 rb_ary_rotate(VALUE ary, long cnt)
3195 rb_ary_modify(ary);
3197 if (cnt != 0) {
3198 long len = RARRAY_LEN(ary);
3199 if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) {
3200 RARRAY_PTR_USE(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
3201 return ary;
3204 return Qnil;
3208 * call-seq:
3209 * array.rotate! -> self
3210 * array.rotate!(count) -> self
3212 * Rotates +self+ in place by moving elements from one end to the other; returns +self+.
3214 * When no argument given, rotates the first element to the last position:
3216 * a = [:foo, 'bar', 2, 'bar']
3217 * a.rotate! # => ["bar", 2, "bar", :foo]
3219 * When given a non-negative Integer +count+,
3220 * rotates +count+ elements from the beginning to the end:
3222 * a = [:foo, 'bar', 2]
3223 * a.rotate!(2)
3224 * a # => [2, :foo, "bar"]
3226 * If +count+ is large, uses <tt>count % array.size</tt> as the count:
3228 * a = [:foo, 'bar', 2]
3229 * a.rotate!(20)
3230 * a # => [2, :foo, "bar"]
3232 * If +count+ is zero, returns +self+ unmodified:
3234 * a = [:foo, 'bar', 2]
3235 * a.rotate!(0)
3236 * a # => [:foo, "bar", 2]
3238 * When given a negative Integer +count+, rotates in the opposite direction,
3239 * from end to beginning:
3241 * a = [:foo, 'bar', 2]
3242 * a.rotate!(-2)
3243 * a # => ["bar", 2, :foo]
3245 * If +count+ is small (far from zero), uses <tt>count % array.size</tt> as the count:
3247 * a = [:foo, 'bar', 2]
3248 * a.rotate!(-5)
3249 * a # => ["bar", 2, :foo]
3253 static VALUE
3254 rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
3256 long n = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
3257 rb_ary_rotate(ary, n);
3258 return ary;
3262 * call-seq:
3263 * array.rotate -> new_array
3264 * array.rotate(count) -> new_array
3266 * Returns a new +Array+ formed from +self+ with elements
3267 * rotated from one end to the other.
3269 * When no argument given, returns a new +Array+ that is like +self+,
3270 * except that the first element has been rotated to the last position:
3272 * a = [:foo, 'bar', 2, 'bar']
3273 * a1 = a.rotate
3274 * a1 # => ["bar", 2, "bar", :foo]
3276 * When given a non-negative Integer +count+,
3277 * returns a new +Array+ with +count+ elements rotated from the beginning to the end:
3279 * a = [:foo, 'bar', 2]
3280 * a1 = a.rotate(2)
3281 * a1 # => [2, :foo, "bar"]
3283 * If +count+ is large, uses <tt>count % array.size</tt> as the count:
3285 * a = [:foo, 'bar', 2]
3286 * a1 = a.rotate(20)
3287 * a1 # => [2, :foo, "bar"]
3289 * If +count+ is zero, returns a copy of +self+, unmodified:
3291 * a = [:foo, 'bar', 2]
3292 * a1 = a.rotate(0)
3293 * a1 # => [:foo, "bar", 2]
3295 * When given a negative Integer +count+, rotates in the opposite direction,
3296 * from end to beginning:
3298 * a = [:foo, 'bar', 2]
3299 * a1 = a.rotate(-2)
3300 * a1 # => ["bar", 2, :foo]
3302 * If +count+ is small (far from zero), uses <tt>count % array.size</tt> as the count:
3304 * a = [:foo, 'bar', 2]
3305 * a1 = a.rotate(-5)
3306 * a1 # => ["bar", 2, :foo]
3310 static VALUE
3311 rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
3313 VALUE rotated;
3314 const VALUE *ptr;
3315 long len;
3316 long cnt = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
3318 len = RARRAY_LEN(ary);
3319 rotated = rb_ary_new2(len);
3320 if (len > 0) {
3321 cnt = rotate_count(cnt, len);
3322 ptr = RARRAY_CONST_PTR(ary);
3323 len -= cnt;
3324 ary_memcpy(rotated, 0, len, ptr + cnt);
3325 ary_memcpy(rotated, len, cnt, ptr);
3327 ARY_SET_LEN(rotated, RARRAY_LEN(ary));
3328 return rotated;
3331 struct ary_sort_data {
3332 VALUE ary;
3333 VALUE receiver;
3336 static VALUE
3337 sort_reentered(VALUE ary)
3339 if (RBASIC(ary)->klass) {
3340 rb_raise(rb_eRuntimeError, "sort reentered");
3342 return Qnil;
3345 static void
3346 sort_returned(struct ary_sort_data *data)
3348 if (rb_obj_frozen_p(data->receiver)) {
3349 rb_raise(rb_eFrozenError, "array frozen during sort");
3351 sort_reentered(data->ary);
3354 static int
3355 sort_1(const void *ap, const void *bp, void *dummy)
3357 struct ary_sort_data *data = dummy;
3358 VALUE retval = sort_reentered(data->ary);
3359 VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
3360 VALUE args[2];
3361 int n;
3363 args[0] = a;
3364 args[1] = b;
3365 retval = rb_yield_values2(2, args);
3366 n = rb_cmpint(retval, a, b);
3367 sort_returned(data);
3368 return n;
3371 static int
3372 sort_2(const void *ap, const void *bp, void *dummy)
3374 struct ary_sort_data *data = dummy;
3375 VALUE retval = sort_reentered(data->ary);
3376 VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
3377 int n;
3379 if (FIXNUM_P(a) && FIXNUM_P(b) && CMP_OPTIMIZABLE(INTEGER)) {
3380 if ((long)a > (long)b) return 1;
3381 if ((long)a < (long)b) return -1;
3382 return 0;
3384 if (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(STRING)) {
3385 return rb_str_cmp(a, b);
3387 if (RB_FLOAT_TYPE_P(a) && CMP_OPTIMIZABLE(FLOAT)) {
3388 return rb_float_cmp(a, b);
3391 retval = rb_funcallv(a, id_cmp, 1, &b);
3392 n = rb_cmpint(retval, a, b);
3393 sort_returned(data);
3395 return n;
3399 * call-seq:
3400 * array.sort! -> self
3401 * array.sort! {|a, b| ... } -> self
3403 * Returns +self+ with its elements sorted in place.
3405 * With no block, compares elements using operator <tt><=></tt>
3406 * (see Comparable):
3408 * a = 'abcde'.split('').shuffle
3409 * a # => ["e", "b", "d", "a", "c"]
3410 * a.sort!
3411 * a # => ["a", "b", "c", "d", "e"]
3413 * With a block, calls the block with each element pair;
3414 * for each element pair +a+ and +b+, the block should return an integer:
3416 * - Negative when +b+ is to follow +a+.
3417 * - Zero when +a+ and +b+ are equivalent.
3418 * - Positive when +a+ is to follow +b+.
3420 * Example:
3422 * a = 'abcde'.split('').shuffle
3423 * a # => ["e", "b", "d", "a", "c"]
3424 * a.sort! {|a, b| a <=> b }
3425 * a # => ["a", "b", "c", "d", "e"]
3426 * a.sort! {|a, b| b <=> a }
3427 * a # => ["e", "d", "c", "b", "a"]
3429 * When the block returns zero, the order for +a+ and +b+ is indeterminate,
3430 * and may be unstable:
3432 * a = 'abcde'.split('').shuffle
3433 * a # => ["e", "b", "d", "a", "c"]
3434 * a.sort! {|a, b| 0 }
3435 * a # => ["d", "e", "c", "a", "b"]
3439 VALUE
3440 rb_ary_sort_bang(VALUE ary)
3442 rb_ary_modify(ary);
3443 RUBY_ASSERT(!ARY_SHARED_P(ary));
3444 if (RARRAY_LEN(ary) > 1) {
3445 VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
3446 struct ary_sort_data data;
3447 long len = RARRAY_LEN(ary);
3448 RBASIC_CLEAR_CLASS(tmp);
3449 data.ary = tmp;
3450 data.receiver = ary;
3451 RARRAY_PTR_USE(tmp, ptr, {
3452 ruby_qsort(ptr, len, sizeof(VALUE),
3453 rb_block_given_p()?sort_1:sort_2, &data);
3454 }); /* WB: no new reference */
3455 rb_ary_modify(ary);
3456 if (ARY_EMBED_P(tmp)) {
3457 if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
3458 rb_ary_unshare(ary);
3459 FL_SET_EMBED(ary);
3461 if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) {
3462 ary_resize_capa(ary, ARY_EMBED_LEN(tmp));
3464 ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
3465 ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
3467 else {
3468 if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
3469 FL_UNSET_SHARED(ary);
3470 ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
3472 else {
3473 RUBY_ASSERT(!ARY_SHARED_P(tmp));
3474 if (ARY_EMBED_P(ary)) {
3475 FL_UNSET_EMBED(ary);
3477 else if (ARY_SHARED_P(ary)) {
3478 /* ary might be destructively operated in the given block */
3479 rb_ary_unshare(ary);
3481 else {
3482 ary_heap_free(ary);
3484 ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp));
3485 ARY_SET_HEAP_LEN(ary, len);
3486 ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
3488 /* tmp was lost ownership for the ptr */
3489 FL_UNSET(tmp, FL_FREEZE);
3490 FL_SET_EMBED(tmp);
3491 ARY_SET_EMBED_LEN(tmp, 0);
3492 FL_SET(tmp, FL_FREEZE);
3494 /* tmp will be GC'ed. */
3495 RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
3497 ary_verify(ary);
3498 return ary;
3502 * call-seq:
3503 * array.sort -> new_array
3504 * array.sort {|a, b| ... } -> new_array
3506 * Returns a new +Array+ whose elements are those from +self+, sorted.
3508 * With no block, compares elements using operator <tt><=></tt>
3509 * (see Comparable):
3511 * a = 'abcde'.split('').shuffle
3512 * a # => ["e", "b", "d", "a", "c"]
3513 * a1 = a.sort
3514 * a1 # => ["a", "b", "c", "d", "e"]
3516 * With a block, calls the block with each element pair;
3517 * for each element pair +a+ and +b+, the block should return an integer:
3519 * - Negative when +b+ is to follow +a+.
3520 * - Zero when +a+ and +b+ are equivalent.
3521 * - Positive when +a+ is to follow +b+.
3523 * Example:
3525 * a = 'abcde'.split('').shuffle
3526 * a # => ["e", "b", "d", "a", "c"]
3527 * a1 = a.sort {|a, b| a <=> b }
3528 * a1 # => ["a", "b", "c", "d", "e"]
3529 * a2 = a.sort {|a, b| b <=> a }
3530 * a2 # => ["e", "d", "c", "b", "a"]
3532 * When the block returns zero, the order for +a+ and +b+ is indeterminate,
3533 * and may be unstable:
3535 * a = 'abcde'.split('').shuffle
3536 * a # => ["e", "b", "d", "a", "c"]
3537 * a1 = a.sort {|a, b| 0 }
3538 * a1 # => ["c", "e", "b", "d", "a"]
3540 * Related: Enumerable#sort_by.
3543 VALUE
3544 rb_ary_sort(VALUE ary)
3546 ary = rb_ary_dup(ary);
3547 rb_ary_sort_bang(ary);
3548 return ary;
3551 static VALUE rb_ary_bsearch_index(VALUE ary);
3554 * call-seq:
3555 * bsearch {|element| ... } -> found_element or nil
3556 * bsearch -> new_enumerator
3558 * Returns the element from +self+ found by a binary search,
3559 * or +nil+ if the search found no suitable element.
3561 * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
3563 * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
3566 static VALUE
3567 rb_ary_bsearch(VALUE ary)
3569 VALUE index_result = rb_ary_bsearch_index(ary);
3571 if (FIXNUM_P(index_result)) {
3572 return rb_ary_entry(ary, FIX2LONG(index_result));
3574 return index_result;
3578 * call-seq:
3579 * bsearch_index {|element| ... } -> integer or nil
3580 * bsearch_index -> new_enumerator
3582 * Returns the integer index of the element from +self+ found by a binary search,
3583 * or +nil+ if the search found no suitable element.
3585 * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
3587 * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
3590 static VALUE
3591 rb_ary_bsearch_index(VALUE ary)
3593 long low = 0, high = RARRAY_LEN(ary), mid;
3594 int smaller = 0, satisfied = 0;
3595 VALUE v, val;
3597 RETURN_ENUMERATOR(ary, 0, 0);
3598 while (low < high) {
3599 mid = low + ((high - low) / 2);
3600 val = rb_ary_entry(ary, mid);
3601 v = rb_yield(val);
3602 if (FIXNUM_P(v)) {
3603 if (v == INT2FIX(0)) return INT2FIX(mid);
3604 smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */
3606 else if (v == Qtrue) {
3607 satisfied = 1;
3608 smaller = 1;
3610 else if (!RTEST(v)) {
3611 smaller = 0;
3613 else if (rb_obj_is_kind_of(v, rb_cNumeric)) {
3614 const VALUE zero = INT2FIX(0);
3615 switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) {
3616 case 0: return INT2FIX(mid);
3617 case 1: smaller = 0; break;
3618 case -1: smaller = 1;
3621 else {
3622 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE
3623 " (must be numeric, true, false or nil)",
3624 rb_obj_class(v));
3626 if (smaller) {
3627 high = mid;
3629 else {
3630 low = mid + 1;
3633 if (!satisfied) return Qnil;
3634 return INT2FIX(low);
3638 static VALUE
3639 sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy))
3641 return rb_yield(i);
3645 * call-seq:
3646 * array.sort_by! {|element| ... } -> self
3647 * array.sort_by! -> new_enumerator
3649 * Sorts the elements of +self+ in place,
3650 * using an ordering determined by the block; returns self.
3652 * Calls the block with each successive element;
3653 * sorts elements based on the values returned from the block.
3655 * For duplicates returned by the block, the ordering is indeterminate, and may be unstable.
3657 * This example sorts strings based on their sizes:
3659 * a = ['aaaa', 'bbb', 'cc', 'd']
3660 * a.sort_by! {|element| element.size }
3661 * a # => ["d", "cc", "bbb", "aaaa"]
3663 * Returns a new Enumerator if no block given:
3665 * a = ['aaaa', 'bbb', 'cc', 'd']
3666 * a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
3670 static VALUE
3671 rb_ary_sort_by_bang(VALUE ary)
3673 VALUE sorted;
3675 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3676 rb_ary_modify(ary);
3677 sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0);
3678 rb_ary_replace(ary, sorted);
3679 return ary;
3684 * call-seq:
3685 * collect {|element| ... } -> new_array
3686 * collect -> new_enumerator
3687 * map {|element| ... } -> new_array
3688 * map -> new_enumerator
3690 * With a block given, calls the block with each element of +self+;
3691 * returns a new array whose elements are the return values from the block:
3693 * a = [:foo, 'bar', 2]
3694 * a1 = a.map {|element| element.class }
3695 * a1 # => [Symbol, String, Integer]
3697 * With no block given, returns a new Enumerator.
3699 * Related: #collect!;
3700 * see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
3703 static VALUE
3704 rb_ary_collect(VALUE ary)
3706 long i;
3707 VALUE collect;
3709 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3710 collect = rb_ary_new2(RARRAY_LEN(ary));
3711 for (i = 0; i < RARRAY_LEN(ary); i++) {
3712 rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
3714 return collect;
3719 * call-seq:
3720 * collect! {|element| ... } -> new_array
3721 * collect! -> new_enumerator
3722 * map! {|element| ... } -> new_array
3723 * map! -> new_enumerator
3725 * With a block given, calls the block with each element of +self+
3726 * and replaces the element with the block's return value;
3727 * returns +self+:
3729 * a = [:foo, 'bar', 2]
3730 * a.map! { |element| element.class } # => [Symbol, String, Integer]
3732 * With no block given, returns a new Enumerator.
3734 * Related: #collect;
3735 * see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
3738 static VALUE
3739 rb_ary_collect_bang(VALUE ary)
3741 long i;
3743 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3744 rb_ary_modify(ary);
3745 for (i = 0; i < RARRAY_LEN(ary); i++) {
3746 rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
3748 return ary;
3751 VALUE
3752 rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func) (VALUE, long))
3754 VALUE result = rb_ary_new2(argc);
3755 long beg, len, i, j;
3757 for (i=0; i<argc; i++) {
3758 if (FIXNUM_P(argv[i])) {
3759 rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
3760 continue;
3762 /* check if idx is Range */
3763 if (rb_range_beg_len(argv[i], &beg, &len, olen, 1)) {
3764 long end = olen < beg+len ? olen : beg+len;
3765 for (j = beg; j < end; j++) {
3766 rb_ary_push(result, (*func)(obj, j));
3768 if (beg + len > j)
3769 rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j);
3770 continue;
3772 rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
3774 return result;
3777 static VALUE
3778 append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
3780 long beg, len;
3781 if (FIXNUM_P(idx)) {
3782 beg = FIX2LONG(idx);
3784 /* check if idx is Range */
3785 else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) {
3786 if (len > 0) {
3787 const VALUE *const src = RARRAY_CONST_PTR(ary);
3788 const long end = beg + len;
3789 const long prevlen = RARRAY_LEN(result);
3790 if (beg < olen) {
3791 rb_ary_cat(result, src + beg, end > olen ? olen-beg : len);
3793 if (end > olen) {
3794 rb_ary_store(result, prevlen + len - 1, Qnil);
3797 return result;
3799 else {
3800 beg = NUM2LONG(idx);
3802 return rb_ary_push(result, rb_ary_entry(ary, beg));
3806 * call-seq:
3807 * array.values_at(*indexes) -> new_array
3809 * Returns a new +Array+ whose elements are the elements
3810 * of +self+ at the given Integer or Range +indexes+.
3812 * For each positive +index+, returns the element at offset +index+:
3814 * a = [:foo, 'bar', 2]
3815 * a.values_at(0, 2) # => [:foo, 2]
3816 * a.values_at(0..1) # => [:foo, "bar"]
3818 * The given +indexes+ may be in any order, and may repeat:
3820 * a = [:foo, 'bar', 2]
3821 * a.values_at(2, 0, 1, 0, 2) # => [2, :foo, "bar", :foo, 2]
3822 * a.values_at(1, 0..2) # => ["bar", :foo, "bar", 2]
3824 * Assigns +nil+ for an +index+ that is too large:
3826 * a = [:foo, 'bar', 2]
3827 * a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil]
3829 * Returns a new empty +Array+ if no arguments given.
3831 * For each negative +index+, counts backward from the end of the array:
3833 * a = [:foo, 'bar', 2]
3834 * a.values_at(-1, -3) # => [2, :foo]
3836 * Assigns +nil+ for an +index+ that is too small:
3838 * a = [:foo, 'bar', 2]
3839 * a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2]
3841 * The given +indexes+ may have a mixture of signs:
3843 * a = [:foo, 'bar', 2]
3844 * a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2]
3848 static VALUE
3849 rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
3851 long i, olen = RARRAY_LEN(ary);
3852 VALUE result = rb_ary_new_capa(argc);
3853 for (i = 0; i < argc; ++i) {
3854 append_values_at_single(result, ary, olen, argv[i]);
3856 RB_GC_GUARD(ary);
3857 return result;
3862 * call-seq:
3863 * array.select {|element| ... } -> new_array
3864 * array.select -> new_enumerator
3866 * Calls the block, if given, with each element of +self+;
3867 * returns a new +Array+ containing those elements of +self+
3868 * for which the block returns a truthy value:
3870 * a = [:foo, 'bar', 2, :bam]
3871 * a1 = a.select {|element| element.to_s.start_with?('b') }
3872 * a1 # => ["bar", :bam]
3874 * Returns a new Enumerator if no block given:
3876 * a = [:foo, 'bar', 2, :bam]
3877 * a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
3881 static VALUE
3882 rb_ary_select(VALUE ary)
3884 VALUE result;
3885 long i;
3887 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3888 result = rb_ary_new2(RARRAY_LEN(ary));
3889 for (i = 0; i < RARRAY_LEN(ary); i++) {
3890 if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
3891 rb_ary_push(result, rb_ary_elt(ary, i));
3894 return result;
3897 struct select_bang_arg {
3898 VALUE ary;
3899 long len[2];
3902 static VALUE
3903 select_bang_i(VALUE a)
3905 volatile struct select_bang_arg *arg = (void *)a;
3906 VALUE ary = arg->ary;
3907 long i1, i2;
3909 for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) {
3910 VALUE v = RARRAY_AREF(ary, i1);
3911 if (!RTEST(rb_yield(v))) continue;
3912 if (i1 != i2) {
3913 rb_ary_store(ary, i2, v);
3915 arg->len[1] = ++i2;
3917 return (i1 == i2) ? Qnil : ary;
3920 static VALUE
3921 select_bang_ensure(VALUE a)
3923 volatile struct select_bang_arg *arg = (void *)a;
3924 VALUE ary = arg->ary;
3925 long len = RARRAY_LEN(ary);
3926 long i1 = arg->len[0], i2 = arg->len[1];
3928 if (i2 < len && i2 < i1) {
3929 long tail = 0;
3930 rb_ary_modify(ary);
3931 if (i1 < len) {
3932 tail = len - i1;
3933 RARRAY_PTR_USE(ary, ptr, {
3934 MEMMOVE(ptr + i2, ptr + i1, VALUE, tail);
3937 ARY_SET_LEN(ary, i2 + tail);
3939 return ary;
3943 * call-seq:
3944 * array.select! {|element| ... } -> self or nil
3945 * array.select! -> new_enumerator
3947 * Calls the block, if given with each element of +self+;
3948 * removes from +self+ those elements for which the block returns +false+ or +nil+.
3950 * Returns +self+ if any elements were removed:
3952 * a = [:foo, 'bar', 2, :bam]
3953 * a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
3955 * Returns +nil+ if no elements were removed.
3957 * Returns a new Enumerator if no block given:
3959 * a = [:foo, 'bar', 2, :bam]
3960 * a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
3964 static VALUE
3965 rb_ary_select_bang(VALUE ary)
3967 struct select_bang_arg args;
3969 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3970 rb_ary_modify(ary);
3972 args.ary = ary;
3973 args.len[0] = args.len[1] = 0;
3974 return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
3978 * call-seq:
3979 * array.keep_if {|element| ... } -> self
3980 * array.keep_if -> new_enumeration
3982 * Retains those elements for which the block returns a truthy value;
3983 * deletes all other elements; returns +self+:
3985 * a = [:foo, 'bar', 2, :bam]
3986 * a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
3988 * Returns a new Enumerator if no block given:
3990 * a = [:foo, 'bar', 2, :bam]
3991 * a.keep_if # => #<Enumerator: [:foo, "bar", 2, :bam]:keep_if>
3995 static VALUE
3996 rb_ary_keep_if(VALUE ary)
3998 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
3999 rb_ary_select_bang(ary);
4000 return ary;
4003 static void
4004 ary_resize_smaller(VALUE ary, long len)
4006 rb_ary_modify(ary);
4007 if (RARRAY_LEN(ary) > len) {
4008 ARY_SET_LEN(ary, len);
4009 if (len * 2 < ARY_CAPA(ary) &&
4010 ARY_CAPA(ary) > ARY_DEFAULT_SIZE) {
4011 ary_resize_capa(ary, len * 2);
4017 * call-seq:
4018 * delete(object) -> last_removed_object
4019 * delete(object) {|element| ... } -> last_removed_object or block_return
4021 * Removes zero or more elements from +self+.
4023 * With no block given,
4024 * removes from +self+ each element +ele+ such that <tt>ele == object</tt>;
4025 * returns the last removed element:
4027 * a = [0, 1, 2, 2.0]
4028 * a.delete(2) # => 2.0
4029 * a # => [0, 1]
4031 * Returns +nil+ if no elements removed:
4033 * a.delete(2) # => nil
4035 * With a block given,
4036 * removes from +self+ each element +ele+ such that <tt>ele == object</tt>.
4038 * If any such elements are found, ignores the block
4039 * and returns the last removed element:
4041 * a = [0, 1, 2, 2.0]
4042 * a.delete(2) {|element| fail 'Cannot happen' } # => 2.0
4043 * a # => [0, 1]
4045 * If no such element is found, returns the block's return value:
4047 * a.delete(2) {|element| "Element #{element} not found." }
4048 * # => "Element 2 not found."
4050 * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
4053 VALUE
4054 rb_ary_delete(VALUE ary, VALUE item)
4056 VALUE v = item;
4057 long i1, i2;
4059 for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
4060 VALUE e = RARRAY_AREF(ary, i1);
4062 if (rb_equal(e, item)) {
4063 v = e;
4064 continue;
4066 if (i1 != i2) {
4067 rb_ary_store(ary, i2, e);
4069 i2++;
4071 if (RARRAY_LEN(ary) == i2) {
4072 if (rb_block_given_p()) {
4073 return rb_yield(item);
4075 return Qnil;
4078 ary_resize_smaller(ary, i2);
4080 ary_verify(ary);
4081 return v;
4084 void
4085 rb_ary_delete_same(VALUE ary, VALUE item)
4087 long i1, i2;
4089 for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
4090 VALUE e = RARRAY_AREF(ary, i1);
4092 if (e == item) {
4093 continue;
4095 if (i1 != i2) {
4096 rb_ary_store(ary, i2, e);
4098 i2++;
4100 if (RARRAY_LEN(ary) == i2) {
4101 return;
4104 ary_resize_smaller(ary, i2);
4107 VALUE
4108 rb_ary_delete_at(VALUE ary, long pos)
4110 long len = RARRAY_LEN(ary);
4111 VALUE del;
4113 if (pos >= len) return Qnil;
4114 if (pos < 0) {
4115 pos += len;
4116 if (pos < 0) return Qnil;
4119 rb_ary_modify(ary);
4120 del = RARRAY_AREF(ary, pos);
4121 RARRAY_PTR_USE(ary, ptr, {
4122 MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1);
4124 ARY_INCREASE_LEN(ary, -1);
4125 ary_verify(ary);
4126 return del;
4130 * call-seq:
4131 * delete_at(index) -> removed_object or nil
4133 * Removes the element of +self+ at the given +index+, which must be an
4134 * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
4136 * When +index+ is non-negative, deletes the element at offset +index+:
4138 * a = [:foo, 'bar', 2]
4139 * a.delete_at(1) # => "bar"
4140 * a # => [:foo, 2]
4142 * When +index+ is negative, counts backward from the end of the array:
4144 * a = [:foo, 'bar', 2]
4145 * a.delete_at(-2) # => "bar"
4146 * a # => [:foo, 2]
4148 * When +index+ is out of range, returns +nil+.
4150 * a = [:foo, 'bar', 2]
4151 * a.delete_at(3) # => nil
4152 * a.delete_at(-4) # => nil
4154 * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
4157 static VALUE
4158 rb_ary_delete_at_m(VALUE ary, VALUE pos)
4160 return rb_ary_delete_at(ary, NUM2LONG(pos));
4163 static VALUE
4164 ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
4166 const long orig_len = RARRAY_LEN(ary);
4168 if (len < 0) {
4169 return Qnil;
4171 else if (pos < -orig_len) {
4172 return Qnil;
4174 else if (pos < 0) {
4175 pos += orig_len;
4177 else if (orig_len < pos) {
4178 return Qnil;
4180 if (orig_len < pos + len) {
4181 len = orig_len - pos;
4183 if (len == 0) {
4184 return rb_ary_new2(0);
4186 else {
4187 VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR(ary)+pos);
4188 rb_ary_splice(ary, pos, len, 0, 0);
4189 return arg2;
4194 * call-seq:
4195 * array.slice!(n) -> object or nil
4196 * array.slice!(start, length) -> new_array or nil
4197 * array.slice!(range) -> new_array or nil
4199 * Removes and returns elements from +self+.
4201 * When the only argument is an Integer +n+,
4202 * removes and returns the _nth_ element in +self+:
4204 * a = [:foo, 'bar', 2]
4205 * a.slice!(1) # => "bar"
4206 * a # => [:foo, 2]
4208 * If +n+ is negative, counts backwards from the end of +self+:
4210 * a = [:foo, 'bar', 2]
4211 * a.slice!(-1) # => 2
4212 * a # => [:foo, "bar"]
4214 * If +n+ is out of range, returns +nil+.
4216 * When the only arguments are Integers +start+ and +length+,
4217 * removes +length+ elements from +self+ beginning at offset +start+;
4218 * returns the deleted objects in a new +Array+:
4220 * a = [:foo, 'bar', 2]
4221 * a.slice!(0, 2) # => [:foo, "bar"]
4222 * a # => [2]
4224 * If <tt>start + length</tt> exceeds the array size,
4225 * removes and returns all elements from offset +start+ to the end:
4227 * a = [:foo, 'bar', 2]
4228 * a.slice!(1, 50) # => ["bar", 2]
4229 * a # => [:foo]
4231 * If <tt>start == a.size</tt> and +length+ is non-negative,
4232 * returns a new empty +Array+.
4234 * If +length+ is negative, returns +nil+.
4236 * When the only argument is a Range object +range+,
4237 * treats <tt>range.min</tt> as +start+ above and <tt>range.size</tt> as +length+ above:
4239 * a = [:foo, 'bar', 2]
4240 * a.slice!(1..2) # => ["bar", 2]
4241 * a # => [:foo]
4243 * If <tt>range.start == a.size</tt>, returns a new empty +Array+.
4245 * If <tt>range.start</tt> is larger than the array size, returns +nil+.
4247 * If <tt>range.end</tt> is negative, counts backwards from the end of the array:
4249 * a = [:foo, 'bar', 2]
4250 * a.slice!(0..-2) # => [:foo, "bar"]
4251 * a # => [2]
4253 * If <tt>range.start</tt> is negative,
4254 * calculates the start index backwards from the end of the array:
4256 * a = [:foo, 'bar', 2]
4257 * a.slice!(-2..2) # => ["bar", 2]
4258 * a # => [:foo]
4262 static VALUE
4263 rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
4265 VALUE arg1;
4266 long pos, len;
4268 rb_ary_modify_check(ary);
4269 rb_check_arity(argc, 1, 2);
4270 arg1 = argv[0];
4272 if (argc == 2) {
4273 pos = NUM2LONG(argv[0]);
4274 len = NUM2LONG(argv[1]);
4275 return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
4278 if (!FIXNUM_P(arg1)) {
4279 switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
4280 case Qtrue:
4281 /* valid range */
4282 return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
4283 case Qnil:
4284 /* invalid range */
4285 return Qnil;
4286 default:
4287 /* not a range */
4288 break;
4292 return rb_ary_delete_at(ary, NUM2LONG(arg1));
4295 static VALUE
4296 ary_reject(VALUE orig, VALUE result)
4298 long i;
4300 for (i = 0; i < RARRAY_LEN(orig); i++) {
4301 VALUE v = RARRAY_AREF(orig, i);
4303 if (!RTEST(rb_yield(v))) {
4304 rb_ary_push(result, v);
4307 return result;
4310 static VALUE
4311 reject_bang_i(VALUE a)
4313 volatile struct select_bang_arg *arg = (void *)a;
4314 VALUE ary = arg->ary;
4315 long i1, i2;
4317 for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) {
4318 VALUE v = RARRAY_AREF(ary, i1);
4319 if (RTEST(rb_yield(v))) continue;
4320 if (i1 != i2) {
4321 rb_ary_store(ary, i2, v);
4323 arg->len[1] = ++i2;
4325 return (i1 == i2) ? Qnil : ary;
4328 static VALUE
4329 ary_reject_bang(VALUE ary)
4331 struct select_bang_arg args;
4332 rb_ary_modify_check(ary);
4333 args.ary = ary;
4334 args.len[0] = args.len[1] = 0;
4335 return rb_ensure(reject_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
4339 * call-seq:
4340 * array.reject! {|element| ... } -> self or nil
4341 * array.reject! -> new_enumerator
4343 * Removes each element for which the block returns a truthy value.
4345 * Returns +self+ if any elements removed:
4347 * a = [:foo, 'bar', 2, 'bat']
4348 * a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
4350 * Returns +nil+ if no elements removed.
4352 * Returns a new Enumerator if no block given:
4354 * a = [:foo, 'bar', 2]
4355 * a.reject! # => #<Enumerator: [:foo, "bar", 2]:reject!>
4359 static VALUE
4360 rb_ary_reject_bang(VALUE ary)
4362 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
4363 rb_ary_modify(ary);
4364 return ary_reject_bang(ary);
4368 * call-seq:
4369 * array.reject {|element| ... } -> new_array
4370 * array.reject -> new_enumerator
4372 * Returns a new +Array+ whose elements are all those from +self+
4373 * for which the block returns +false+ or +nil+:
4375 * a = [:foo, 'bar', 2, 'bat']
4376 * a1 = a.reject {|element| element.to_s.start_with?('b') }
4377 * a1 # => [:foo, 2]
4379 * Returns a new Enumerator if no block given:
4381 * a = [:foo, 'bar', 2]
4382 * a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
4386 static VALUE
4387 rb_ary_reject(VALUE ary)
4389 VALUE rejected_ary;
4391 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
4392 rejected_ary = rb_ary_new();
4393 ary_reject(ary, rejected_ary);
4394 return rejected_ary;
4398 * call-seq:
4399 * delete_if {|element| ... } -> self
4400 * delete_if -> new_numerator
4402 * With a block given, calls the block with each element of +self+;
4403 * removes the element if the block returns a truthy value;
4404 * returns +self+:
4406 * a = [:foo, 'bar', 2, 'bat']
4407 * a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
4409 * With no block given, returns a new Enumerator.
4411 * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
4414 static VALUE
4415 rb_ary_delete_if(VALUE ary)
4417 ary_verify(ary);
4418 RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
4419 ary_reject_bang(ary);
4420 return ary;
4423 static VALUE
4424 take_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, cbarg))
4426 VALUE *args = (VALUE *)cbarg;
4427 if (argc > 1) val = rb_ary_new4(argc, argv);
4428 rb_ary_push(args[0], val);
4429 if (--args[1] == 0) rb_iter_break();
4430 return Qnil;
4433 static VALUE
4434 take_items(VALUE obj, long n)
4436 VALUE result = rb_check_array_type(obj);
4437 VALUE args[2];
4439 if (n == 0) return result;
4440 if (!NIL_P(result)) return rb_ary_subseq(result, 0, n);
4441 result = rb_ary_new2(n);
4442 args[0] = result; args[1] = (VALUE)n;
4443 if (UNDEF_P(rb_check_block_call(obj, idEach, 0, 0, take_i, (VALUE)args)))
4444 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)",
4445 rb_obj_class(obj));
4446 return result;
4451 * call-seq:
4452 * array.zip(*other_arrays) -> new_array
4453 * array.zip(*other_arrays) {|other_array| ... } -> nil
4455 * When no block given, returns a new +Array+ +new_array+ of size <tt>self.size</tt>
4456 * whose elements are Arrays.
4458 * Each nested array <tt>new_array[n]</tt> is of size <tt>other_arrays.size+1</tt>,
4459 * and contains:
4461 * - The _nth_ element of +self+.
4462 * - The _nth_ element of each of the +other_arrays+.
4464 * If all +other_arrays+ and +self+ are the same size:
4466 * a = [:a0, :a1, :a2, :a3]
4467 * b = [:b0, :b1, :b2, :b3]
4468 * c = [:c0, :c1, :c2, :c3]
4469 * d = a.zip(b, c)
4470 * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
4472 * If any array in +other_arrays+ is smaller than +self+,
4473 * fills to <tt>self.size</tt> with +nil+:
4475 * a = [:a0, :a1, :a2, :a3]
4476 * b = [:b0, :b1, :b2]
4477 * c = [:c0, :c1]
4478 * d = a.zip(b, c)
4479 * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
4481 * If any array in +other_arrays+ is larger than +self+,
4482 * its trailing elements are ignored:
4484 * a = [:a0, :a1, :a2, :a3]
4485 * b = [:b0, :b1, :b2, :b3, :b4]
4486 * c = [:c0, :c1, :c2, :c3, :c4, :c5]
4487 * d = a.zip(b, c)
4488 * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
4490 * If an argument is not an array, it extracts the values by calling #each:
4492 * a = [:a0, :a1, :a2, :a2]
4493 * b = 1..4
4494 * c = a.zip(b)
4495 * c # => [[:a0, 1], [:a1, 2], [:a2, 3], [:a2, 4]]
4497 * When a block is given, calls the block with each of the sub-arrays (formed as above); returns +nil+:
4499 * a = [:a0, :a1, :a2, :a3]
4500 * b = [:b0, :b1, :b2, :b3]
4501 * c = [:c0, :c1, :c2, :c3]
4502 * a.zip(b, c) {|sub_array| p sub_array} # => nil
4504 * Output:
4506 * [:a0, :b0, :c0]
4507 * [:a1, :b1, :c1]
4508 * [:a2, :b2, :c2]
4509 * [:a3, :b3, :c3]
4513 static VALUE
4514 rb_ary_zip(int argc, VALUE *argv, VALUE ary)
4516 int i, j;
4517 long len = RARRAY_LEN(ary);
4518 VALUE result = Qnil;
4520 for (i=0; i<argc; i++) {
4521 argv[i] = take_items(argv[i], len);
4524 if (rb_block_given_p()) {
4525 int arity = rb_block_arity();
4527 if (arity > 1) {
4528 VALUE work, *tmp;
4530 tmp = ALLOCV_N(VALUE, work, argc+1);
4532 for (i=0; i<RARRAY_LEN(ary); i++) {
4533 tmp[0] = RARRAY_AREF(ary, i);
4534 for (j=0; j<argc; j++) {
4535 tmp[j+1] = rb_ary_elt(argv[j], i);
4537 rb_yield_values2(argc+1, tmp);
4540 if (work) ALLOCV_END(work);
4542 else {
4543 for (i=0; i<RARRAY_LEN(ary); i++) {
4544 VALUE tmp = rb_ary_new2(argc+1);
4546 rb_ary_push(tmp, RARRAY_AREF(ary, i));
4547 for (j=0; j<argc; j++) {
4548 rb_ary_push(tmp, rb_ary_elt(argv[j], i));
4550 rb_yield(tmp);
4554 else {
4555 result = rb_ary_new_capa(len);
4557 for (i=0; i<len; i++) {
4558 VALUE tmp = rb_ary_new_capa(argc+1);
4560 rb_ary_push(tmp, RARRAY_AREF(ary, i));
4561 for (j=0; j<argc; j++) {
4562 rb_ary_push(tmp, rb_ary_elt(argv[j], i));
4564 rb_ary_push(result, tmp);
4568 return result;
4572 * call-seq:
4573 * array.transpose -> new_array
4575 * Transposes the rows and columns in an +Array+ of Arrays;
4576 * the nested Arrays must all be the same size:
4578 * a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]]
4579 * a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
4583 static VALUE
4584 rb_ary_transpose(VALUE ary)
4586 long elen = -1, alen, i, j;
4587 VALUE tmp, result = 0;
4589 alen = RARRAY_LEN(ary);
4590 if (alen == 0) return rb_ary_dup(ary);
4591 for (i=0; i<alen; i++) {
4592 tmp = to_ary(rb_ary_elt(ary, i));
4593 if (elen < 0) { /* first element */
4594 elen = RARRAY_LEN(tmp);
4595 result = rb_ary_new2(elen);
4596 for (j=0; j<elen; j++) {
4597 rb_ary_store(result, j, rb_ary_new2(alen));
4600 else if (elen != RARRAY_LEN(tmp)) {
4601 rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
4602 RARRAY_LEN(tmp), elen);
4604 for (j=0; j<elen; j++) {
4605 rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
4608 return result;
4612 * call-seq:
4613 * array.replace(other_array) -> self
4615 * Replaces the content of +self+ with the content of +other_array+; returns +self+:
4617 * a = [:foo, 'bar', 2]
4618 * a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
4622 VALUE
4623 rb_ary_replace(VALUE copy, VALUE orig)
4625 rb_ary_modify_check(copy);
4626 orig = to_ary(orig);
4627 if (copy == orig) return copy;
4629 rb_ary_reset(copy);
4631 /* orig has enough space to embed the contents of orig. */
4632 if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) {
4633 RUBY_ASSERT(ARY_EMBED_P(copy));
4634 ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
4635 ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig));
4637 /* orig is embedded but copy does not have enough space to embed the
4638 * contents of orig. */
4639 else if (ARY_EMBED_P(orig)) {
4640 long len = ARY_EMBED_LEN(orig);
4641 VALUE *ptr = ary_heap_alloc_buffer(len);
4643 FL_UNSET_EMBED(copy);
4644 ARY_SET_PTR(copy, ptr);
4645 ARY_SET_LEN(copy, len);
4646 ARY_SET_CAPA(copy, len);
4648 // No allocation and exception expected that could leave `copy` in a
4649 // bad state from the edits above.
4650 ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig));
4652 /* Otherwise, orig is on heap and copy does not have enough space to embed
4653 * the contents of orig. */
4654 else {
4655 VALUE shared_root = ary_make_shared(orig);
4656 FL_UNSET_EMBED(copy);
4657 ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
4658 ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
4659 rb_ary_set_shared(copy, shared_root);
4661 ary_verify(copy);
4662 return copy;
4666 * call-seq:
4667 * clear -> self
4669 * Removes all elements from +self+; returns +self+:
4671 * a = [:foo, 'bar', 2]
4672 * a.clear # => []
4674 * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
4677 VALUE
4678 rb_ary_clear(VALUE ary)
4680 rb_ary_modify_check(ary);
4681 if (ARY_SHARED_P(ary)) {
4682 rb_ary_unshare(ary);
4683 FL_SET_EMBED(ary);
4684 ARY_SET_EMBED_LEN(ary, 0);
4686 else {
4687 ARY_SET_LEN(ary, 0);
4688 if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
4689 ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
4692 ary_verify(ary);
4693 return ary;
4697 * call-seq:
4698 * array.fill(obj) -> self
4699 * array.fill(obj, start) -> self
4700 * array.fill(obj, start, length) -> self
4701 * array.fill(obj, range) -> self
4702 * array.fill {|index| ... } -> self
4703 * array.fill(start) {|index| ... } -> self
4704 * array.fill(start, length) {|index| ... } -> self
4705 * array.fill(range) {|index| ... } -> self
4707 * Replaces specified elements in +self+ with specified objects; returns +self+.
4709 * With argument +obj+ and no block given, replaces all elements with that one object:
4711 * a = ['a', 'b', 'c', 'd']
4712 * a # => ["a", "b", "c", "d"]
4713 * a.fill(:X) # => [:X, :X, :X, :X]
4715 * With arguments +obj+ and Integer +start+, and no block given,
4716 * replaces elements based on the given start.
4718 * If +start+ is in range (<tt>0 <= start < array.size</tt>),
4719 * replaces all elements from offset +start+ through the end:
4721 * a = ['a', 'b', 'c', 'd']
4722 * a.fill(:X, 2) # => ["a", "b", :X, :X]
4724 * If +start+ is too large (<tt>start >= array.size</tt>), does nothing:
4726 * a = ['a', 'b', 'c', 'd']
4727 * a.fill(:X, 4) # => ["a", "b", "c", "d"]
4728 * a = ['a', 'b', 'c', 'd']
4729 * a.fill(:X, 5) # => ["a", "b", "c", "d"]
4731 * If +start+ is negative, counts from the end (starting index is <tt>start + array.size</tt>):
4733 * a = ['a', 'b', 'c', 'd']
4734 * a.fill(:X, -2) # => ["a", "b", :X, :X]
4736 * If +start+ is too small (less than and far from zero), replaces all elements:
4738 * a = ['a', 'b', 'c', 'd']
4739 * a.fill(:X, -6) # => [:X, :X, :X, :X]
4740 * a = ['a', 'b', 'c', 'd']
4741 * a.fill(:X, -50) # => [:X, :X, :X, :X]
4743 * With arguments +obj+, Integer +start+, and Integer +length+, and no block given,
4744 * replaces elements based on the given +start+ and +length+.
4746 * If +start+ is in range, replaces +length+ elements beginning at offset +start+:
4748 * a = ['a', 'b', 'c', 'd']
4749 * a.fill(:X, 1, 1) # => ["a", :X, "c", "d"]
4751 * If +start+ is negative, counts from the end:
4753 * a = ['a', 'b', 'c', 'd']
4754 * a.fill(:X, -2, 1) # => ["a", "b", :X, "d"]
4756 * If +start+ is large (<tt>start >= array.size</tt>), extends +self+ with +nil+:
4758 * a = ['a', 'b', 'c', 'd']
4759 * a.fill(:X, 5, 0) # => ["a", "b", "c", "d", nil]
4760 * a = ['a', 'b', 'c', 'd']
4761 * a.fill(:X, 5, 2) # => ["a", "b", "c", "d", nil, :X, :X]
4763 * If +length+ is zero or negative, replaces no elements:
4765 * a = ['a', 'b', 'c', 'd']
4766 * a.fill(:X, 1, 0) # => ["a", "b", "c", "d"]
4767 * a.fill(:X, 1, -1) # => ["a", "b", "c", "d"]
4769 * With arguments +obj+ and Range +range+, and no block given,
4770 * replaces elements based on the given range.
4772 * If the range is positive and ascending (<tt>0 < range.begin <= range.end</tt>),
4773 * replaces elements from <tt>range.begin</tt> to <tt>range.end</tt>:
4775 * a = ['a', 'b', 'c', 'd']
4776 * a.fill(:X, (1..1)) # => ["a", :X, "c", "d"]
4778 * If <tt>range.first</tt> is negative, replaces no elements:
4780 * a = ['a', 'b', 'c', 'd']
4781 * a.fill(:X, (-1..1)) # => ["a", "b", "c", "d"]
4783 * If <tt>range.last</tt> is negative, counts from the end:
4785 * a = ['a', 'b', 'c', 'd']
4786 * a.fill(:X, (0..-2)) # => [:X, :X, :X, "d"]
4787 * a = ['a', 'b', 'c', 'd']
4788 * a.fill(:X, (1..-2)) # => ["a", :X, :X, "d"]
4790 * If <tt>range.last</tt> and <tt>range.last</tt> are both negative,
4791 * both count from the end of the array:
4793 * a = ['a', 'b', 'c', 'd']
4794 * a.fill(:X, (-1..-1)) # => ["a", "b", "c", :X]
4795 * a = ['a', 'b', 'c', 'd']
4796 * a.fill(:X, (-2..-2)) # => ["a", "b", :X, "d"]
4798 * With no arguments and a block given, calls the block with each index;
4799 * replaces the corresponding element with the block's return value:
4801 * a = ['a', 'b', 'c', 'd']
4802 * a.fill { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
4804 * With argument +start+ and a block given, calls the block with each index
4805 * from offset +start+ to the end; replaces the corresponding element
4806 * with the block's return value.
4808 * If start is in range (<tt>0 <= start < array.size</tt>),
4809 * replaces from offset +start+ to the end:
4811 * a = ['a', 'b', 'c', 'd']
4812 * a.fill(1) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "new_3"]
4814 * If +start+ is too large(<tt>start >= array.size</tt>), does nothing:
4816 * a = ['a', 'b', 'c', 'd']
4817 * a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
4818 * a = ['a', 'b', 'c', 'd']
4819 * a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
4821 * If +start+ is negative, counts from the end:
4823 * a = ['a', 'b', 'c', 'd']
4824 * a.fill(-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "new_3"]
4826 * If start is too small (<tt>start <= -array.size</tt>, replaces all elements:
4828 * a = ['a', 'b', 'c', 'd']
4829 * a.fill(-6) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
4830 * a = ['a', 'b', 'c', 'd']
4831 * a.fill(-50) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
4833 * With arguments +start+ and +length+, and a block given,
4834 * calls the block for each index specified by start length;
4835 * replaces the corresponding element with the block's return value.
4837 * If +start+ is in range, replaces +length+ elements beginning at offset +start+:
4839 * a = ['a', 'b', 'c', 'd']
4840 * a.fill(1, 1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
4842 * If start is negative, counts from the end:
4844 * a = ['a', 'b', 'c', 'd']
4845 * a.fill(-2, 1) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
4847 * If +start+ is large (<tt>start >= array.size</tt>), extends +self+ with +nil+:
4849 * a = ['a', 'b', 'c', 'd']
4850 * a.fill(5, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil]
4851 * a = ['a', 'b', 'c', 'd']
4852 * a.fill(5, 2) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil, "new_5", "new_6"]
4854 * If +length+ is zero or less, replaces no elements:
4856 * a = ['a', 'b', 'c', 'd']
4857 * a.fill(1, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
4858 * a.fill(1, -1) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
4860 * With arguments +obj+ and +range+, and a block given,
4861 * calls the block with each index in the given range;
4862 * replaces the corresponding element with the block's return value.
4864 * If the range is positive and ascending (<tt>range 0 < range.begin <= range.end</tt>,
4865 * replaces elements from <tt>range.begin</tt> to <tt>range.end</tt>:
4867 * a = ['a', 'b', 'c', 'd']
4868 * a.fill(1..1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
4870 * If +range.first+ is negative, does nothing:
4872 * a = ['a', 'b', 'c', 'd']
4873 * a.fill(-1..1) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
4875 * If <tt>range.last</tt> is negative, counts from the end:
4877 * a = ['a', 'b', 'c', 'd']
4878 * a.fill(0..-2) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "d"]
4879 * a = ['a', 'b', 'c', 'd']
4880 * a.fill(1..-2) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "d"]
4882 * If <tt>range.first</tt> and <tt>range.last</tt> are both negative,
4883 * both count from the end:
4885 * a = ['a', 'b', 'c', 'd']
4886 * a.fill(-1..-1) { |index| "new_#{index}" } # => ["a", "b", "c", "new_3"]
4887 * a = ['a', 'b', 'c', 'd']
4888 * a.fill(-2..-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
4892 static VALUE
4893 rb_ary_fill(int argc, VALUE *argv, VALUE ary)
4895 VALUE item = Qundef, arg1, arg2;
4896 long beg = 0, end = 0, len = 0;
4898 if (rb_block_given_p()) {
4899 rb_scan_args(argc, argv, "02", &arg1, &arg2);
4900 argc += 1; /* hackish */
4902 else {
4903 rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
4905 switch (argc) {
4906 case 1:
4907 beg = 0;
4908 len = RARRAY_LEN(ary);
4909 break;
4910 case 2:
4911 if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
4912 break;
4914 /* fall through */
4915 case 3:
4916 beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
4917 if (beg < 0) {
4918 beg = RARRAY_LEN(ary) + beg;
4919 if (beg < 0) beg = 0;
4921 len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
4922 break;
4924 rb_ary_modify(ary);
4925 if (len < 0) {
4926 return ary;
4928 if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
4929 rb_raise(rb_eArgError, "argument too big");
4931 end = beg + len;
4932 if (RARRAY_LEN(ary) < end) {
4933 if (end >= ARY_CAPA(ary)) {
4934 ary_resize_capa(ary, end);
4936 ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary));
4937 ARY_SET_LEN(ary, end);
4940 if (UNDEF_P(item)) {
4941 VALUE v;
4942 long i;
4944 for (i=beg; i<end; i++) {
4945 v = rb_yield(LONG2NUM(i));
4946 if (i>=RARRAY_LEN(ary)) break;
4947 ARY_SET(ary, i, v);
4950 else {
4951 ary_memfill(ary, beg, len, item);
4953 return ary;
4957 * call-seq:
4958 * self + other_array -> new_array
4960 * Returns a new array containing all elements of +self+
4961 * followed by all elements of +other_array+:
4963 * a = [0, 1] + [2, 3]
4964 * a # => [0, 1, 2, 3]
4966 * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
4969 VALUE
4970 rb_ary_plus(VALUE x, VALUE y)
4972 VALUE z;
4973 long len, xlen, ylen;
4975 y = to_ary(y);
4976 xlen = RARRAY_LEN(x);
4977 ylen = RARRAY_LEN(y);
4978 len = xlen + ylen;
4979 z = rb_ary_new2(len);
4981 ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
4982 ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
4983 ARY_SET_LEN(z, len);
4984 return z;
4987 static VALUE
4988 ary_append(VALUE x, VALUE y)
4990 long n = RARRAY_LEN(y);
4991 if (n > 0) {
4992 rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n);
4994 RB_GC_GUARD(y);
4995 return x;
4999 * call-seq:
5000 * concat(*other_arrays) -> self
5002 * Adds to +self+ all elements from each array in +other_arrays+; returns +self+:
5004 * a = [0, 1]
5005 * a.concat(['two', 'three'], [:four, :five], a)
5006 * # => [0, 1, "two", "three", :four, :five, 0, 1]
5008 * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
5011 static VALUE
5012 rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary)
5014 rb_ary_modify_check(ary);
5016 if (argc == 1) {
5017 rb_ary_concat(ary, argv[0]);
5019 else if (argc > 1) {
5020 int i;
5021 VALUE args = rb_ary_hidden_new(argc);
5022 for (i = 0; i < argc; i++) {
5023 rb_ary_concat(args, argv[i]);
5025 ary_append(ary, args);
5028 ary_verify(ary);
5029 return ary;
5032 VALUE
5033 rb_ary_concat(VALUE x, VALUE y)
5035 return ary_append(x, to_ary(y));
5039 * call-seq:
5040 * self * n -> new_array
5041 * self * string_separator -> new_string
5043 * When non-negative integer argument +n+ is given,
5044 * returns a new array built by concatenating +n+ copies of +self+:
5046 * a = ['x', 'y']
5047 * a * 3 # => ["x", "y", "x", "y", "x", "y"]
5049 * When string argument +string_separator+ is given,
5050 * equivalent to <tt>array.join(string_separator)</tt>:
5052 * [0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {:foo=>0}"
5056 static VALUE
5057 rb_ary_times(VALUE ary, VALUE times)
5059 VALUE ary2, tmp;
5060 const VALUE *ptr;
5061 long t, len;
5063 tmp = rb_check_string_type(times);
5064 if (!NIL_P(tmp)) {
5065 return rb_ary_join(ary, tmp);
5068 len = NUM2LONG(times);
5069 if (len == 0) {
5070 ary2 = ary_new(rb_cArray, 0);
5071 goto out;
5073 if (len < 0) {
5074 rb_raise(rb_eArgError, "negative argument");
5076 if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) {
5077 rb_raise(rb_eArgError, "argument too big");
5079 len *= RARRAY_LEN(ary);
5081 ary2 = ary_new(rb_cArray, len);
5082 ARY_SET_LEN(ary2, len);
5084 ptr = RARRAY_CONST_PTR(ary);
5085 t = RARRAY_LEN(ary);
5086 if (0 < t) {
5087 ary_memcpy(ary2, 0, t, ptr);
5088 while (t <= len/2) {
5089 ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2));
5090 t *= 2;
5092 if (t < len) {
5093 ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2));
5096 out:
5097 return ary2;
5101 * call-seq:
5102 * assoc(object) -> found_array or nil
5104 * Returns the first element +ele+ in +self+ such that +ele+ is an array
5105 * and <tt>ele[0] == object</tt>:
5107 * a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
5108 * a.assoc(4) # => [4, 5, 6]
5110 * Returns +nil+ if no such element is found.
5112 * Related: Array#rassoc;
5113 * see also {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
5116 VALUE
5117 rb_ary_assoc(VALUE ary, VALUE key)
5119 long i;
5120 VALUE v;
5122 for (i = 0; i < RARRAY_LEN(ary); ++i) {
5123 v = rb_check_array_type(RARRAY_AREF(ary, i));
5124 if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
5125 rb_equal(RARRAY_AREF(v, 0), key))
5126 return v;
5128 return Qnil;
5132 * call-seq:
5133 * array.rassoc(obj) -> found_array or nil
5135 * Returns the first element in +self+ that is an +Array+
5136 * whose second element <tt>==</tt> +obj+:
5138 * a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
5139 * a.rassoc(4) # => [2, 4]
5141 * Returns +nil+ if no such element is found.
5143 * Related: #assoc.
5146 VALUE
5147 rb_ary_rassoc(VALUE ary, VALUE value)
5149 long i;
5150 VALUE v;
5152 for (i = 0; i < RARRAY_LEN(ary); ++i) {
5153 v = rb_check_array_type(RARRAY_AREF(ary, i));
5154 if (RB_TYPE_P(v, T_ARRAY) &&
5155 RARRAY_LEN(v) > 1 &&
5156 rb_equal(RARRAY_AREF(v, 1), value))
5157 return v;
5159 return Qnil;
5162 static VALUE
5163 recursive_equal(VALUE ary1, VALUE ary2, int recur)
5165 long i, len1;
5166 const VALUE *p1, *p2;
5168 if (recur) return Qtrue; /* Subtle! */
5170 /* rb_equal() can evacuate ptrs */
5171 p1 = RARRAY_CONST_PTR(ary1);
5172 p2 = RARRAY_CONST_PTR(ary2);
5173 len1 = RARRAY_LEN(ary1);
5175 for (i = 0; i < len1; i++) {
5176 if (*p1 != *p2) {
5177 if (rb_equal(*p1, *p2)) {
5178 len1 = RARRAY_LEN(ary1);
5179 if (len1 != RARRAY_LEN(ary2))
5180 return Qfalse;
5181 if (len1 < i)
5182 return Qtrue;
5183 p1 = RARRAY_CONST_PTR(ary1) + i;
5184 p2 = RARRAY_CONST_PTR(ary2) + i;
5186 else {
5187 return Qfalse;
5190 p1++;
5191 p2++;
5193 return Qtrue;
5197 * call-seq:
5198 * self == other_array -> true or false
5200 * Returns whether both:
5202 * - +self+ and +other_array+ are the same size.
5203 * - Their corresponding elements are the same;
5204 * that is, for each index +i+ in <tt>(0...self.size)</tt>,
5205 * <tt>self[i] == other_array[i]</tt>.
5207 * Examples:
5209 * [:foo, 'bar', 2] == [:foo, 'bar', 2] # => true
5210 * [:foo, 'bar', 2] == [:foo, 'bar', 2.0] # => true
5211 * [:foo, 'bar', 2] == [:foo, 'bar'] # => false # Different sizes.
5212 * [:foo, 'bar', 2] == [:foo, 'bar', 3] # => false # Different elements.
5214 * This method is different from method Array#eql?,
5215 * which compares elements using <tt>Object#eql?</tt>.
5217 * Related: see {Methods for Comparing}[rdoc-ref:Array@Methods+for+Comparing].
5220 static VALUE
5221 rb_ary_equal(VALUE ary1, VALUE ary2)
5223 if (ary1 == ary2) return Qtrue;
5224 if (!RB_TYPE_P(ary2, T_ARRAY)) {
5225 if (!rb_respond_to(ary2, idTo_ary)) {
5226 return Qfalse;
5228 return rb_equal(ary2, ary1);
5230 if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
5231 if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
5232 return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
5235 static VALUE
5236 recursive_eql(VALUE ary1, VALUE ary2, int recur)
5238 long i;
5240 if (recur) return Qtrue; /* Subtle! */
5241 for (i=0; i<RARRAY_LEN(ary1); i++) {
5242 if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
5243 return Qfalse;
5245 return Qtrue;
5249 * call-seq:
5250 * array.eql?(other_array) -> true or false
5252 * Returns +true+ if +self+ and +other_array+ are the same size,
5253 * and if, for each index +i+ in +self+, <tt>self[i].eql?(other_array[i])</tt>:
5255 * a0 = [:foo, 'bar', 2]
5256 * a1 = [:foo, 'bar', 2]
5257 * a1.eql?(a0) # => true
5259 * Otherwise, returns +false+.
5261 * This method is different from method Array#==,
5262 * which compares using method <tt>Object#==</tt>.
5265 static VALUE
5266 rb_ary_eql(VALUE ary1, VALUE ary2)
5268 if (ary1 == ary2) return Qtrue;
5269 if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
5270 if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
5271 if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
5272 return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
5275 VALUE
5276 rb_ary_hash_values(long len, const VALUE *elements)
5278 long i;
5279 st_index_t h;
5280 VALUE n;
5282 h = rb_hash_start(len);
5283 h = rb_hash_uint(h, (st_index_t)rb_ary_hash_values);
5284 for (i=0; i<len; i++) {
5285 n = rb_hash(elements[i]);
5286 h = rb_hash_uint(h, NUM2LONG(n));
5288 h = rb_hash_end(h);
5289 return ST2FIX(h);
5293 * call-seq:
5294 * array.hash -> integer
5296 * Returns the integer hash value for +self+.
5298 * Two arrays with the same content will have the same hash code (and will compare using #eql?):
5300 * [0, 1, 2].hash == [0, 1, 2].hash # => true
5301 * [0, 1, 2].hash == [0, 1, 3].hash # => false
5305 static VALUE
5306 rb_ary_hash(VALUE ary)
5308 return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
5312 * call-seq:
5313 * array.include?(obj) -> true or false
5315 * Returns +true+ if for some index +i+ in +self+, <tt>obj == self[i]</tt>;
5316 * otherwise +false+:
5318 * [0, 1, 2].include?(2) # => true
5319 * [0, 1, 2].include?(3) # => false
5322 VALUE
5323 rb_ary_includes(VALUE ary, VALUE item)
5325 long i;
5326 VALUE e;
5328 for (i=0; i<RARRAY_LEN(ary); i++) {
5329 e = RARRAY_AREF(ary, i);
5330 if (rb_equal(e, item)) {
5331 return Qtrue;
5334 return Qfalse;
5337 static VALUE
5338 rb_ary_includes_by_eql(VALUE ary, VALUE item)
5340 long i;
5341 VALUE e;
5343 for (i=0; i<RARRAY_LEN(ary); i++) {
5344 e = RARRAY_AREF(ary, i);
5345 if (rb_eql(item, e)) {
5346 return Qtrue;
5349 return Qfalse;
5352 static VALUE
5353 recursive_cmp(VALUE ary1, VALUE ary2, int recur)
5355 long i, len;
5357 if (recur) return Qundef; /* Subtle! */
5358 len = RARRAY_LEN(ary1);
5359 if (len > RARRAY_LEN(ary2)) {
5360 len = RARRAY_LEN(ary2);
5362 for (i=0; i<len; i++) {
5363 VALUE e1 = rb_ary_elt(ary1, i), e2 = rb_ary_elt(ary2, i);
5364 VALUE v = rb_funcallv(e1, id_cmp, 1, &e2);
5365 if (v != INT2FIX(0)) {
5366 return v;
5369 return Qundef;
5373 * call-seq:
5374 * self <=> other_array -> -1, 0, or 1
5376 * Returns -1, 0, or 1 as +self+ is determined
5377 * to be less than, equal to, or greater than +other_array+.
5379 * Iterates over each index +i+ in <tt>(0...self.size)</tt>:
5381 * - Computes <tt>result[i]</tt> as <tt>self[i] <=> other_array[i]</tt>.
5382 * - Immediately returns 1 if <tt>result[i]</tt> is 1:
5384 * [0, 1, 2] <=> [0, 0, 2] # => 1
5386 * - Immediately returns -1 if <tt>result[i]</tt> is -1:
5388 * [0, 1, 2] <=> [0, 2, 2] # => -1
5390 * - Continues if <tt>result[i]</tt> is 0.
5392 * When every +result+ is 0,
5393 * returns <tt>self.size <=> other_array.size</tt>
5394 * (see Integer#<=>):
5396 * [0, 1, 2] <=> [0, 1] # => 1
5397 * [0, 1, 2] <=> [0, 1, 2] # => 0
5398 * [0, 1, 2] <=> [0, 1, 2, 3] # => -1
5400 * Note that when +other_array+ is larger than +self+,
5401 * its trailing elements do not affect the result:
5403 * [0, 1, 2] <=> [0, 1, 2, -3] # => -1
5404 * [0, 1, 2] <=> [0, 1, 2, 0] # => -1
5405 * [0, 1, 2] <=> [0, 1, 2, 3] # => -1
5407 * Related: see {Methods for Comparing}[rdoc-ref:Array@Methods+for+Comparing].
5410 VALUE
5411 rb_ary_cmp(VALUE ary1, VALUE ary2)
5413 long len;
5414 VALUE v;
5416 ary2 = rb_check_array_type(ary2);
5417 if (NIL_P(ary2)) return Qnil;
5418 if (ary1 == ary2) return INT2FIX(0);
5419 v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
5420 if (!UNDEF_P(v)) return v;
5421 len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
5422 if (len == 0) return INT2FIX(0);
5423 if (len > 0) return INT2FIX(1);
5424 return INT2FIX(-1);
5427 static VALUE
5428 ary_add_hash(VALUE hash, VALUE ary)
5430 long i;
5432 for (i=0; i<RARRAY_LEN(ary); i++) {
5433 VALUE elt = RARRAY_AREF(ary, i);
5434 rb_hash_add_new_element(hash, elt, elt);
5436 return hash;
5439 static inline VALUE
5440 ary_tmp_hash_new(VALUE ary)
5442 long size = RARRAY_LEN(ary);
5443 VALUE hash = rb_hash_new_with_size(size);
5445 RBASIC_CLEAR_CLASS(hash);
5446 return hash;
5449 static VALUE
5450 ary_make_hash(VALUE ary)
5452 VALUE hash = ary_tmp_hash_new(ary);
5453 return ary_add_hash(hash, ary);
5456 static VALUE
5457 ary_add_hash_by(VALUE hash, VALUE ary)
5459 long i;
5461 for (i = 0; i < RARRAY_LEN(ary); ++i) {
5462 VALUE v = rb_ary_elt(ary, i), k = rb_yield(v);
5463 rb_hash_add_new_element(hash, k, v);
5465 return hash;
5468 static VALUE
5469 ary_make_hash_by(VALUE ary)
5471 VALUE hash = ary_tmp_hash_new(ary);
5472 return ary_add_hash_by(hash, ary);
5476 * call-seq:
5477 * self - other_array -> new_array
5479 * Returns a new array containing only those elements of +self+
5480 * that are not found in +other_array+;
5481 * the order from +self+ is preserved:
5483 * [0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3]
5484 * [0, 1, 1, 2, 1, 1, 3, 1, 1] - [3, 2, 0, :foo] # => [1, 1, 1, 1, 1, 1]
5485 * [0, 1, 2] - [:foo] # => [0, 1, 2]
5487 * Element are compared using method <tt>#eql?</tt>
5488 * (as defined in each element of +self+).
5490 * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
5493 VALUE
5494 rb_ary_diff(VALUE ary1, VALUE ary2)
5496 VALUE ary3;
5497 VALUE hash;
5498 long i;
5500 ary2 = to_ary(ary2);
5501 if (RARRAY_LEN(ary2) == 0) { return ary_make_shared_copy(ary1); }
5502 ary3 = rb_ary_new();
5504 if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN || RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
5505 for (i=0; i<RARRAY_LEN(ary1); i++) {
5506 VALUE elt = rb_ary_elt(ary1, i);
5507 if (rb_ary_includes_by_eql(ary2, elt)) continue;
5508 rb_ary_push(ary3, elt);
5510 return ary3;
5513 hash = ary_make_hash(ary2);
5514 for (i=0; i<RARRAY_LEN(ary1); i++) {
5515 if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
5516 rb_ary_push(ary3, rb_ary_elt(ary1, i));
5519 return ary3;
5523 * call-seq:
5524 * array.difference(*other_arrays) -> new_array
5526 * Returns a new +Array+ containing only those elements from +self+
5527 * that are not found in any of the Arrays +other_arrays+;
5528 * items are compared using <tt>eql?</tt>; order from +self+ is preserved:
5530 * [0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1]) # => [0, 2, 3]
5531 * [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2]
5532 * [0, 1, 2].difference([4]) # => [0, 1, 2]
5534 * Returns a copy of +self+ if no arguments given.
5536 * Related: Array#-.
5539 static VALUE
5540 rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
5542 VALUE ary_diff;
5543 long i, length;
5544 volatile VALUE t0;
5545 bool *is_hash = ALLOCV_N(bool, t0, argc);
5546 ary_diff = rb_ary_new();
5547 length = RARRAY_LEN(ary);
5549 for (i = 0; i < argc; i++) {
5550 argv[i] = to_ary(argv[i]);
5551 is_hash[i] = (length > SMALL_ARRAY_LEN && RARRAY_LEN(argv[i]) > SMALL_ARRAY_LEN);
5552 if (is_hash[i]) argv[i] = ary_make_hash(argv[i]);
5555 for (i = 0; i < RARRAY_LEN(ary); i++) {
5556 int j;
5557 VALUE elt = rb_ary_elt(ary, i);
5558 for (j = 0; j < argc; j++) {
5559 if (is_hash[j]) {
5560 if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL))
5561 break;
5563 else {
5564 if (rb_ary_includes_by_eql(argv[j], elt)) break;
5567 if (j == argc) rb_ary_push(ary_diff, elt);
5570 ALLOCV_END(t0);
5572 return ary_diff;
5577 * call-seq:
5578 * self & other_array -> new_array
5580 * Returns a new array containing the _intersection_ of +self+ and +other_array+;
5581 * that is, containing those elements found in both +self+ and +other_array+:
5583 * [0, 1, 2, 3] & [1, 2] # => [1, 2]
5585 * Omits duplicates:
5587 * [0, 1, 1, 0] & [0, 1] # => [0, 1]
5589 * Preserves order from +self+:
5591 * [0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
5593 * Identifies common elements using method <tt>#eql?</tt>
5594 * (as defined in each element of +self+).
5596 * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
5600 static VALUE
5601 rb_ary_and(VALUE ary1, VALUE ary2)
5603 VALUE hash, ary3, v;
5604 st_data_t vv;
5605 long i;
5607 ary2 = to_ary(ary2);
5608 ary3 = rb_ary_new();
5609 if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return ary3;
5611 if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
5612 for (i=0; i<RARRAY_LEN(ary1); i++) {
5613 v = RARRAY_AREF(ary1, i);
5614 if (!rb_ary_includes_by_eql(ary2, v)) continue;
5615 if (rb_ary_includes_by_eql(ary3, v)) continue;
5616 rb_ary_push(ary3, v);
5618 return ary3;
5621 hash = ary_make_hash(ary2);
5623 for (i=0; i<RARRAY_LEN(ary1); i++) {
5624 v = RARRAY_AREF(ary1, i);
5625 vv = (st_data_t)v;
5626 if (rb_hash_stlike_delete(hash, &vv, 0)) {
5627 rb_ary_push(ary3, v);
5631 return ary3;
5635 * call-seq:
5636 * array.intersection(*other_arrays) -> new_array
5638 * Returns a new +Array+ containing each element found both in +self+
5639 * and in all of the given Arrays +other_arrays+;
5640 * duplicates are omitted; items are compared using <tt>eql?</tt>
5641 * (items must also implement +hash+ correctly):
5643 * [0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
5644 * [0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
5646 * Preserves order from +self+:
5648 * [0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
5650 * Returns a copy of +self+ if no arguments given.
5652 * Related: Array#&.
5655 static VALUE
5656 rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary)
5658 VALUE result = rb_ary_dup(ary);
5659 int i;
5661 for (i = 0; i < argc; i++) {
5662 result = rb_ary_and(result, argv[i]);
5665 return result;
5668 static int
5669 ary_hash_orset(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
5671 if (existing) return ST_STOP;
5672 *key = *value = (VALUE)arg;
5673 return ST_CONTINUE;
5676 static void
5677 rb_ary_union(VALUE ary_union, VALUE ary)
5679 long i;
5680 for (i = 0; i < RARRAY_LEN(ary); i++) {
5681 VALUE elt = rb_ary_elt(ary, i);
5682 if (rb_ary_includes_by_eql(ary_union, elt)) continue;
5683 rb_ary_push(ary_union, elt);
5687 static void
5688 rb_ary_union_hash(VALUE hash, VALUE ary2)
5690 long i;
5691 for (i = 0; i < RARRAY_LEN(ary2); i++) {
5692 VALUE elt = RARRAY_AREF(ary2, i);
5693 if (!rb_hash_stlike_update(hash, (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
5694 RB_OBJ_WRITTEN(hash, Qundef, elt);
5700 * call-seq:
5701 * array | other_array -> new_array
5703 * Returns the union of +array+ and +Array+ +other_array+;
5704 * duplicates are removed; order is preserved;
5705 * items are compared using <tt>eql?</tt>:
5707 * [0, 1] | [2, 3] # => [0, 1, 2, 3]
5708 * [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3]
5709 * [0, 1, 2] | [3, 2, 1, 0] # => [0, 1, 2, 3]
5711 * Related: Array#union.
5714 static VALUE
5715 rb_ary_or(VALUE ary1, VALUE ary2)
5717 VALUE hash;
5719 ary2 = to_ary(ary2);
5720 if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
5721 VALUE ary3 = rb_ary_new();
5722 rb_ary_union(ary3, ary1);
5723 rb_ary_union(ary3, ary2);
5724 return ary3;
5727 hash = ary_make_hash(ary1);
5728 rb_ary_union_hash(hash, ary2);
5730 return rb_hash_values(hash);
5734 * call-seq:
5735 * array.union(*other_arrays) -> new_array
5737 * Returns a new +Array+ that is the union of +self+ and all given Arrays +other_arrays+;
5738 * duplicates are removed; order is preserved; items are compared using <tt>eql?</tt>:
5740 * [0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
5741 * [0, 1, 1].union([2, 1], [3, 1]) # => [0, 1, 2, 3]
5742 * [0, 1, 2, 3].union([3, 2], [1, 0]) # => [0, 1, 2, 3]
5744 * Returns a copy of +self+ if no arguments given.
5746 * Related: Array#|.
5749 static VALUE
5750 rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
5752 int i;
5753 long sum;
5754 VALUE hash;
5756 sum = RARRAY_LEN(ary);
5757 for (i = 0; i < argc; i++) {
5758 argv[i] = to_ary(argv[i]);
5759 sum += RARRAY_LEN(argv[i]);
5762 if (sum <= SMALL_ARRAY_LEN) {
5763 VALUE ary_union = rb_ary_new();
5765 rb_ary_union(ary_union, ary);
5766 for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
5768 return ary_union;
5771 hash = ary_make_hash(ary);
5772 for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
5774 return rb_hash_values(hash);
5778 * call-seq:
5779 * ary.intersect?(other_ary) -> true or false
5781 * Returns +true+ if the array and +other_ary+ have at least one element in
5782 * common, otherwise returns +false+:
5784 * a = [ 1, 2, 3 ]
5785 * b = [ 3, 4, 5 ]
5786 * c = [ 5, 6, 7 ]
5787 * a.intersect?(b) #=> true
5788 * a.intersect?(c) #=> false
5790 * +Array+ elements are compared using <tt>eql?</tt>
5791 * (items must also implement +hash+ correctly).
5794 static VALUE
5795 rb_ary_intersect_p(VALUE ary1, VALUE ary2)
5797 VALUE hash, v, result, shorter, longer;
5798 st_data_t vv;
5799 long i;
5801 ary2 = to_ary(ary2);
5802 if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return Qfalse;
5804 if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
5805 for (i=0; i<RARRAY_LEN(ary1); i++) {
5806 v = RARRAY_AREF(ary1, i);
5807 if (rb_ary_includes_by_eql(ary2, v)) return Qtrue;
5809 return Qfalse;
5812 shorter = ary1;
5813 longer = ary2;
5814 if (RARRAY_LEN(ary1) > RARRAY_LEN(ary2)) {
5815 longer = ary1;
5816 shorter = ary2;
5819 hash = ary_make_hash(shorter);
5820 result = Qfalse;
5822 for (i=0; i<RARRAY_LEN(longer); i++) {
5823 v = RARRAY_AREF(longer, i);
5824 vv = (st_data_t)v;
5825 if (rb_hash_stlike_lookup(hash, vv, 0)) {
5826 result = Qtrue;
5827 break;
5831 return result;
5834 static VALUE
5835 ary_max_generic(VALUE ary, long i, VALUE vmax)
5837 RUBY_ASSERT(i > 0 && i < RARRAY_LEN(ary));
5839 VALUE v;
5840 for (; i < RARRAY_LEN(ary); ++i) {
5841 v = RARRAY_AREF(ary, i);
5843 if (rb_cmpint(rb_funcallv(vmax, id_cmp, 1, &v), vmax, v) < 0) {
5844 vmax = v;
5848 return vmax;
5851 static VALUE
5852 ary_max_opt_fixnum(VALUE ary, long i, VALUE vmax)
5854 const long n = RARRAY_LEN(ary);
5855 RUBY_ASSERT(i > 0 && i < n);
5856 RUBY_ASSERT(FIXNUM_P(vmax));
5858 VALUE v;
5859 for (; i < n; ++i) {
5860 v = RARRAY_AREF(ary, i);
5862 if (FIXNUM_P(v)) {
5863 if ((long)vmax < (long)v) {
5864 vmax = v;
5867 else {
5868 return ary_max_generic(ary, i, vmax);
5872 return vmax;
5875 static VALUE
5876 ary_max_opt_float(VALUE ary, long i, VALUE vmax)
5878 const long n = RARRAY_LEN(ary);
5879 RUBY_ASSERT(i > 0 && i < n);
5880 RUBY_ASSERT(RB_FLOAT_TYPE_P(vmax));
5882 VALUE v;
5883 for (; i < n; ++i) {
5884 v = RARRAY_AREF(ary, i);
5886 if (RB_FLOAT_TYPE_P(v)) {
5887 if (rb_float_cmp(vmax, v) < 0) {
5888 vmax = v;
5891 else {
5892 return ary_max_generic(ary, i, vmax);
5896 return vmax;
5899 static VALUE
5900 ary_max_opt_string(VALUE ary, long i, VALUE vmax)
5902 const long n = RARRAY_LEN(ary);
5903 RUBY_ASSERT(i > 0 && i < n);
5904 RUBY_ASSERT(STRING_P(vmax));
5906 VALUE v;
5907 for (; i < n; ++i) {
5908 v = RARRAY_AREF(ary, i);
5910 if (STRING_P(v)) {
5911 if (rb_str_cmp(vmax, v) < 0) {
5912 vmax = v;
5915 else {
5916 return ary_max_generic(ary, i, vmax);
5920 return vmax;
5924 * call-seq:
5925 * array.max -> element
5926 * array.max {|a, b| ... } -> element
5927 * array.max(n) -> new_array
5928 * array.max(n) {|a, b| ... } -> new_array
5930 * Returns one of the following:
5932 * - The maximum-valued element from +self+.
5933 * - A new +Array+ of maximum-valued elements selected from +self+.
5935 * When no block is given, each element in +self+ must respond to method <tt><=></tt>
5936 * with an Integer.
5938 * With no argument and no block, returns the element in +self+
5939 * having the maximum value per method <tt><=></tt>:
5941 * [0, 1, 2].max # => 2
5943 * With an argument Integer +n+ and no block, returns a new +Array+ with at most +n+ elements,
5944 * in descending order per method <tt><=></tt>:
5946 * [0, 1, 2, 3].max(3) # => [3, 2, 1]
5947 * [0, 1, 2, 3].max(6) # => [3, 2, 1, 0]
5949 * When a block is given, the block must return an Integer.
5951 * With a block and no argument, calls the block <tt>self.size-1</tt> times to compare elements;
5952 * returns the element having the maximum value per the block:
5954 * ['0', '00', '000'].max {|a, b| a.size <=> b.size } # => "000"
5956 * With an argument +n+ and a block, returns a new +Array+ with at most +n+ elements,
5957 * in descending order per the block:
5959 * ['0', '00', '000'].max(2) {|a, b| a.size <=> b.size } # => ["000", "00"]
5962 static VALUE
5963 rb_ary_max(int argc, VALUE *argv, VALUE ary)
5965 VALUE result = Qundef, v;
5966 VALUE num;
5967 long i;
5969 if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
5970 return rb_nmin_run(ary, num, 0, 1, 1);
5972 const long n = RARRAY_LEN(ary);
5973 if (rb_block_given_p()) {
5974 for (i = 0; i < RARRAY_LEN(ary); i++) {
5975 v = RARRAY_AREF(ary, i);
5976 if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) {
5977 result = v;
5981 else if (n > 0) {
5982 result = RARRAY_AREF(ary, 0);
5983 if (n > 1) {
5984 if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
5985 return ary_max_opt_fixnum(ary, 1, result);
5987 else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
5988 return ary_max_opt_string(ary, 1, result);
5990 else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
5991 return ary_max_opt_float(ary, 1, result);
5993 else {
5994 return ary_max_generic(ary, 1, result);
5998 if (UNDEF_P(result)) return Qnil;
5999 return result;
6002 static VALUE
6003 ary_min_generic(VALUE ary, long i, VALUE vmin)
6005 RUBY_ASSERT(i > 0 && i < RARRAY_LEN(ary));
6007 VALUE v;
6008 for (; i < RARRAY_LEN(ary); ++i) {
6009 v = RARRAY_AREF(ary, i);
6011 if (rb_cmpint(rb_funcallv(vmin, id_cmp, 1, &v), vmin, v) > 0) {
6012 vmin = v;
6016 return vmin;
6019 static VALUE
6020 ary_min_opt_fixnum(VALUE ary, long i, VALUE vmin)
6022 const long n = RARRAY_LEN(ary);
6023 RUBY_ASSERT(i > 0 && i < n);
6024 RUBY_ASSERT(FIXNUM_P(vmin));
6026 VALUE a;
6027 for (; i < n; ++i) {
6028 a = RARRAY_AREF(ary, i);
6030 if (FIXNUM_P(a)) {
6031 if ((long)vmin > (long)a) {
6032 vmin = a;
6035 else {
6036 return ary_min_generic(ary, i, vmin);
6040 return vmin;
6043 static VALUE
6044 ary_min_opt_float(VALUE ary, long i, VALUE vmin)
6046 const long n = RARRAY_LEN(ary);
6047 RUBY_ASSERT(i > 0 && i < n);
6048 RUBY_ASSERT(RB_FLOAT_TYPE_P(vmin));
6050 VALUE a;
6051 for (; i < n; ++i) {
6052 a = RARRAY_AREF(ary, i);
6054 if (RB_FLOAT_TYPE_P(a)) {
6055 if (rb_float_cmp(vmin, a) > 0) {
6056 vmin = a;
6059 else {
6060 return ary_min_generic(ary, i, vmin);
6064 return vmin;
6067 static VALUE
6068 ary_min_opt_string(VALUE ary, long i, VALUE vmin)
6070 const long n = RARRAY_LEN(ary);
6071 RUBY_ASSERT(i > 0 && i < n);
6072 RUBY_ASSERT(STRING_P(vmin));
6074 VALUE a;
6075 for (; i < n; ++i) {
6076 a = RARRAY_AREF(ary, i);
6078 if (STRING_P(a)) {
6079 if (rb_str_cmp(vmin, a) > 0) {
6080 vmin = a;
6083 else {
6084 return ary_min_generic(ary, i, vmin);
6088 return vmin;
6092 * call-seq:
6093 * array.min -> element
6094 * array.min { |a, b| ... } -> element
6095 * array.min(n) -> new_array
6096 * array.min(n) { |a, b| ... } -> new_array
6098 * Returns one of the following:
6100 * - The minimum-valued element from +self+.
6101 * - A new +Array+ of minimum-valued elements selected from +self+.
6103 * When no block is given, each element in +self+ must respond to method <tt><=></tt>
6104 * with an Integer.
6106 * With no argument and no block, returns the element in +self+
6107 * having the minimum value per method <tt><=></tt>:
6109 * [0, 1, 2].min # => 0
6111 * With Integer argument +n+ and no block, returns a new +Array+ with at most +n+ elements,
6112 * in ascending order per method <tt><=></tt>:
6114 * [0, 1, 2, 3].min(3) # => [0, 1, 2]
6115 * [0, 1, 2, 3].min(6) # => [0, 1, 2, 3]
6117 * When a block is given, the block must return an Integer.
6119 * With a block and no argument, calls the block <tt>self.size-1</tt> times to compare elements;
6120 * returns the element having the minimum value per the block:
6122 * ['0', '00', '000'].min { |a, b| a.size <=> b.size } # => "0"
6124 * With an argument +n+ and a block, returns a new +Array+ with at most +n+ elements,
6125 * in ascending order per the block:
6127 * ['0', '00', '000'].min(2) {|a, b| a.size <=> b.size } # => ["0", "00"]
6130 static VALUE
6131 rb_ary_min(int argc, VALUE *argv, VALUE ary)
6133 VALUE result = Qundef, v;
6134 VALUE num;
6135 long i;
6137 if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
6138 return rb_nmin_run(ary, num, 0, 0, 1);
6140 const long n = RARRAY_LEN(ary);
6141 if (rb_block_given_p()) {
6142 for (i = 0; i < RARRAY_LEN(ary); i++) {
6143 v = RARRAY_AREF(ary, i);
6144 if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) {
6145 result = v;
6149 else if (n > 0) {
6150 result = RARRAY_AREF(ary, 0);
6151 if (n > 1) {
6152 if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
6153 return ary_min_opt_fixnum(ary, 1, result);
6155 else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
6156 return ary_min_opt_string(ary, 1, result);
6158 else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
6159 return ary_min_opt_float(ary, 1, result);
6161 else {
6162 return ary_min_generic(ary, 1, result);
6166 if (UNDEF_P(result)) return Qnil;
6167 return result;
6171 * call-seq:
6172 * array.minmax -> [min_val, max_val]
6173 * array.minmax {|a, b| ... } -> [min_val, max_val]
6175 * Returns a new 2-element +Array+ containing the minimum and maximum values
6176 * from +self+, either per method <tt><=></tt> or per a given block:.
6178 * When no block is given, each element in +self+ must respond to method <tt><=></tt>
6179 * with an Integer;
6180 * returns a new 2-element +Array+ containing the minimum and maximum values
6181 * from +self+, per method <tt><=></tt>:
6183 * [0, 1, 2].minmax # => [0, 2]
6185 * When a block is given, the block must return an Integer;
6186 * the block is called <tt>self.size-1</tt> times to compare elements;
6187 * returns a new 2-element +Array+ containing the minimum and maximum values
6188 * from +self+, per the block:
6190 * ['0', '00', '000'].minmax {|a, b| a.size <=> b.size } # => ["0", "000"]
6193 static VALUE
6194 rb_ary_minmax(VALUE ary)
6196 if (rb_block_given_p()) {
6197 return rb_call_super(0, NULL);
6199 return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary));
6202 static int
6203 push_value(st_data_t key, st_data_t val, st_data_t ary)
6205 rb_ary_push((VALUE)ary, (VALUE)val);
6206 return ST_CONTINUE;
6210 * call-seq:
6211 * array.uniq! -> self or nil
6212 * array.uniq! {|element| ... } -> self or nil
6214 * Removes duplicate elements from +self+, the first occurrence always being retained;
6215 * returns +self+ if any elements removed, +nil+ otherwise.
6217 * With no block given, identifies and removes elements using method <tt>eql?</tt>
6218 * to compare.
6220 * Returns +self+ if any elements removed:
6222 * a = [0, 0, 1, 1, 2, 2]
6223 * a.uniq! # => [0, 1, 2]
6225 * Returns +nil+ if no elements removed.
6227 * With a block given, calls the block for each element;
6228 * identifies (using method <tt>eql?</tt>) and removes
6229 * elements for which the block returns duplicate values.
6231 * Returns +self+ if any elements removed:
6233 * a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb']
6234 * a.uniq! {|element| element.size } # => ['a', 'aa', 'aaa']
6236 * Returns +nil+ if no elements removed.
6238 static VALUE
6239 rb_ary_uniq_bang(VALUE ary)
6241 VALUE hash;
6242 long hash_size;
6244 rb_ary_modify_check(ary);
6245 if (RARRAY_LEN(ary) <= 1)
6246 return Qnil;
6247 if (rb_block_given_p())
6248 hash = ary_make_hash_by(ary);
6249 else
6250 hash = ary_make_hash(ary);
6252 hash_size = RHASH_SIZE(hash);
6253 if (RARRAY_LEN(ary) == hash_size) {
6254 return Qnil;
6256 rb_ary_modify_check(ary);
6257 ARY_SET_LEN(ary, 0);
6258 if (ARY_SHARED_P(ary)) {
6259 rb_ary_unshare(ary);
6260 FL_SET_EMBED(ary);
6262 ary_resize_capa(ary, hash_size);
6263 rb_hash_foreach(hash, push_value, ary);
6265 return ary;
6269 * call-seq:
6270 * array.uniq -> new_array
6271 * array.uniq {|element| ... } -> new_array
6273 * Returns a new +Array+ containing those elements from +self+ that are not duplicates,
6274 * the first occurrence always being retained.
6276 * With no block given, identifies and omits duplicates using method <tt>eql?</tt>
6277 * to compare:
6279 * a = [0, 0, 1, 1, 2, 2]
6280 * a.uniq # => [0, 1, 2]
6282 * With a block given, calls the block for each element;
6283 * identifies (using method <tt>eql?</tt>) and omits duplicate values,
6284 * that is, those elements for which the block returns the same value:
6286 * a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb']
6287 * a.uniq {|element| element.size } # => ["a", "aa", "aaa"]
6291 static VALUE
6292 rb_ary_uniq(VALUE ary)
6294 VALUE hash, uniq;
6296 if (RARRAY_LEN(ary) <= 1) {
6297 hash = 0;
6298 uniq = rb_ary_dup(ary);
6300 else if (rb_block_given_p()) {
6301 hash = ary_make_hash_by(ary);
6302 uniq = rb_hash_values(hash);
6304 else {
6305 hash = ary_make_hash(ary);
6306 uniq = rb_hash_values(hash);
6309 return uniq;
6313 * call-seq:
6314 * compact! -> self or nil
6316 * Removes all +nil+ elements from +self+;
6317 * Returns +self+ if any elements are removed, +nil+ otherwise:
6319 * a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
6320 * a.compact! # => [0, false, "", [], {}]
6321 * a # => [0, false, "", [], {}]
6322 * a.compact! # => nil
6324 * Related: Array#compact;
6325 * see also {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
6328 static VALUE
6329 rb_ary_compact_bang(VALUE ary)
6331 VALUE *p, *t, *end;
6332 long n;
6334 rb_ary_modify(ary);
6335 p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
6336 end = p + RARRAY_LEN(ary);
6338 while (t < end) {
6339 if (NIL_P(*t)) t++;
6340 else *p++ = *t++;
6342 n = p - RARRAY_CONST_PTR(ary);
6343 if (RARRAY_LEN(ary) == n) {
6344 return Qnil;
6346 ary_resize_smaller(ary, n);
6348 return ary;
6352 * call-seq:
6353 * compact -> new_array
6355 * Returns a new array containing only the non-+nil+ elements from +self+;
6356 * element order is preserved:
6358 * a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
6359 * a.compact # => [0, false, "", [], {}]
6361 * Related: Array#compact!.
6364 static VALUE
6365 rb_ary_compact(VALUE ary)
6367 ary = rb_ary_dup(ary);
6368 rb_ary_compact_bang(ary);
6369 return ary;
6373 * call-seq:
6374 * count -> integer
6375 * count(object) -> integer
6376 * count {|element| ... } -> integer
6378 * Returns a count of specified elements.
6380 * With no argument and no block, returns the count of all elements:
6382 * [0, :one, 'two', 3, 3.0].count # => 5
6384 * With argument +object+ given, returns the count of elements <tt>==</tt> to +object+:
6386 * [0, :one, 'two', 3, 3.0].count(3) # => 2
6388 * With no argument and a block given, calls the block with each element;
6389 * returns the count of elements for which the block returns a truthy value:
6391 * [0, 1, 2, 3].count {|element| element > 1 } # => 2
6393 * With argument +object+ and a block given, issues a warning, ignores the block,
6394 * and returns the count of elements <tt>==</tt> to +object+.
6396 * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
6399 static VALUE
6400 rb_ary_count(int argc, VALUE *argv, VALUE ary)
6402 long i, n = 0;
6404 if (rb_check_arity(argc, 0, 1) == 0) {
6405 VALUE v;
6407 if (!rb_block_given_p())
6408 return LONG2NUM(RARRAY_LEN(ary));
6410 for (i = 0; i < RARRAY_LEN(ary); i++) {
6411 v = RARRAY_AREF(ary, i);
6412 if (RTEST(rb_yield(v))) n++;
6415 else {
6416 VALUE obj = argv[0];
6418 if (rb_block_given_p()) {
6419 rb_warn("given block not used");
6421 for (i = 0; i < RARRAY_LEN(ary); i++) {
6422 if (rb_equal(RARRAY_AREF(ary, i), obj)) n++;
6426 return LONG2NUM(n);
6429 static VALUE
6430 flatten(VALUE ary, int level)
6432 long i;
6433 VALUE stack, result, tmp = 0, elt;
6434 VALUE memo = Qfalse;
6436 for (i = 0; i < RARRAY_LEN(ary); i++) {
6437 elt = RARRAY_AREF(ary, i);
6438 tmp = rb_check_array_type(elt);
6439 if (!NIL_P(tmp)) {
6440 break;
6443 if (i == RARRAY_LEN(ary)) {
6444 return ary;
6447 result = ary_new(0, RARRAY_LEN(ary));
6448 ary_memcpy(result, 0, i, RARRAY_CONST_PTR(ary));
6449 ARY_SET_LEN(result, i);
6451 stack = ary_new(0, ARY_DEFAULT_SIZE);
6452 rb_ary_push(stack, ary);
6453 rb_ary_push(stack, LONG2NUM(i + 1));
6455 if (level < 0) {
6456 memo = rb_obj_hide(rb_ident_hash_new());
6457 rb_hash_aset(memo, ary, Qtrue);
6458 rb_hash_aset(memo, tmp, Qtrue);
6461 ary = tmp;
6462 i = 0;
6464 while (1) {
6465 while (i < RARRAY_LEN(ary)) {
6466 elt = RARRAY_AREF(ary, i++);
6467 if (level >= 0 && RARRAY_LEN(stack) / 2 >= level) {
6468 rb_ary_push(result, elt);
6469 continue;
6471 tmp = rb_check_array_type(elt);
6472 if (RBASIC(result)->klass) {
6473 if (RTEST(memo)) {
6474 rb_hash_clear(memo);
6476 rb_raise(rb_eRuntimeError, "flatten reentered");
6478 if (NIL_P(tmp)) {
6479 rb_ary_push(result, elt);
6481 else {
6482 if (memo) {
6483 if (rb_hash_aref(memo, tmp) == Qtrue) {
6484 rb_hash_clear(memo);
6485 rb_raise(rb_eArgError, "tried to flatten recursive array");
6487 rb_hash_aset(memo, tmp, Qtrue);
6489 rb_ary_push(stack, ary);
6490 rb_ary_push(stack, LONG2NUM(i));
6491 ary = tmp;
6492 i = 0;
6495 if (RARRAY_LEN(stack) == 0) {
6496 break;
6498 if (memo) {
6499 rb_hash_delete(memo, ary);
6501 tmp = rb_ary_pop(stack);
6502 i = NUM2LONG(tmp);
6503 ary = rb_ary_pop(stack);
6506 if (memo) {
6507 rb_hash_clear(memo);
6510 RBASIC_SET_CLASS(result, rb_cArray);
6511 return result;
6515 * call-seq:
6516 * array.flatten! -> self or nil
6517 * array.flatten!(level) -> self or nil
6519 * Replaces each nested +Array+ in +self+ with the elements from that +Array+;
6520 * returns +self+ if any changes, +nil+ otherwise.
6522 * With non-negative Integer argument +level+, flattens recursively through +level+ levels:
6524 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6525 * a.flatten!(1) # => [0, 1, [2, 3], 4, 5]
6526 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6527 * a.flatten!(2) # => [0, 1, 2, 3, 4, 5]
6528 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6529 * a.flatten!(3) # => [0, 1, 2, 3, 4, 5]
6530 * [0, 1, 2].flatten!(1) # => nil
6532 * With no argument, a +nil+ argument, or with negative argument +level+, flattens all levels:
6534 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6535 * a.flatten! # => [0, 1, 2, 3, 4, 5]
6536 * [0, 1, 2].flatten! # => nil
6537 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6538 * a.flatten!(-1) # => [0, 1, 2, 3, 4, 5]
6539 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6540 * a.flatten!(-2) # => [0, 1, 2, 3, 4, 5]
6541 * [0, 1, 2].flatten!(-1) # => nil
6545 static VALUE
6546 rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
6548 int mod = 0, level = -1;
6549 VALUE result, lv;
6551 lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil);
6552 rb_ary_modify_check(ary);
6553 if (!NIL_P(lv)) level = NUM2INT(lv);
6554 if (level == 0) return Qnil;
6556 result = flatten(ary, level);
6557 if (result == ary) {
6558 return Qnil;
6560 if (!(mod = ARY_EMBED_P(result))) rb_ary_freeze(result);
6561 rb_ary_replace(ary, result);
6562 if (mod) ARY_SET_EMBED_LEN(result, 0);
6564 return ary;
6568 * call-seq:
6569 * array.flatten -> new_array
6570 * array.flatten(level) -> new_array
6572 * Returns a new +Array+ that is a recursive flattening of +self+:
6573 * - Each non-Array element is unchanged.
6574 * - Each +Array+ is replaced by its individual elements.
6576 * With non-negative Integer argument +level+, flattens recursively through +level+ levels:
6578 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6579 * a.flatten(0) # => [0, [1, [2, 3], 4], 5]
6580 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6581 * a.flatten(1) # => [0, 1, [2, 3], 4, 5]
6582 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6583 * a.flatten(2) # => [0, 1, 2, 3, 4, 5]
6584 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6585 * a.flatten(3) # => [0, 1, 2, 3, 4, 5]
6587 * With no argument, a +nil+ argument, or with negative argument +level+, flattens all levels:
6589 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6590 * a.flatten # => [0, 1, 2, 3, 4, 5]
6591 * [0, 1, 2].flatten # => [0, 1, 2]
6592 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6593 * a.flatten(-1) # => [0, 1, 2, 3, 4, 5]
6594 * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
6595 * a.flatten(-2) # => [0, 1, 2, 3, 4, 5]
6596 * [0, 1, 2].flatten(-1) # => [0, 1, 2]
6600 static VALUE
6601 rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
6603 int level = -1;
6604 VALUE result;
6606 if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) {
6607 level = NUM2INT(argv[0]);
6608 if (level == 0) return ary_make_shared_copy(ary);
6611 result = flatten(ary, level);
6612 if (result == ary) {
6613 result = ary_make_shared_copy(ary);
6616 return result;
6619 #define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)
6621 static VALUE
6622 rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
6624 long i, len;
6626 rb_ary_modify(ary);
6627 i = len = RARRAY_LEN(ary);
6628 RARRAY_PTR_USE(ary, ptr, {
6629 while (i) {
6630 long j = RAND_UPTO(i);
6631 VALUE tmp;
6632 if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) {
6633 rb_raise(rb_eRuntimeError, "modified during shuffle");
6635 tmp = ptr[--i];
6636 ptr[i] = ptr[j];
6637 ptr[j] = tmp;
6639 }); /* WB: no new reference */
6640 return ary;
6643 static VALUE
6644 rb_ary_shuffle(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
6646 ary = rb_ary_dup(ary);
6647 rb_ary_shuffle_bang(ec, ary, randgen);
6648 return ary;
6651 static const rb_data_type_t ary_sample_memo_type = {
6652 .wrap_struct_name = "ary_sample_memo",
6653 .function = {
6654 .dfree = (RUBY_DATA_FUNC)st_free_table,