1 /**********************************************************************
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"
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"
28 #include "ruby/encoding.h"
30 #include "ruby/util.h"
38 #include "ruby_assert.h"
41 VALUE rb_cArray_empty_frozen
;
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
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
67 /* for OPTIMIZED_CMP: */
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()
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); \
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); \
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); \
114 #define ARY_SET_EMBED_LEN(ary, n) do { \
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; \
120 #define ARY_SET_HEAP_LEN(ary, n) do { \
121 RUBY_ASSERT(!ARY_EMBED_P(ary)); \
122 RARRAY(ary)->as.heap.len = (n); \
124 #define ARY_SET_LEN(ary, n) do { \
125 if (ARY_EMBED_P(ary)) { \
126 ARY_SET_EMBED_LEN((ary), (n)); \
129 ARY_SET_HEAP_LEN((ary), (n)); \
131 RUBY_ASSERT(RARRAY_LEN(ary) == (n)); \
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); \
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)); \
144 RARRAY(ary)->as.heap.len += (n); \
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); \
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); \
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); \
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
);
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
);
189 ary_embed_size(long capa
)
191 return offsetof(struct RArray
, as
.ary
) + (sizeof(VALUE
) * capa
);
195 ary_embeddable_p(long capa
)
197 return rb_gc_size_allocatable_p(ary_embed_size(capa
));
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
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
));
215 rb_ary_size_as_embedded(VALUE ary
)
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
));
226 real_size
= sizeof(struct RArray
);
233 #define ary_verify(ary) ary_verify_(ary, __FILE__, __LINE__)
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
);
249 else if (ARY_EMBED_P(ary
)) {
250 RUBY_ASSERT(!ARY_SHARED_P(ary
));
251 RUBY_ASSERT(RARRAY_LEN(ary
) <= ary_embed_capa(ary
));
254 const VALUE
*ptr
= RARRAY_CONST_PTR(ary
);
255 long i
, len
= RARRAY_LEN(ary
);
257 if (len
> 1) len
= 1; /* check only HEAD */
258 for (i
=0; i
<len
; i
++) {
259 v
= ptr
[i
]; /* access check */
268 rb_ary_verify(VALUE ary
)
273 #define ary_verify(ary) ((void)0)
277 rb_ary_ptr_use_start(VALUE ary
)
280 FL_SET_RAW(ary
, RARRAY_PTR_IN_USE_FLAG
);
282 return (VALUE
*)RARRAY_CONST_PTR(ary
);
286 rb_ary_ptr_use_end(VALUE ary
)
289 FL_UNSET_RAW(ary
, RARRAY_PTR_IN_USE_FLAG
);
294 rb_mem_clear(VALUE
*mem
, long size
)
302 ary_mem_clear(VALUE ary
, long beg
, long size
)
304 RARRAY_PTR_USE(ary
, ptr
, {
305 rb_mem_clear(ptr
+ beg
, size
);
310 memfill(register VALUE
*mem
, register long size
, register VALUE val
)
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
);
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
);
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
]);
348 ary_memcpy(VALUE ary
, long beg
, long argc
, const VALUE
*argv
)
350 ary_memcpy0(ary
, beg
, argc
, argv
, ary
);
354 ary_heap_alloc_buffer(size_t capa
)
356 return ALLOC_N(VALUE
, capa
);
360 ary_heap_free_ptr(VALUE ary
, const VALUE
*ptr
, long size
)
362 ruby_sized_xfree((void *)ptr
, size
);
366 ary_heap_free(VALUE ary
)
368 ary_heap_free_ptr(ary
, ARY_HEAP_PTR(ary
), ARY_HEAP_SIZE(ary
));
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
));
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
);
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
));
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
);
413 ARY_SET_PTR(ary
, ptr
);
414 ARY_SET_HEAP_LEN(ary
, len
);
417 new_capa
= ary_heap_realloc(ary
, capacity
);
419 ARY_SET_CAPA(ary
, new_capa
);
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
);
432 ARY_SET_LEN(ary
, len
);
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
);
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;
466 ary_resize_capa(ary
, new_capa
);
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);
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
);
489 rb_ary_reset(VALUE ary
)
491 if (ARY_OWNS_HEAP_P(ary
)) {
494 else if (ARY_SHARED_P(ary
)) {
499 ARY_SET_EMBED_LEN(ary
, 0);
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);
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
);
522 RB_OBJ_WRITE(ary
, &RARRAY(ary
)->as
.heap
.aux
.shared_root
, shared_root
);
524 RB_DEBUG_COUNTER_INC(obj_ary_shared_create
);
528 rb_ary_modify_check(VALUE ary
)
530 rb_check_frozen(ary
);
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
);
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
);
563 VALUE
*ptr
= ary_heap_alloc_buffer(len
);
564 MEMCPY(ptr
, ARY_HEAP_PTR(ary
), VALUE
, len
);
566 ARY_SET_CAPA(ary
, len
);
567 ARY_SET_PTR(ary
, ptr
);
570 rb_gc_writebarrier_remember(ary
);
576 rb_ary_modify(VALUE ary
)
578 rb_ary_modify_check(ary
);
579 rb_ary_cancel_sharing(ary
);
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
;
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
);
600 ary_verify(shared_root
);
604 /* if array is shared, then it is likely it participate in push/shift pattern */
606 capa
= ARY_CAPA(ary
);
607 if (new_len
> capa
- (capa
>> 6)) {
608 ary_double_capa(ary
, new_len
);
619 rb_ary_modify_check(ary
);
621 capa
= ARY_CAPA(ary
);
622 if (new_len
> capa
) {
623 ary_double_capa(ary
, new_len
);
632 * array.freeze -> self
634 * Freezes +self+; returns +self+:
637 * a.frozen? # => false
639 * a.frozen? # => true
641 * An attempt to modify a frozen +Array+ raises FrozenError.
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
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
)) {
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),
686 * FL_SET_EMBED((VALUE)ary);
687 * ARY_SET_EMBED_LEN((VALUE)ary, 0);
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);
702 empty_ary_alloc(VALUE klass
)
704 RUBY_DTRACE_CREATE_HOOK(ARRAY
, 0);
705 return ary_alloc_embed(klass
, 0);
709 ary_new(VALUE klass
, long capa
)
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
);
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);
738 rb_ary_new_capa(long capa
)
740 return ary_new(rb_cArray
, capa
);
746 return rb_ary_new_capa(0);
750 (rb_ary_new_from_args
)(long n
, ...)
756 ary
= rb_ary_new2(n
);
759 for (i
=0; i
<n
; i
++) {
760 ARY_SET(ary
, i
, va_arg(ar
, VALUE
));
769 rb_ary_tmp_new_from_values(VALUE klass
, long n
, const VALUE
*elts
)
773 ary
= ary_new(klass
, n
);
775 ary_memcpy(ary
, 0, n
, elts
);
783 rb_ary_new_from_values(long n
, const VALUE
*elts
)
785 return rb_ary_tmp_new_from_values(rb_cArray
, n
, elts
);
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),
797 * FL_SET_EMBED((VALUE)ary);
798 * ARY_SET_EMBED_LEN((VALUE)ary, 0);
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
);
813 ec_ary_new(rb_execution_context_t
*ec
, VALUE klass
, long capa
)
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
);
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);
842 rb_ec_ary_new_from_values(rb_execution_context_t
*ec
, long n
, const VALUE
*elts
)
846 ary
= ec_ary_new(ec
, rb_cArray
, n
);
848 ary_memcpy(ary
, 0, n
, elts
);
856 rb_ary_hidden_new(long capa
)
858 VALUE ary
= ary_new(0, capa
);
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
);
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
);
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
;
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
;
905 return fake_ary
.basic
.flags
;
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
;
922 rb_ary_memsize(VALUE ary
)
924 if (ARY_OWNS_HEAP_P(ary
)) {
925 return ARY_CAPA(ary
) * sizeof(VALUE
);
933 ary_make_shared(VALUE ary
)
937 if (ARY_SHARED_P(ary
)) {
938 return ARY_SHARED_ROOT(ary
);
940 else if (ARY_SHARED_ROOT_P(ary
)) {
943 else if (OBJ_FROZEN(ary
)) {
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
));
961 ARY_SET_HEAP_LEN(ary
, len
);
962 ARY_SET_PTR(ary
, ptr
);
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
);
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
);
993 return rb_ary_increment_share(ary_make_shared(ary
));
998 rb_assoc_new(VALUE car
, VALUE cdr
)
1000 return rb_ary_new3(2, car
, cdr
);
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
1011 rb_check_array_type(VALUE ary
)
1013 return rb_check_convert_type_with_id(ary
, T_ARRAY
, "Array", idTo_ary
);
1017 rb_check_to_array(VALUE ary
)
1019 return rb_check_convert_type_with_id(ary
, T_ARRAY
, "Array", idTo_a
);
1023 rb_to_array(VALUE ary
)
1025 return rb_convert_type_with_id(ary
, T_ARRAY
, "Array", idTo_a
);
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].
1047 rb_ary_s_try_convert(VALUE dummy
, VALUE ary
)
1049 return rb_check_array_type(ary
);
1054 rb_ary_s_new(int argc
, VALUE
*argv
, VALUE klass
)
1058 if (klass
== rb_cArray
) {
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
);
1070 ary
= rb_class_new_instance_pass_kw(argc
, argv
, klass
);
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:
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 # => [{}, {}]
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 # => [{}, {}]
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].
1128 rb_ary_initialize(int argc
, VALUE
*argv
, VALUE 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");
1143 rb_scan_args(argc
, argv
, "02", &size
, &val
);
1144 if (argc
== 1 && !FIXNUM_P(size
)) {
1145 val
= rb_check_array_type(size
);
1147 rb_ary_replace(ary
, val
);
1152 len
= NUM2LONG(size
);
1153 /* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */
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 */
1162 ary_resize_capa(ary
, len
);
1163 if (rb_block_given_p()) {
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);
1175 ary_memfill(ary
, 0, len
, val
);
1176 ARY_SET_LEN(ary
, len
);
1182 * Returns a new array, populated with the given objects:
1184 * Array[1, 'a', /^A/] # => [1, "a", /^A/]
1186 * Array.[](1, 'a', /^A/) # => [1, "a", /^A/]
1188 * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
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
);
1204 rb_ary_store(VALUE ary
, long idx
, VALUE val
)
1206 long len
= RARRAY_LEN(ary
);
1211 rb_raise(rb_eIndexError
, "index %ld too small for array; minimum: %ld",
1215 else if (idx
>= ARY_MAX_SIZE
) {
1216 rb_raise(rb_eIndexError
, "index %ld too big", idx
);
1220 if (idx
>= ARY_CAPA(ary
)) {
1221 ary_double_capa(ary
, idx
);
1224 ary_mem_clear(ary
, len
, idx
- len
+ 1);
1228 ARY_SET_LEN(ary
, idx
+ 1);
1230 ARY_SET(ary
, idx
, val
);
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
);
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
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
);
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);
1288 else if (step
< 0 && step
< -len
) {
1292 long ustep
= (step
< 0) ? -step
: step
;
1293 len
= roomof(len
, ustep
);
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
]);
1307 ARY_SET_EMBED_LEN(result
, len
);
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
]);
1318 ARY_SET_LEN(result
, len
);
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
1337 ary_take_first_or_last_n(VALUE ary
, long n
, enum ary_take_pos_flags last
)
1339 long len
= RARRAY_LEN(ary
);
1346 rb_raise(rb_eArgError
, "negative array size");
1351 return ary_make_partial(ary
, rb_cArray
, offset
, n
);
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
);
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].
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);
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
);
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].
1422 rb_ary_push_m(int argc
, VALUE
*argv
, VALUE ary
)
1424 return rb_ary_cat(ary
, argv
, argc
);
1428 rb_ary_pop(VALUE ary
)
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);
1441 ARY_SET_LEN(ary
, n
);
1443 return RARRAY_AREF(ary
, n
);
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]
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.
1478 rb_ary_pop_m(int argc
, VALUE
*argv
, VALUE ary
)
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
));
1494 rb_ary_shift(VALUE ary
)
1497 long len
= RARRAY_LEN(ary
);
1500 rb_ary_modify_check(ary
);
1504 top
= RARRAY_AREF(ary
, 0);
1506 rb_ary_behead(ary
, 1);
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]
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']
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.
1545 rb_ary_shift_m(int argc
, VALUE
*argv
, VALUE ary
)
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
);
1563 rb_ary_behead(VALUE ary
, long n
)
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
);
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
);
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
;
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
)));
1609 return ARY_SHARED_ROOT(ary
);
1613 ary_modify_for_unshift(VALUE ary
, int argc
)
1615 long len
= RARRAY_LEN(ary
);
1616 long new_len
= len
+ argc
;
1618 const VALUE
*head
, *sharedp
;
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
)) {
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
);
1639 RARRAY_PTR_USE(ary
, ptr
, {
1640 MEMMOVE(ptr
+ argc
, ptr
, VALUE
, len
);
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
);
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
);
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
);
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.
1693 rb_ary_unshift_m(int argc
, VALUE
*argv
, VALUE ary
)
1695 long len
= RARRAY_LEN(ary
);
1699 rb_ary_modify_check(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
);
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 */
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
) {
1724 return RARRAY_AREF(ary
, offset
);
1728 rb_ary_entry(VALUE ary
, long offset
)
1730 return rb_ary_entry_internal(ary
, offset
);
1734 rb_ary_subseq_step(VALUE ary
, long beg
, long len
, long step
)
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
) {
1746 if (len
== 0) return ary_new(klass
, 0);
1748 rb_raise(rb_eArgError
, "slice step cannot be zero");
1750 return ary_make_partial(ary
, klass
, beg
, len
);
1752 return ary_make_partial_step(ary
, klass
, beg
, len
, step
);
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
);
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+.
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]
1798 * a # => [:foo, "bar", 2]
1800 * If +index+ is negative, counts backwards from the end of +self+:
1802 * a = [:foo, 'bar', 2]
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]
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]
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]
1859 * When a single Enumerator::ArithmeticSequence argument +aseq+ is given,
1860 * returns an +Array+ of elements corresponding to the indexes produced by
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)
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):
1882 * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
1886 rb_ary_aref(int argc
, const VALUE
*argv
, VALUE ary
)
1888 rb_check_arity(argc
, 1, 2);
1890 return rb_ary_aref2(ary
, argv
[0], argv
[1]);
1892 return rb_ary_aref1(ary
, argv
[0]);
1896 rb_ary_aref2(VALUE ary
, VALUE b
, VALUE e
)
1898 long beg
= NUM2LONG(b
);
1899 long len
= NUM2LONG(e
);
1901 beg
+= RARRAY_LEN(ary
);
1903 return rb_ary_subseq(ary
, beg
, len
);
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)) {
1922 return rb_ary_subseq_step(ary
, beg
, len
, step
);
1925 return rb_ary_entry(ary
, NUM2LONG(arg
));
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]
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].
1953 rb_ary_at(VALUE ary
, VALUE pos
)
1955 return rb_ary_entry(ary
, NUM2LONG(pos
));
1960 rb_ary_first(int argc
, VALUE
*argv
, VALUE ary
)
1963 if (RARRAY_LEN(ary
) == 0) return Qnil
;
1964 return RARRAY_AREF(ary
, 0);
1967 return ary_take_first_or_last(argc
, argv
, ary
, ARY_TAKE_FIRST
);
1973 ary_first(VALUE self
)
1975 return (RARRAY_LEN(self
) == 0) ? Qnil
: RARRAY_AREF(self
, 0);
1979 ary_last(VALUE self
)
1981 long len
= RARRAY_LEN(self
);
1982 return (len
== 0) ? Qnil
: RARRAY_AREF(self
, len
-1);
1986 rb_ary_last(int argc
, const VALUE
*argv
, VALUE ary
) // used by parse.y
1989 return ary_last(ary
);
1992 return ary_take_first_or_last(argc
, argv
, ary
, ARY_TAKE_LAST
);
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"
2034 rb_ary_fetch(int argc
, VALUE
*argv
, VALUE ary
)
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
);
2048 idx
+= RARRAY_LEN(ary
);
2050 if (idx
< 0 || RARRAY_LEN(ary
) <= idx
) {
2051 if (block_given
) return rb_yield(pos
);
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
));
2058 return RARRAY_AREF(ary
, idx
);
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]
2091 * e # => #<Enumerator: [:foo, "bar", 2]:index>
2092 * e.each {|element| element == 'bar' } # => 1
2098 rb_ary_index(int argc
, VALUE
*argv
, VALUE ary
)
2104 RETURN_ENUMERATOR(ary
, 0, 0);
2105 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
2106 if (RTEST(rb_yield(RARRAY_AREF(ary
, i
)))) {
2112 rb_check_arity(argc
, 0, 1);
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
)) {
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']
2152 * e # => #<Enumerator: [:foo, "bar", 2, "bar"]:rindex>
2153 * e.each {|element| element == 'bar' } # => 3
2159 rb_ary_rindex(int argc
, VALUE
*argv
, VALUE ary
)
2162 long i
= RARRAY_LEN(ary
), len
;
2165 RETURN_ENUMERATOR(ary
, 0, 0);
2167 if (RTEST(rb_yield(RARRAY_AREF(ary
, i
))))
2169 if (i
> (len
= RARRAY_LEN(ary
))) {
2175 rb_check_arity(argc
, 0, 1);
2177 if (rb_block_given_p())
2178 rb_warn("given block not used");
2180 VALUE e
= RARRAY_AREF(ary
, i
);
2181 if (rb_equal(e
, val
)) {
2184 if (i
> RARRAY_LEN(ary
)) {
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
);
2201 rb_ary_splice(VALUE ary
, long beg
, long len
, const VALUE
*rptr
, long rlen
)
2206 if (len
< 0) rb_raise(rb_eIndexError
, "negative length (%ld)", len
);
2207 olen
= RARRAY_LEN(ary
);
2211 rb_raise(rb_eIndexError
, "index %ld too small for array; minimum: %ld",
2215 if (olen
< len
|| olen
< beg
+ len
) {
2220 const VALUE
*optr
= RARRAY_CONST_PTR(ary
);
2221 rofs
= (rptr
>= optr
&& rptr
< optr
+ olen
) ? rptr
- optr
: -1;
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 */
2231 ary_mem_clear(ary
, olen
, beg
- olen
);
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
);
2241 if (olen
- len
> ARY_MAX_SIZE
- rlen
) {
2242 rb_raise(rb_eIndexError
, "index %ld too big", olen
+ rlen
- len
);
2245 alen
= olen
+ rlen
- len
;
2246 if (alen
>= ARY_CAPA(ary
)) {
2247 ary_double_capa(ary
, alen
);
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
);
2258 rb_gc_writebarrier_remember(ary
);
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
));
2276 rb_ary_set_len(VALUE ary
, long len
)
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
);
2291 rb_ary_resize(VALUE ary
, long len
)
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
);
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
);
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
);
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
);
2335 ary_aset_by_rb_ary_store(VALUE ary
, long key
, VALUE val
)
2337 rb_ary_store(ary
, key
, val
);
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
));
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+.
2360 * a_orig = [:foo, 'bar', 2]
2362 * # With argument index.
2364 * a[0] = 'foo' # => "foo"
2365 * a # => ["foo", "bar", 2]
2367 * a[7] = 'foo' # => "foo"
2368 * a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
2370 * # With arguments start and length.
2372 * a[0, 2] = 'foo' # => "foo"
2375 * a[6, 50] = 'foo' # => "foo"
2376 * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
2378 * # With argument range.
2380 * a[0..1] = 'foo' # => "foo"
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"
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"
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].
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
);
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]);
2521 * array.insert(index, *objects) -> self
2523 * Inserts given +objects+ before or after the element at Integer index +offset+;
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]
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]
2556 rb_ary_insert(int argc
, VALUE
*argv
, VALUE ary
)
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
;
2565 pos
= RARRAY_LEN(ary
);
2568 long minpos
= -RARRAY_LEN(ary
) - 1;
2570 rb_raise(rb_eIndexError
, "index %ld too small for array; minimum: %ld",
2575 rb_ary_splice(ary
, pos
, 0, argv
+ 1, argc
- 1);
2580 rb_ary_length(VALUE ary
);
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.
2591 ary_fetch_next(VALUE self
, VALUE
*index
, VALUE
*value
)
2593 long i
= NUM2LONG(*index
);
2594 if (i
>= RARRAY_LEN(self
)) {
2597 *value
= RARRAY_AREF(self
, i
);
2598 *index
= LONG2NUM(i
+ 1);
2603 rb_ary_each(VALUE 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
));
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;
2624 * a = [:foo, 'bar', 2]
2625 * a.each_index {|index| puts "#{index} #{a[index]}" }
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 }
2643 * When no block given, returns a new Enumerator:
2645 * a = [:foo, 'bar', 2]
2647 * e # => #<Enumerator: [:foo, "bar", 2]:each_index>
2648 * a1 = e.each {|index| puts "#{index} #{a[index]}"}
2656 * Related: #each, #reverse_each.
2660 rb_ary_each_index(VALUE ary
)
2663 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
2665 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
2666 rb_yield(LONG2NUM(i
));
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;
2681 * a = [:foo, 'bar', 2]
2682 * a.reverse_each {|element| puts "#{element.class} #{element}" }
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') }
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}" }
2713 * Related: #each, #each_index.
2717 rb_ary_reverse_each(VALUE ary
)
2721 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
2722 len
= RARRAY_LEN(ary
);
2725 rb_yield(RARRAY_AREF(ary
, len
));
2726 nlen
= RARRAY_LEN(ary
);
2736 * array.length -> an_integer
2738 * Returns the count of elements in +self+.
2742 rb_ary_length(VALUE ary
)
2744 long len
= RARRAY_LEN(ary
);
2745 return LONG2NUM(len
);
2750 * array.empty? -> true or false
2752 * Returns +true+ if the count of elements in +self+ is zero,
2753 * +false+ otherwise.
2757 rb_ary_empty_p(VALUE ary
)
2759 return RBOOL(RARRAY_LEN(ary
) == 0);
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
);
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
);
2786 recursive_join(VALUE obj
, VALUE argp
, int recur
)
2788 VALUE
*arg
= (VALUE
*)argp
;
2791 VALUE result
= arg
[2];
2792 int *first
= (int *)arg
[3];
2795 rb_raise(rb_eArgError
, "recursive array join");
2798 ary_join_1(obj
, ary
, sep
, 0, result
, first
);
2804 ary_join_0(VALUE ary
, VALUE sep
, long max
, VALUE result
)
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
);
2821 ary_join_1_str(VALUE dst
, VALUE src
, int *first
)
2823 rb_str_buf_append(dst
, src
);
2825 rb_enc_copy(dst
, src
);
2831 ary_join_1_ary(VALUE obj
, VALUE ary
, VALUE sep
, VALUE result
, VALUE val
, int *first
)
2834 rb_raise(rb_eArgError
, "recursive array join");
2843 args
[3] = (VALUE
)first
;
2844 rb_exec_recursive(recursive_join
, obj
, (VALUE
)args
);
2849 ary_join_1(VALUE obj
, VALUE ary
, VALUE sep
, long i
, VALUE result
, int *first
)
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
);
2871 ary_join_1_str(result
, rb_obj_as_string(val
), first
);
2877 rb_ary_join(VALUE ary
, VALUE sep
)
2880 VALUE val
, tmp
, result
;
2882 if (RARRAY_LEN(ary
) == 0) return rb_usascii_str_new(0, 0);
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
) {
2894 long n
= RARRAY_LEN(ary
);
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
);
2900 ary_join_1(ary
, ary
, sep
, i
, result
, &first
);
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
);
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]
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"
2944 rb_ary_join_m(int argc
, VALUE
*argv
, VALUE ary
)
2948 if (rb_check_arity(argc
, 0, 1) == 0 || NIL_P(sep
= argv
[0])) {
2951 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED
, "$, is set to non-nil value");
2955 return rb_ary_join(ary
, sep
);
2959 inspect_ary(VALUE ary
, VALUE dummy
, int recur
)
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
, "]");
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]"
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);
2996 rb_ary_to_s(VALUE ary
)
2998 return rb_ary_inspect(ary
);
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
3017 * a1 # => ["foo", "bar", "two"]
3018 * a1.class # => Array # Not MyArray
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
);
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:
3052 * a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
3054 * h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
3059 rb_ary_to_h(VALUE ary
)
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));
3084 * array.to_ary -> self
3090 rb_ary_to_ary_m(VALUE ary
)
3096 ary_reverse(VALUE
*p1
, VALUE
*p2
)
3106 rb_ary_reverse(VALUE ary
)
3109 long len
= RARRAY_LEN(ary
);
3113 RARRAY_PTR_USE(ary
, p1
, {
3114 p2
= p1
+ len
- 1; /* points last item */
3115 ary_reverse(p1
, p2
);
3116 }); /* WB: no new reference */
3123 * array.reverse! -> self
3125 * Reverses +self+ in place:
3127 * a = ['foo', 'bar', 'two']
3128 * a.reverse! # => ["two", "bar", "foo"]
3133 rb_ary_reverse_bang(VALUE ary
)
3135 return rb_ary_reverse(ary
);
3140 * array.reverse -> new_array
3142 * Returns a new +Array+ with the elements of +self+ in reverse order:
3144 * a = ['foo', 'bar', 'two']
3146 * a1 # => ["two", "bar", "foo"]
3151 rb_ary_reverse_m(VALUE ary
)
3153 long len
= RARRAY_LEN(ary
);
3154 VALUE dup
= rb_ary_new2(len
);
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
));
3166 rotate_count(long cnt
, long len
)
3168 return (cnt
< 0) ? (len
- (~cnt
% len
) - 1) : (cnt
% len
);
3172 ary_rotate_ptr(VALUE
*ptr
, long len
, long cnt
)
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));
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
);
3193 rb_ary_rotate(VALUE ary
, long cnt
)
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
));
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]
3224 * a # => [2, :foo, "bar"]
3226 * If +count+ is large, uses <tt>count % array.size</tt> as the count:
3228 * a = [:foo, 'bar', 2]
3230 * a # => [2, :foo, "bar"]
3232 * If +count+ is zero, returns +self+ unmodified:
3234 * a = [:foo, 'bar', 2]
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]
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]
3249 * a # => ["bar", 2, :foo]
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
);
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']
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]
3281 * a1 # => [2, :foo, "bar"]
3283 * If +count+ is large, uses <tt>count % array.size</tt> as the count:
3285 * a = [:foo, 'bar', 2]
3287 * a1 # => [2, :foo, "bar"]
3289 * If +count+ is zero, returns a copy of +self+, unmodified:
3291 * a = [:foo, 'bar', 2]
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]
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]
3306 * a1 # => ["bar", 2, :foo]
3311 rb_ary_rotate_m(int argc
, VALUE
*argv
, VALUE ary
)
3316 long cnt
= (rb_check_arity(argc
, 0, 1) ? NUM2LONG(argv
[0]) : 1);
3318 len
= RARRAY_LEN(ary
);
3319 rotated
= rb_ary_new2(len
);
3321 cnt
= rotate_count(cnt
, len
);
3322 ptr
= RARRAY_CONST_PTR(ary
);
3324 ary_memcpy(rotated
, 0, len
, ptr
+ cnt
);
3325 ary_memcpy(rotated
, len
, cnt
, ptr
);
3327 ARY_SET_LEN(rotated
, RARRAY_LEN(ary
));
3331 struct ary_sort_data
{
3337 sort_reentered(VALUE ary
)
3339 if (RBASIC(ary
)->klass
) {
3340 rb_raise(rb_eRuntimeError
, "sort reentered");
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
);
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
;
3365 retval
= rb_yield_values2(2, args
);
3366 n
= rb_cmpint(retval
, a
, b
);
3367 sort_returned(data
);
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
;
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;
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
);
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>
3408 * a = 'abcde'.split('').shuffle
3409 * a # => ["e", "b", "d", "a", "c"]
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+.
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"]
3440 rb_ary_sort_bang(VALUE 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
);
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 */
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
);
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
));
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
));
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
);
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
);
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 */
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>
3511 * a = 'abcde'.split('').shuffle
3512 * a # => ["e", "b", "d", "a", "c"]
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+.
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.
3544 rb_ary_sort(VALUE ary
)
3546 ary
= rb_ary_dup(ary
);
3547 rb_ary_sort_bang(ary
);
3551 static VALUE
rb_ary_bsearch_index(VALUE ary
);
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].
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
;
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].
3591 rb_ary_bsearch_index(VALUE ary
)
3593 long low
= 0, high
= RARRAY_LEN(ary
), mid
;
3594 int smaller
= 0, satisfied
= 0;
3597 RETURN_ENUMERATOR(ary
, 0, 0);
3598 while (low
< high
) {
3599 mid
= low
+ ((high
- low
) / 2);
3600 val
= rb_ary_entry(ary
, mid
);
3603 if (v
== INT2FIX(0)) return INT2FIX(mid
);
3604 smaller
= (SIGNED_VALUE
)v
< 0; /* Fixnum preserves its sign-bit */
3606 else if (v
== Qtrue
) {
3610 else if (!RTEST(v
)) {
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;
3622 rb_raise(rb_eTypeError
, "wrong argument type %"PRIsVALUE
3623 " (must be numeric, true, false or nil)",
3633 if (!satisfied
) return Qnil
;
3634 return INT2FIX(low
);
3639 sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i
, dummy
))
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!>
3671 rb_ary_sort_by_bang(VALUE ary
)
3675 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
3677 sorted
= rb_block_call(ary
, rb_intern("sort_by"), 0, 0, sort_by_i
, 0);
3678 rb_ary_replace(ary
, sorted
);
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].
3704 rb_ary_collect(VALUE ary
)
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
)));
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;
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].
3739 rb_ary_collect_bang(VALUE ary
)
3743 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
3745 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
3746 rb_ary_store(ary
, i
, rb_yield(RARRAY_AREF(ary
, i
)));
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
])));
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
));
3769 rb_ary_resize(result
, RARRAY_LEN(result
) + (beg
+ len
) - j
);
3772 rb_ary_push(result
, (*func
)(obj
, NUM2LONG(argv
[i
])));
3778 append_values_at_single(VALUE result
, VALUE ary
, long olen
, VALUE idx
)
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)) {
3787 const VALUE
*const src
= RARRAY_CONST_PTR(ary
);
3788 const long end
= beg
+ len
;
3789 const long prevlen
= RARRAY_LEN(result
);
3791 rb_ary_cat(result
, src
+ beg
, end
> olen
? olen
-beg
: len
);
3794 rb_ary_store(result
, prevlen
+ len
- 1, Qnil
);
3800 beg
= NUM2LONG(idx
);
3802 return rb_ary_push(result
, rb_ary_entry(ary
, beg
));
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]
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
]);
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>
3882 rb_ary_select(VALUE ary
)
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
));
3897 struct select_bang_arg
{
3903 select_bang_i(VALUE a
)
3905 volatile struct select_bang_arg
*arg
= (void *)a
;
3906 VALUE ary
= arg
->ary
;
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;
3913 rb_ary_store(ary
, i2
, v
);
3917 return (i1
== i2
) ? Qnil
: ary
;
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
) {
3933 RARRAY_PTR_USE(ary
, ptr
, {
3934 MEMMOVE(ptr
+ i2
, ptr
+ i1
, VALUE
, tail
);
3937 ARY_SET_LEN(ary
, i2
+ tail
);
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!>
3965 rb_ary_select_bang(VALUE ary
)
3967 struct select_bang_arg args
;
3969 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
3973 args
.len
[0] = args
.len
[1] = 0;
3974 return rb_ensure(select_bang_i
, (VALUE
)&args
, select_bang_ensure
, (VALUE
)&args
);
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>
3996 rb_ary_keep_if(VALUE ary
)
3998 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
3999 rb_ary_select_bang(ary
);
4004 ary_resize_smaller(VALUE ary
, long len
)
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);
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
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
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].
4054 rb_ary_delete(VALUE ary
, VALUE item
)
4059 for (i1
= i2
= 0; i1
< RARRAY_LEN(ary
); i1
++) {
4060 VALUE e
= RARRAY_AREF(ary
, i1
);
4062 if (rb_equal(e
, item
)) {
4067 rb_ary_store(ary
, i2
, e
);
4071 if (RARRAY_LEN(ary
) == i2
) {
4072 if (rb_block_given_p()) {
4073 return rb_yield(item
);
4078 ary_resize_smaller(ary
, i2
);
4085 rb_ary_delete_same(VALUE ary
, VALUE item
)
4089 for (i1
= i2
= 0; i1
< RARRAY_LEN(ary
); i1
++) {
4090 VALUE e
= RARRAY_AREF(ary
, i1
);
4096 rb_ary_store(ary
, i2
, e
);
4100 if (RARRAY_LEN(ary
) == i2
) {
4104 ary_resize_smaller(ary
, i2
);
4108 rb_ary_delete_at(VALUE ary
, long pos
)
4110 long len
= RARRAY_LEN(ary
);
4113 if (pos
>= len
) return Qnil
;
4116 if (pos
< 0) return Qnil
;
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);
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"
4142 * When +index+ is negative, counts backward from the end of the array:
4144 * a = [:foo, 'bar', 2]
4145 * a.delete_at(-2) # => "bar"
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].
4158 rb_ary_delete_at_m(VALUE ary
, VALUE pos
)
4160 return rb_ary_delete_at(ary
, NUM2LONG(pos
));
4164 ary_slice_bang_by_rb_ary_splice(VALUE ary
, long pos
, long len
)
4166 const long orig_len
= RARRAY_LEN(ary
);
4171 else if (pos
< -orig_len
) {
4177 else if (orig_len
< pos
) {
4180 if (orig_len
< pos
+ len
) {
4181 len
= orig_len
- pos
;
4184 return rb_ary_new2(0);
4187 VALUE arg2
= rb_ary_new4(len
, RARRAY_CONST_PTR(ary
)+pos
);
4188 rb_ary_splice(ary
, pos
, len
, 0, 0);
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"
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"]
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]
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]
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"]
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]
4263 rb_ary_slice_bang(int argc
, VALUE
*argv
, VALUE ary
)
4268 rb_ary_modify_check(ary
);
4269 rb_check_arity(argc
, 1, 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)) {
4282 return ary_slice_bang_by_rb_ary_splice(ary
, pos
, len
);
4292 return rb_ary_delete_at(ary
, NUM2LONG(arg1
));
4296 ary_reject(VALUE orig
, VALUE result
)
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
);
4311 reject_bang_i(VALUE a
)
4313 volatile struct select_bang_arg
*arg
= (void *)a
;
4314 VALUE ary
= arg
->ary
;
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;
4321 rb_ary_store(ary
, i2
, v
);
4325 return (i1
== i2
) ? Qnil
: ary
;
4329 ary_reject_bang(VALUE ary
)
4331 struct select_bang_arg args
;
4332 rb_ary_modify_check(ary
);
4334 args
.len
[0] = args
.len
[1] = 0;
4335 return rb_ensure(reject_bang_i
, (VALUE
)&args
, select_bang_ensure
, (VALUE
)&args
);
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!>
4360 rb_ary_reject_bang(VALUE ary
)
4362 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
4364 return ary_reject_bang(ary
);
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') }
4379 * Returns a new Enumerator if no block given:
4381 * a = [:foo, 'bar', 2]
4382 * a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
4387 rb_ary_reject(VALUE 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
;
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;
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].
4415 rb_ary_delete_if(VALUE ary
)
4418 RETURN_SIZED_ENUMERATOR(ary
, 0, 0, ary_enum_length
);
4419 ary_reject_bang(ary
);
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();
4434 take_items(VALUE obj
, long n
)
4436 VALUE result
= rb_check_array_type(obj
);
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)",
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>,
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]
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]
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]
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]
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
4514 rb_ary_zip(int argc
, VALUE
*argv
, VALUE ary
)
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();
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
);
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
));
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
);
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]]
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
));
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]
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
;
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. */
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
);
4669 * Removes all elements from +self+; returns +self+:
4671 * a = [:foo, 'bar', 2]
4674 * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
4678 rb_ary_clear(VALUE ary
)
4680 rb_ary_modify_check(ary
);
4681 if (ARY_SHARED_P(ary
)) {
4682 rb_ary_unshare(ary
);
4684 ARY_SET_EMBED_LEN(ary
, 0);
4687 ARY_SET_LEN(ary
, 0);
4688 if (ARY_DEFAULT_SIZE
* 2 < ARY_CAPA(ary
)) {
4689 ary_resize_capa(ary
, ARY_DEFAULT_SIZE
* 2);
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"]
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 */
4903 rb_scan_args(argc
, argv
, "12", &item
, &arg1
, &arg2
);
4908 len
= RARRAY_LEN(ary
);
4911 if (rb_range_beg_len(arg1
, &beg
, &len
, RARRAY_LEN(ary
), 1)) {
4916 beg
= NIL_P(arg1
) ? 0 : NUM2LONG(arg1
);
4918 beg
= RARRAY_LEN(ary
) + beg
;
4919 if (beg
< 0) beg
= 0;
4921 len
= NIL_P(arg2
) ? RARRAY_LEN(ary
) - beg
: NUM2LONG(arg2
);
4928 if (beg
>= ARY_MAX_SIZE
|| len
> ARY_MAX_SIZE
- beg
) {
4929 rb_raise(rb_eArgError
, "argument too big");
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
)) {
4944 for (i
=beg
; i
<end
; i
++) {
4945 v
= rb_yield(LONG2NUM(i
));
4946 if (i
>=RARRAY_LEN(ary
)) break;
4951 ary_memfill(ary
, beg
, len
, item
);
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].
4970 rb_ary_plus(VALUE x
, VALUE y
)
4973 long len
, xlen
, ylen
;
4976 xlen
= RARRAY_LEN(x
);
4977 ylen
= RARRAY_LEN(y
);
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
);
4988 ary_append(VALUE x
, VALUE y
)
4990 long n
= RARRAY_LEN(y
);
4992 rb_ary_splice(x
, RARRAY_LEN(x
), 0, RARRAY_CONST_PTR(y
), n
);
5000 * concat(*other_arrays) -> self
5002 * Adds to +self+ all elements from each array in +other_arrays+; returns +self+:
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].
5012 rb_ary_concat_multi(int argc
, VALUE
*argv
, VALUE ary
)
5014 rb_ary_modify_check(ary
);
5017 rb_ary_concat(ary
, argv
[0]);
5019 else if (argc
> 1) {
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
);
5033 rb_ary_concat(VALUE x
, VALUE y
)
5035 return ary_append(x
, to_ary(y
));
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+:
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}"
5057 rb_ary_times(VALUE ary
, VALUE times
)
5063 tmp
= rb_check_string_type(times
);
5065 return rb_ary_join(ary
, tmp
);
5068 len
= NUM2LONG(times
);
5070 ary2
= ary_new(rb_cArray
, 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
);
5087 ary_memcpy(ary2
, 0, t
, ptr
);
5088 while (t
<= len
/2) {
5089 ary_memcpy(ary2
, t
, t
, RARRAY_CONST_PTR(ary2
));
5093 ary_memcpy(ary2
, t
, len
-t
, RARRAY_CONST_PTR(ary2
));
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].
5117 rb_ary_assoc(VALUE ary
, VALUE key
)
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
))
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.
5147 rb_ary_rassoc(VALUE ary
, VALUE value
)
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
))
5163 recursive_equal(VALUE ary1
, VALUE ary2
, int recur
)
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
++) {
5177 if (rb_equal(*p1
, *p2
)) {
5178 len1
= RARRAY_LEN(ary1
);
5179 if (len1
!= RARRAY_LEN(ary2
))
5183 p1
= RARRAY_CONST_PTR(ary1
) + i
;
5184 p2
= RARRAY_CONST_PTR(ary2
) + i
;
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>.
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].
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
)) {
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
);
5236 recursive_eql(VALUE ary1
, VALUE ary2
, int recur
)
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
)))
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>.
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
);
5276 rb_ary_hash_values(long len
, const VALUE
*elements
)
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
));
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
5306 rb_ary_hash(VALUE ary
)
5308 return rb_ary_hash_values(RARRAY_LEN(ary
), RARRAY_CONST_PTR(ary
));
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
5323 rb_ary_includes(VALUE ary
, VALUE item
)
5328 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
5329 e
= RARRAY_AREF(ary
, i
);
5330 if (rb_equal(e
, item
)) {
5338 rb_ary_includes_by_eql(VALUE ary
, VALUE item
)
5343 for (i
=0; i
<RARRAY_LEN(ary
); i
++) {
5344 e
= RARRAY_AREF(ary
, i
);
5345 if (rb_eql(item
, e
)) {
5353 recursive_cmp(VALUE ary1
, VALUE ary2
, int recur
)
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)) {
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].
5411 rb_ary_cmp(VALUE ary1
, VALUE ary2
)
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);
5428 ary_add_hash(VALUE hash
, VALUE ary
)
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
);
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
);
5450 ary_make_hash(VALUE ary
)
5452 VALUE hash
= ary_tmp_hash_new(ary
);
5453 return ary_add_hash(hash
, ary
);
5457 ary_add_hash_by(VALUE hash
, VALUE ary
)
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
);
5469 ary_make_hash_by(VALUE ary
)
5471 VALUE hash
= ary_tmp_hash_new(ary
);
5472 return ary_add_hash_by(hash
, ary
);
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].
5494 rb_ary_diff(VALUE ary1
, VALUE ary2
)
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
);
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
));
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.
5540 rb_ary_difference_multi(int argc
, VALUE
*argv
, VALUE ary
)
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
++) {
5557 VALUE elt
= rb_ary_elt(ary
, i
);
5558 for (j
= 0; j
< argc
; j
++) {
5560 if (rb_hash_stlike_lookup(argv
[j
], RARRAY_AREF(ary
, i
), NULL
))
5564 if (rb_ary_includes_by_eql(argv
[j
], elt
)) break;
5567 if (j
== argc
) rb_ary_push(ary_diff
, elt
);
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]
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].
5601 rb_ary_and(VALUE ary1
, VALUE ary2
)
5603 VALUE hash
, ary3
, v
;
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
);
5621 hash
= ary_make_hash(ary2
);
5623 for (i
=0; i
<RARRAY_LEN(ary1
); i
++) {
5624 v
= RARRAY_AREF(ary1
, i
);
5626 if (rb_hash_stlike_delete(hash
, &vv
, 0)) {
5627 rb_ary_push(ary3
, v
);
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.
5656 rb_ary_intersection_multi(int argc
, VALUE
*argv
, VALUE ary
)
5658 VALUE result
= rb_ary_dup(ary
);
5661 for (i
= 0; i
< argc
; i
++) {
5662 result
= rb_ary_and(result
, argv
[i
]);
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
;
5677 rb_ary_union(VALUE ary_union
, VALUE ary
)
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
);
5688 rb_ary_union_hash(VALUE hash
, VALUE ary2
)
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
);
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.
5715 rb_ary_or(VALUE ary1
, VALUE ary2
)
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
);
5727 hash
= ary_make_hash(ary1
);
5728 rb_ary_union_hash(hash
, ary2
);
5730 return rb_hash_values(hash
);
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.
5750 rb_ary_union_multi(int argc
, VALUE
*argv
, VALUE ary
)
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
]);
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
);
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+:
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).
5795 rb_ary_intersect_p(VALUE ary1
, VALUE ary2
)
5797 VALUE hash
, v
, result
, shorter
, longer
;
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
;
5814 if (RARRAY_LEN(ary1
) > RARRAY_LEN(ary2
)) {
5819 hash
= ary_make_hash(shorter
);
5822 for (i
=0; i
<RARRAY_LEN(longer
); i
++) {
5823 v
= RARRAY_AREF(longer
, i
);
5825 if (rb_hash_stlike_lookup(hash
, vv
, 0)) {
5835 ary_max_generic(VALUE ary
, long i
, VALUE vmax
)
5837 RUBY_ASSERT(i
> 0 && i
< RARRAY_LEN(ary
));
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) {
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
));
5859 for (; i
< n
; ++i
) {
5860 v
= RARRAY_AREF(ary
, i
);
5863 if ((long)vmax
< (long)v
) {
5868 return ary_max_generic(ary
, i
, vmax
);
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
));
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) {
5892 return ary_max_generic(ary
, i
, vmax
);
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
));
5907 for (; i
< n
; ++i
) {
5908 v
= RARRAY_AREF(ary
, i
);
5911 if (rb_str_cmp(vmax
, v
) < 0) {
5916 return ary_max_generic(ary
, i
, vmax
);
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>
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"]
5963 rb_ary_max(int argc
, VALUE
*argv
, VALUE ary
)
5965 VALUE result
= Qundef
, v
;
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) {
5982 result
= RARRAY_AREF(ary
, 0);
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
);
5994 return ary_max_generic(ary
, 1, result
);
5998 if (UNDEF_P(result
)) return Qnil
;
6003 ary_min_generic(VALUE ary
, long i
, VALUE vmin
)
6005 RUBY_ASSERT(i
> 0 && i
< RARRAY_LEN(ary
));
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) {
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
));
6027 for (; i
< n
; ++i
) {
6028 a
= RARRAY_AREF(ary
, i
);
6031 if ((long)vmin
> (long)a
) {
6036 return ary_min_generic(ary
, i
, vmin
);
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
));
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) {
6060 return ary_min_generic(ary
, i
, vmin
);
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
));
6075 for (; i
< n
; ++i
) {
6076 a
= RARRAY_AREF(ary
, i
);
6079 if (rb_str_cmp(vmin
, a
) > 0) {
6084 return ary_min_generic(ary
, i
, vmin
);
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>
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"]
6131 rb_ary_min(int argc
, VALUE
*argv
, VALUE ary
)
6133 VALUE result
= Qundef
, v
;
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) {
6150 result
= RARRAY_AREF(ary
, 0);
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
);
6162 return ary_min_generic(ary
, 1, result
);
6166 if (UNDEF_P(result
)) return Qnil
;
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>
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"]
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
));
6203 push_value(st_data_t key
, st_data_t val
, st_data_t ary
)
6205 rb_ary_push((VALUE
)ary
, (VALUE
)val
);
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>
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.
6239 rb_ary_uniq_bang(VALUE ary
)
6244 rb_ary_modify_check(ary
);
6245 if (RARRAY_LEN(ary
) <= 1)
6247 if (rb_block_given_p())
6248 hash
= ary_make_hash_by(ary
);
6250 hash
= ary_make_hash(ary
);
6252 hash_size
= RHASH_SIZE(hash
);
6253 if (RARRAY_LEN(ary
) == hash_size
) {
6256 rb_ary_modify_check(ary
);
6257 ARY_SET_LEN(ary
, 0);
6258 if (ARY_SHARED_P(ary
)) {
6259 rb_ary_unshare(ary
);
6262 ary_resize_capa(ary
, hash_size
);
6263 rb_hash_foreach(hash
, push_value
, ary
);
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>
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"]
6292 rb_ary_uniq(VALUE ary
)
6296 if (RARRAY_LEN(ary
) <= 1) {
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
);
6305 hash
= ary_make_hash(ary
);
6306 uniq
= rb_hash_values(hash
);
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].
6329 rb_ary_compact_bang(VALUE ary
)
6335 p
= t
= (VALUE
*)RARRAY_CONST_PTR(ary
); /* WB: no new reference */
6336 end
= p
+ RARRAY_LEN(ary
);
6342 n
= p
- RARRAY_CONST_PTR(ary
);
6343 if (RARRAY_LEN(ary
) == n
) {
6346 ary_resize_smaller(ary
, n
);
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!.
6365 rb_ary_compact(VALUE ary
)
6367 ary
= rb_ary_dup(ary
);
6368 rb_ary_compact_bang(ary
);
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].
6400 rb_ary_count(int argc
, VALUE
*argv
, VALUE ary
)
6404 if (rb_check_arity(argc
, 0, 1) == 0) {
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
++;
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
++;
6430 flatten(VALUE ary
, int level
)
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
);
6443 if (i
== RARRAY_LEN(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));
6456 memo
= rb_obj_hide(rb_ident_hash_new());
6457 rb_hash_aset(memo
, ary
, Qtrue
);
6458 rb_hash_aset(memo
, tmp
, Qtrue
);
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
);
6471 tmp
= rb_check_array_type(elt
);
6472 if (RBASIC(result
)->klass
) {
6474 rb_hash_clear(memo
);
6476 rb_raise(rb_eRuntimeError
, "flatten reentered");
6479 rb_ary_push(result
, elt
);
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
));
6495 if (RARRAY_LEN(stack
) == 0) {
6499 rb_hash_delete(memo
, ary
);
6501 tmp
= rb_ary_pop(stack
);
6503 ary
= rb_ary_pop(stack
);
6507 rb_hash_clear(memo
);
6510 RBASIC_SET_CLASS(result
, rb_cArray
);
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
6546 rb_ary_flatten_bang(int argc
, VALUE
*argv
, VALUE ary
)
6548 int mod
= 0, level
= -1;
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
) {
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);
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]
6601 rb_ary_flatten(int argc
, VALUE
*argv
, VALUE ary
)
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
);
6619 #define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)
6622 rb_ary_shuffle_bang(rb_execution_context_t
*ec
, VALUE ary
, VALUE randgen
)
6627 i
= len
= RARRAY_LEN(ary
);
6628 RARRAY_PTR_USE(ary
, ptr
, {
6630 long j
= RAND_UPTO(i
);
6632 if (len
!= RARRAY_LEN(ary
) || ptr
!= RARRAY_CONST_PTR(ary
)) {
6633 rb_raise(rb_eRuntimeError
, "modified during shuffle");
6639 }); /* WB: no new reference */
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
);
6651 static const rb_data_type_t ary_sample_memo_type
= {
6652 .wrap_struct_name
= "ary_sample_memo",
6654 .dfree
= (RUBY_DATA_FUNC
)st_free_table
,