diff options
Diffstat (limited to 'array.c')
| -rw-r--r-- | array.c | 1598 |
1 files changed, 449 insertions, 1149 deletions
@@ -10,16 +10,15 @@ Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ -#include "ruby/encoding.h" + +#include "internal.h" #include "ruby/util.h" #include "ruby/st.h" #include "probes.h" #include "id.h" #include "debug_counter.h" -#include "transient_heap.h" -#include "internal.h" -#if !ARRAY_DEBUG +#ifndef ARRAY_DEBUG # define NDEBUG #endif #include "ruby_assert.h" @@ -33,50 +32,27 @@ VALUE rb_cArray; #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE)) #define SMALL_ARRAY_LEN 16 -static int -should_be_T_ARRAY(VALUE ary) -{ - return RB_TYPE_P(ary, T_ARRAY); -} - -static int -should_not_be_shared_and_embedded(VALUE ary) -{ - return !FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG); -} - -#define ARY_SHARED_P(ary) \ - (assert(should_be_T_ARRAY((VALUE)(ary))), \ - assert(should_not_be_shared_and_embedded((VALUE)ary)), \ - FL_TEST_RAW((ary),ELTS_SHARED)!=0) - -#define ARY_EMBED_P(ary) \ - (assert(should_be_T_ARRAY((VALUE)(ary))), \ - assert(should_not_be_shared_and_embedded((VALUE)ary)), \ - FL_TEST_RAW((ary), RARRAY_EMBED_FLAG) != 0) +# define ARY_SHARED_P(ary) \ + (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ + FL_TEST((ary),ELTS_SHARED)!=0) +# define ARY_EMBED_P(ary) \ + (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ + FL_TEST((ary), RARRAY_EMBED_FLAG)!=0) #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr) #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len) -#define ARY_HEAP_CAPA(a) (assert(!ARY_EMBED_P(a)), assert(!ARY_SHARED_ROOT_P(a)), \ - RARRAY(a)->as.heap.aux.capa) - #define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary) #define ARY_EMBED_LEN(a) \ (assert(ARY_EMBED_P(a)), \ (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT))) -#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), ARY_CAPA(a) * sizeof(VALUE)) - -#define ARY_OWNS_HEAP_P(a) (assert(should_be_T_ARRAY((VALUE)(a))), \ - !FL_TEST_RAW((a), ELTS_SHARED|RARRAY_EMBED_FLAG)) +#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), RARRAY(a)->as.heap.aux.capa * sizeof(VALUE)) +#define ARY_OWNS_HEAP_P(a) (!FL_TEST((a), ELTS_SHARED|RARRAY_EMBED_FLAG)) #define FL_SET_EMBED(a) do { \ assert(!ARY_SHARED_P(a)); \ FL_SET((a), RARRAY_EMBED_FLAG); \ - RARY_TRANSIENT_UNSET(a); \ - ary_verify(a); \ } while (0) - #define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK) #define FL_SET_SHARED(ary) do { \ assert(!ARY_EMBED_P(ary)); \ @@ -125,7 +101,7 @@ should_not_be_shared_and_embedded(VALUE ary) } while (0) #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \ - ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary)) + ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa) #define ARY_SET_CAPA(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ assert(!ARY_SHARED_P(ary)); \ @@ -133,114 +109,33 @@ should_not_be_shared_and_embedded(VALUE ary) RARRAY(ary)->as.heap.aux.capa = (n); \ } while (0) -#define ARY_SHARED_ROOT(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared_root) +#define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared) #define ARY_SET_SHARED(ary, value) do { \ const VALUE _ary_ = (ary); \ const VALUE _value_ = (value); \ assert(!ARY_EMBED_P(_ary_)); \ assert(ARY_SHARED_P(_ary_)); \ assert(ARY_SHARED_ROOT_P(_value_)); \ - RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared_root, _value_); \ + RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared, _value_); \ } while (0) #define RARRAY_SHARED_ROOT_FLAG FL_USER5 -#define ARY_SHARED_ROOT_P(ary) (assert(should_be_T_ARRAY((VALUE)(ary))), \ - FL_TEST_RAW((ary), RARRAY_SHARED_ROOT_FLAG)) -#define ARY_SHARED_ROOT_REFCNT(ary) \ +#define ARY_SHARED_ROOT_P(ary) (FL_TEST((ary), RARRAY_SHARED_ROOT_FLAG)) +#define ARY_SHARED_NUM(ary) \ (assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa) -#define ARY_SHARED_ROOT_OCCUPIED(ary) (ARY_SHARED_ROOT_REFCNT(ary) == 1) -#define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \ +#define ARY_SHARED_OCCUPIED(ary) (ARY_SHARED_NUM(ary) == 1) +#define ARY_SET_SHARED_NUM(ary, value) do { \ assert(ARY_SHARED_ROOT_P(ary)); \ RARRAY(ary)->as.heap.aux.capa = (value); \ } while (0) #define FL_SET_SHARED_ROOT(ary) do { \ assert(!ARY_EMBED_P(ary)); \ - assert(!RARRAY_TRANSIENT_P(ary)); \ FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \ } while (0) -static inline void -ARY_SET(VALUE a, long i, VALUE v) -{ - assert(!ARY_SHARED_P(a)); - assert(!OBJ_FROZEN(a)); - - RARRAY_ASET(a, i, v); -} -#undef RARRAY_ASET - - -#if ARRAY_DEBUG -#define ary_verify(ary) ary_verify_(ary, __FILE__, __LINE__) - -static VALUE -ary_verify_(VALUE ary, const char *file, int line) -{ - assert(RB_TYPE_P(ary, T_ARRAY)); - - if (FL_TEST(ary, ELTS_SHARED)) { - VALUE root = RARRAY(ary)->as.heap.aux.shared_root; - const VALUE *ptr = ARY_HEAP_PTR(ary); - const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root); - long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root); - assert(FL_TEST(root, RARRAY_SHARED_ROOT_FLAG)); - assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len); - ary_verify(root); - } - else if (ARY_EMBED_P(ary)) { - assert(!RARRAY_TRANSIENT_P(ary)); - assert(!ARY_SHARED_P(ary)); - assert(RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX); - } - else { -#if 1 - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary); - long i, len = RARRAY_LEN(ary); - volatile VALUE v; - if (len > 1) len = 1; /* check only HEAD */ - for (i=0; i<len; i++) { - v = ptr[i]; /* access check */ - } - v = v; -#endif - } - - if (RARRAY_TRANSIENT_P(ary)) { - assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary))); - } - - rb_transient_heap_verify(); - - return ary; -} +#define ARY_SET(a, i, v) RARRAY_ASET((assert(!ARY_SHARED_P(a)), (a)), (i), (v)) void -rb_ary_verify(VALUE ary) -{ - ary_verify(ary); -} -#else -#define ary_verify(ary) ((void)0) -#endif - -VALUE * -rb_ary_ptr_use_start(VALUE ary) -{ -#if ARRAY_DEBUG - FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG); -#endif - return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); -} - -void -rb_ary_ptr_use_end(VALUE ary) -{ -#if ARRAY_DEBUG - FL_UNSET_RAW(ary, RARRAY_PTR_IN_USE_FLAG); -#endif -} - -void -rb_mem_clear(VALUE *mem, long size) +rb_mem_clear(register VALUE *mem, register long size) { while (size--) { *mem++ = Qnil; @@ -250,7 +145,7 @@ rb_mem_clear(VALUE *mem, long size) static void ary_mem_clear(VALUE ary, long beg, long size) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { rb_mem_clear(ptr + beg, size); }); } @@ -266,7 +161,7 @@ memfill(register VALUE *mem, register long size, register VALUE val) static void ary_memfill(VALUE ary, long beg, long size, VALUE val) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { memfill(ptr + beg, size, val); RB_OBJ_WRITTEN(ary, Qundef, val); }); @@ -275,22 +170,28 @@ ary_memfill(VALUE ary, long beg, long size, VALUE val) static void ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary) { +#if 1 assert(!ARY_SHARED_P(buff_owner_ary)); if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) { - rb_gc_writebarrier_remember(buff_owner_ary); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { - MEMCPY(ptr+beg, argv, VALUE, argc); - }); + rb_gc_writebarrier_remember(buff_owner_ary); + RARRAY_PTR_USE(ary, ptr, { + MEMCPY(ptr+beg, argv, VALUE, argc); + }); } else { - int i; - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { - for (i=0; i<argc; i++) { - RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]); - } - }); + int i; + RARRAY_PTR_USE(ary, ptr, { + for (i=0; i<argc; i++) { + RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]); + } + }); } +#else + /* giveup write barrier (traditional way) */ + RARRAY_PTR(buff_owner_ary); + MEMCPY(RARRAY_PTR(ary)+beg, argv, VALUE, argc); +#endif } static void @@ -299,175 +200,49 @@ ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv) ary_memcpy0(ary, beg, argc, argv, ary); } -static VALUE * -ary_heap_alloc(VALUE ary, size_t capa) -{ - VALUE *ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * capa); - - if (ptr != NULL) { - RARY_TRANSIENT_SET(ary); - } - else { - RARY_TRANSIENT_UNSET(ary); - ptr = ALLOC_N(VALUE, capa); - } - - return ptr; -} - -static void -ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size) -{ - if (RARRAY_TRANSIENT_P(ary)) { - /* ignore it */ - } - else { - ruby_sized_xfree((void *)ptr, size); - } -} - -static void -ary_heap_free(VALUE ary) -{ - if (RARRAY_TRANSIENT_P(ary)) { - RARY_TRANSIENT_UNSET(ary); - } - else { - ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary)); - } -} - -static void -ary_heap_realloc(VALUE ary, size_t new_capa) -{ - size_t old_capa = ARY_HEAP_CAPA(ary); - - if (RARRAY_TRANSIENT_P(ary)) { - if (new_capa <= old_capa) { - /* do nothing */ - } - else { - VALUE *new_ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * new_capa); - - if (new_ptr == NULL) { - new_ptr = ALLOC_N(VALUE, new_capa); - RARY_TRANSIENT_UNSET(ary); - } - - MEMCPY(new_ptr, ARY_HEAP_PTR(ary), VALUE, old_capa); - ARY_SET_PTR(ary, new_ptr); - } - } - else { - SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, old_capa); - } - ary_verify(ary); -} - -#if USE_TRANSIENT_HEAP -static inline void -rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote) -{ - if (transient) { - VALUE *new_ptr; - const VALUE *old_ptr = ARY_HEAP_PTR(ary); - long capa = ARY_HEAP_CAPA(ary); - long len = ARY_HEAP_LEN(ary); - - if (ARY_SHARED_ROOT_P(ary)) { - capa = len; - } - - assert(ARY_OWNS_HEAP_P(ary)); - assert(RARRAY_TRANSIENT_P(ary)); - assert(!ARY_PTR_USING_P(ary)); - - if (promote) { - new_ptr = ALLOC_N(VALUE, capa); - RARY_TRANSIENT_UNSET(ary); - } - else { - new_ptr = ary_heap_alloc(ary, capa); - } - - MEMCPY(new_ptr, old_ptr, VALUE, capa); - /* do not use ARY_SET_PTR() because they assert !frozen */ - RARRAY(ary)->as.heap.ptr = new_ptr; - } - - ary_verify(ary); -} - -void -rb_ary_transient_heap_evacuate(VALUE ary, int promote) -{ - rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote); -} - -void -rb_ary_detransient(VALUE ary) -{ - assert(RARRAY_TRANSIENT_P(ary)); - rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE); -} -#else -void -rb_ary_detransient(VALUE ary) -{ - /* do nothing */ -} -#endif - static void ary_resize_capa(VALUE ary, long capacity) { assert(RARRAY_LEN(ary) <= capacity); assert(!OBJ_FROZEN(ary)); assert(!ARY_SHARED_P(ary)); - if (capacity > RARRAY_EMBED_LEN_MAX) { if (ARY_EMBED_P(ary)) { long len = ARY_EMBED_LEN(ary); - VALUE *ptr = ary_heap_alloc(ary, capacity); - + VALUE *ptr = ALLOC_N(VALUE, (capacity)); MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len); FL_UNSET_EMBED(ary); ARY_SET_PTR(ary, ptr); ARY_SET_HEAP_LEN(ary, len); } else { - ary_heap_realloc(ary, capacity); + SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity, RARRAY(ary)->as.heap.aux.capa); } - ARY_SET_CAPA(ary, capacity); + ARY_SET_CAPA(ary, (capacity)); } else { if (!ARY_EMBED_P(ary)) { - long len = ARY_HEAP_LEN(ary); - long old_capa = ARY_HEAP_CAPA(ary); - const VALUE *ptr = ARY_HEAP_PTR(ary); + long len = RARRAY_LEN(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); - if (len > capacity) len = capacity; + if (len > capacity) len = capacity; MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len); - ary_heap_free_ptr(ary, ptr, old_capa); - FL_SET_EMBED(ary); ARY_SET_LEN(ary, len); + ruby_xfree((VALUE *)ptr); } } - - ary_verify(ary); } static inline void ary_shrink_capa(VALUE ary) { long capacity = ARY_HEAP_LEN(ary); - long old_capa = ARY_HEAP_CAPA(ary); + long old_capa = RARRAY(ary)->as.heap.aux.capa; assert(!ARY_SHARED_P(ary)); assert(old_capa >= capacity); - if (old_capa > capacity) ary_heap_realloc(ary, capacity); - - ary_verify(ary); + if (old_capa > capacity) + REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity); } static void @@ -483,21 +258,19 @@ ary_double_capa(VALUE ary, long min) } new_capa += min; ary_resize_capa(ary, new_capa); - - ary_verify(ary); } static void -rb_ary_decrement_share(VALUE shared_root) +rb_ary_decrement_share(VALUE shared) { - if (shared_root) { - long num = ARY_SHARED_ROOT_REFCNT(shared_root) - 1; + if (shared) { + long num = ARY_SHARED_NUM(shared) - 1; if (num == 0) { - rb_ary_free(shared_root); - rb_gc_force_recycle(shared_root); + rb_ary_free(shared); + rb_gc_force_recycle(shared); } else if (num > 0) { - ARY_SET_SHARED_ROOT_REFCNT(shared_root, num); + ARY_SET_SHARED_NUM(shared, num); } } } @@ -505,8 +278,8 @@ rb_ary_decrement_share(VALUE shared_root) static void rb_ary_unshare(VALUE ary) { - VALUE shared_root = RARRAY(ary)->as.heap.aux.shared_root; - rb_ary_decrement_share(shared_root); + VALUE shared = RARRAY(ary)->as.heap.aux.shared; + rb_ary_decrement_share(shared); FL_UNSET_SHARED(ary); } @@ -519,29 +292,27 @@ rb_ary_unshare_safe(VALUE ary) } static VALUE -rb_ary_increment_share(VALUE shared_root) +rb_ary_increment_share(VALUE shared) { - long num = ARY_SHARED_ROOT_REFCNT(shared_root); + long num = ARY_SHARED_NUM(shared); if (num >= 0) { - ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1); + ARY_SET_SHARED_NUM(shared, num + 1); } - return shared_root; + return shared; } static void -rb_ary_set_shared(VALUE ary, VALUE shared_root) +rb_ary_set_shared(VALUE ary, VALUE shared) { - rb_ary_increment_share(shared_root); + rb_ary_increment_share(shared); FL_SET_SHARED(ary); - RB_DEBUG_COUNTER_INC(obj_ary_shared_create); - ARY_SET_SHARED(ary, shared_root); + ARY_SET_SHARED(ary, shared); } static inline void rb_ary_modify_check(VALUE ary) { rb_check_frozen(ary); - ary_verify(ary); } void @@ -550,32 +321,29 @@ rb_ary_modify(VALUE ary) rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { long shared_len, len = RARRAY_LEN(ary); - VALUE shared_root = ARY_SHARED_ROOT(ary); - - ary_verify(shared_root); - + VALUE shared = ARY_SHARED(ary); if (len <= RARRAY_EMBED_LEN_MAX) { const VALUE *ptr = ARY_HEAP_PTR(ary); FL_UNSET_SHARED(ary); FL_SET_EMBED(ary); MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); - rb_ary_decrement_share(shared_root); + rb_ary_decrement_share(shared); ARY_SET_EMBED_LEN(ary, len); } - else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) { - long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root); + else if (ARY_SHARED_OCCUPIED(shared) && len > ((shared_len = RARRAY_LEN(shared))>>1)) { + long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared); FL_UNSET_SHARED(ary); - ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root)); + ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared)); ARY_SET_CAPA(ary, shared_len); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+shift, VALUE, len); }); - FL_SET_EMBED(shared_root); - rb_ary_decrement_share(shared_root); + FL_SET_EMBED(shared); + rb_ary_decrement_share(shared); } else { - VALUE *ptr = ary_heap_alloc(ary, len); - MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len); + VALUE *ptr = ALLOC_N(VALUE, len); + MEMCPY(ptr, RARRAY_CONST_PTR(ary), VALUE, len); rb_ary_unshare(ary); ARY_SET_CAPA(ary, len); ARY_SET_PTR(ary, ptr); @@ -583,7 +351,6 @@ rb_ary_modify(VALUE ary) rb_gc_writebarrier_remember(ary); } - ary_verify(ary); } static VALUE @@ -598,14 +365,11 @@ ary_ensure_room_for_push(VALUE ary, long add_len) } if (ARY_SHARED_P(ary)) { if (new_len > RARRAY_EMBED_LEN_MAX) { - VALUE shared_root = ARY_SHARED_ROOT(ary); - if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) { - if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root) + new_len <= RARRAY_LEN(shared_root)) { + VALUE shared = ARY_SHARED(ary); + if (ARY_SHARED_OCCUPIED(shared)) { + if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) { rb_ary_modify_check(ary); - - ary_verify(ary); - ary_verify(shared_root); - return shared_root; + return shared; } else { /* if array is shared, then it is likely it participate in push/shift pattern */ @@ -614,13 +378,11 @@ ary_ensure_room_for_push(VALUE ary, long add_len) if (new_len > capa - (capa >> 6)) { ary_double_capa(ary, new_len); } - ary_verify(ary); return ary; } } } - ary_verify(ary); - rb_ary_modify(ary); + rb_ary_modify(ary); } else { rb_ary_modify_check(ary); @@ -630,7 +392,6 @@ ary_ensure_room_for_push(VALUE ary, long add_len) ary_double_capa(ary, new_len); } - ary_verify(ary); return ary; } @@ -650,6 +411,21 @@ rb_ary_freeze(VALUE ary) return rb_obj_freeze(ary); } +/* + * call-seq: + * ary.frozen? -> true or false + * + * Return +true+ if this array is frozen (or temporarily frozen + * while being sorted). See also Object#frozen? + */ + +static VALUE +rb_ary_frozen_p(VALUE ary) +{ + if (OBJ_FROZEN(ary)) return Qtrue; + return Qfalse; +} + /* This can be used to take a snapshot of an array (with e.g. rb_ary_replace) and check later whether the array has been modified from the snapshot. The snapshot is cheap, though if @@ -662,7 +438,7 @@ rb_ary_shared_with_p(VALUE ary1, VALUE ary2) { if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) && !ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) && - RARRAY(ary1)->as.heap.aux.shared_root == RARRAY(ary2)->as.heap.aux.shared_root && + RARRAY(ary1)->as.heap.aux.shared == RARRAY(ary2)->as.heap.aux.shared && RARRAY(ary1)->as.heap.len == RARRAY(ary2)->as.heap.len) { return Qtrue; } @@ -703,7 +479,7 @@ ary_new(VALUE klass, long capa) ary = ary_alloc(klass); if (capa > RARRAY_EMBED_LEN_MAX) { - ptr = ary_heap_alloc(ary, capa); + ptr = ALLOC_N(VALUE, capa); FL_UNSET_EMBED(ary); ARY_SET_PTR(ary, ptr); ARY_SET_CAPA(ary, capa); @@ -744,7 +520,7 @@ VALUE return ary; } -MJIT_FUNC_EXPORTED VALUE +VALUE rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts) { VALUE ary; @@ -767,9 +543,7 @@ rb_ary_new_from_values(long n, const VALUE *elts) VALUE rb_ary_tmp_new(long capa) { - VALUE ary = ary_new(0, capa); - rb_ary_transient_heap_evacuate(ary, TRUE); - return ary; + return ary_new(0, capa); } VALUE @@ -778,7 +552,6 @@ rb_ary_tmp_new_fill(long capa) VALUE ary = ary_new(0, capa); ary_memfill(ary, 0, capa, Qnil); ARY_SET_LEN(ary, capa); - rb_ary_transient_heap_evacuate(ary, TRUE); return ary; } @@ -786,29 +559,11 @@ void rb_ary_free(VALUE ary) { if (ARY_OWNS_HEAP_P(ary)) { - if (USE_DEBUG_COUNTER && - !ARY_SHARED_ROOT_P(ary) && - ARY_HEAP_CAPA(ary) > RARRAY_LEN(ary)) { - RB_DEBUG_COUNTER_INC(obj_ary_extracapa); - } - - if (RARRAY_TRANSIENT_P(ary)) { - RB_DEBUG_COUNTER_INC(obj_ary_transient); - } - else { - RB_DEBUG_COUNTER_INC(obj_ary_ptr); - ary_heap_free(ary); - } + RB_DEBUG_COUNTER_INC(obj_ary_ptr); + ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary)); } else { - RB_DEBUG_COUNTER_INC(obj_ary_embed); - } - - if (ARY_SHARED_P(ary)) { - RB_DEBUG_COUNTER_INC(obj_ary_shared); - } - if (ARY_SHARED_ROOT_P(ary) && ARY_SHARED_ROOT_OCCUPIED(ary)) { - RB_DEBUG_COUNTER_INC(obj_ary_shared_root_occupied); + RB_DEBUG_COUNTER_INC(obj_ary_embed); } } @@ -828,51 +583,39 @@ ary_discard(VALUE ary) { rb_ary_free(ary); RBASIC(ary)->flags |= RARRAY_EMBED_FLAG; - RBASIC(ary)->flags &= ~(RARRAY_EMBED_LEN_MASK | RARRAY_TRANSIENT_FLAG); + RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; } static VALUE ary_make_shared(VALUE ary) { assert(!ARY_EMBED_P(ary)); - ary_verify(ary); - if (ARY_SHARED_P(ary)) { - return ARY_SHARED_ROOT(ary); + return ARY_SHARED(ary); } else if (ARY_SHARED_ROOT_P(ary)) { return ary; } else if (OBJ_FROZEN(ary)) { - rb_ary_transient_heap_evacuate(ary, TRUE); ary_shrink_capa(ary); FL_SET_SHARED_ROOT(ary); - ARY_SET_SHARED_ROOT_REFCNT(ary, 1); + ARY_SET_SHARED_NUM(ary, 1); return ary; } else { long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary); - const VALUE *ptr; NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0)); - - rb_ary_transient_heap_evacuate(ary, TRUE); - ptr = ARY_HEAP_PTR(ary); - FL_UNSET_EMBED(shared); + ARY_SET_LEN((VALUE)shared, capa); - ARY_SET_PTR((VALUE)shared, ptr); - ary_mem_clear((VALUE)shared, len, capa - len); + ARY_SET_PTR((VALUE)shared, RARRAY_CONST_PTR(ary)); + ary_mem_clear((VALUE)shared, len, capa - len); FL_SET_SHARED_ROOT(shared); - ARY_SET_SHARED_ROOT_REFCNT((VALUE)shared, 1); + ARY_SET_SHARED_NUM((VALUE)shared, 1); FL_SET_SHARED(ary); - RB_DEBUG_COUNTER_INC(obj_ary_shared_create); ARY_SET_SHARED(ary, (VALUE)shared); OBJ_FREEZE(shared); - - ary_verify((VALUE)shared); - ary_verify(ary); - - return (VALUE)shared; + return (VALUE)shared; } } @@ -883,7 +626,7 @@ ary_make_substitution(VALUE ary) if (len <= RARRAY_EMBED_LEN_MAX) { VALUE subst = rb_ary_new2(len); - ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary)); + ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_EMBED_LEN(subst, len); return subst; } @@ -911,18 +654,12 @@ rb_check_array_type(VALUE ary) return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary); } -MJIT_FUNC_EXPORTED VALUE -rb_check_to_array(VALUE ary) -{ - return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a); -} - /* * call-seq: * Array.try_convert(obj) -> array or nil * - * Tries to convert +obj+ into an array, using the +to_ary+ method. Returns - * the converted array or +nil+ if +obj+ cannot be converted. + * Tries to convert +obj+ into an array, using +to_ary+ method. Returns the + * converted array or +nil+ if +obj+ cannot be converted for any reason. * This method can be used to check if an argument is an array. * * Array.try_convert([1]) #=> [1] @@ -968,7 +705,7 @@ rb_ary_s_try_convert(VALUE dummy, VALUE ary) * this array is created by passing the element's index to the given block * and storing the return value. * - * Array.new(3) {|index| index ** 2} + * Array.new(3){ |index| index ** 2 } * # => [0, 1, 4] * * == Common gotchas @@ -992,7 +729,7 @@ rb_ary_s_try_convert(VALUE dummy, VALUE ary) * version which uses the result of that block each time an element * of the array needs to be initialized: * - * a = Array.new(2) {Hash.new} + * a = Array.new(2) { Hash.new } * a[0]['cat'] = 'feline' * a # => [{"cat"=>"feline"}, {}] * @@ -1006,8 +743,8 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary) rb_ary_modify(ary); if (argc == 0) { - if (ARY_OWNS_HEAP_P(ary) && ARY_HEAP_PTR(ary) != NULL) { - ary_heap_free(ary); + if (ARY_OWNS_HEAP_P(ary) && RARRAY_CONST_PTR(ary) != 0) { + ruby_sized_xfree((void *)RARRAY_CONST_PTR(ary), ARY_HEAP_SIZE(ary)); } rb_ary_unshare_safe(ary); FL_SET_EMBED(ary); @@ -1058,7 +795,7 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary) /* * Returns a new array populated with the given objects. * - * Array.[]( 1, 'a', /^A/) # => [1, "a", /^A/] + * Array.[]( 1, 'a', /^A/ ) # => [1, "a", /^A/] * Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/] * [ 1, 'a', /^A/ ] # => [1, "a", /^A/] */ @@ -1114,7 +851,7 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) if (len <= RARRAY_EMBED_LEN_MAX) { VALUE result = ary_alloc(klass); - ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset); + ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset); ARY_SET_EMBED_LEN(result, len); return result; } @@ -1123,15 +860,12 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) FL_UNSET_EMBED(result); shared = ary_make_shared(ary); - ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary)); + ARY_SET_PTR(result, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(result, RARRAY_LEN(ary)); rb_ary_set_shared(result, shared); ARY_INCREASE_PTR(result, offset); ARY_SET_LEN(result, len); - - ary_verify(shared); - ary_verify(result); return result; } } @@ -1151,17 +885,13 @@ enum ary_take_pos_flags static VALUE ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last) { + VALUE nv; long n; long len; long offset = 0; - argc = rb_check_arity(argc, 0, 1); - /* the case optional argument is omitted should be handled in - * callers of this function. if another arity case is added, - * this arity check needs to rewrite. */ - RUBY_ASSERT_ALWAYS(argc == 1); - - n = NUM2LONG(argv[0]); + rb_scan_args(argc, argv, "1", &nv); + n = NUM2LONG(nv); len = RARRAY_LEN(ary); if (n > len) { n = len; @@ -1194,13 +924,12 @@ ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos VALUE rb_ary_push(VALUE ary, VALUE item) { - long idx = RARRAY_LEN((ary_verify(ary), ary)); + long idx = RARRAY_LEN(ary); VALUE target_ary = ary_ensure_room_for_push(ary, 1); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { RB_OBJ_WRITE(target_ary, &ptr[idx], item); }); ARY_SET_LEN(ary, idx + 1); - ary_verify(ary); return ary; } @@ -1216,8 +945,7 @@ rb_ary_cat(VALUE ary, const VALUE *argv, long len) /* * call-seq: - * ary.push(obj, ...) -> ary - * ary.append(obj, ...) -> ary + * ary.push(obj, ... ) -> ary * * Append --- Pushes the given object(s) on to the end of this array. This * expression returns the array itself, so several appends @@ -1252,7 +980,6 @@ rb_ary_pop(VALUE ary) } --n; ARY_SET_LEN(ary, n); - ary_verify(ary); return RARRAY_AREF(ary, n); } @@ -1286,7 +1013,6 @@ rb_ary_pop_m(int argc, VALUE *argv, VALUE ary) rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); ARY_INCREASE_LEN(ary, -RARRAY_LEN(result)); - ary_verify(ary); return result; } @@ -1301,11 +1027,10 @@ rb_ary_shift(VALUE ary) top = RARRAY_AREF(ary, 0); if (!ARY_SHARED_P(ary)) { if (len < ARY_DEFAULT_SIZE) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+1, VALUE, len-1); }); /* WB: no new reference */ ARY_INCREASE_LEN(ary, -1); - ary_verify(ary); return top; } assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */ @@ -1313,14 +1038,12 @@ rb_ary_shift(VALUE ary) ARY_SET(ary, 0, Qnil); ary_make_shared(ary); } - else if (ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, ptr[0] = Qnil); + else if (ARY_SHARED_OCCUPIED(ARY_SHARED(ary))) { + RARRAY_PTR_USE(ary, ptr, ptr[0] = Qnil); } ARY_INCREASE_PTR(ary, 1); /* shift ptr */ ARY_INCREASE_LEN(ary, -1); - ary_verify(ary); - return top; } @@ -1360,19 +1083,8 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary) rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); n = RARRAY_LEN(result); - rb_ary_behead(ary,n); - - return result; -} - -MJIT_FUNC_EXPORTED VALUE -rb_ary_behead(VALUE ary, long n) -{ - if (n<=0) return ary; - - rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { - if (ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))) { + if (ARY_SHARED_OCCUPIED(ARY_SHARED(ary))) { setup_occupied_shared: ary_mem_clear(ary, 0, n); } @@ -1380,8 +1092,8 @@ rb_ary_behead(VALUE ary, long n) } else { if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { - MEMMOVE(ptr, ptr+n, VALUE, RARRAY_LEN(ary)-n); + RARRAY_PTR_USE(ary, ptr, { + MEMMOVE(ptr, ptr+n, VALUE, RARRAY_LEN(ary)-n); }); /* WB: no new reference */ } else { @@ -1391,8 +1103,7 @@ rb_ary_behead(VALUE ary, long n) } ARY_INCREASE_LEN(ary, -n); - ary_verify(ary); - return ary; + return result; } static VALUE @@ -1407,18 +1118,18 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) rb_raise(rb_eIndexError, "index %ld too big", new_len); } + rb_ary_modify(ary); + if (ARY_SHARED_P(ary)) { - VALUE shared_root = ARY_SHARED_ROOT(ary); - capa = RARRAY_LEN(shared_root); - if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && capa > new_len) { - rb_ary_modify_check(ary); - head = RARRAY_CONST_PTR_TRANSIENT(ary); - sharedp = RARRAY_CONST_PTR_TRANSIENT(shared_root); + VALUE shared = ARY_SHARED(ary); + capa = RARRAY_LEN(shared); + if (ARY_SHARED_OCCUPIED(shared) && capa > new_len) { + head = RARRAY_CONST_PTR(ary); + sharedp = RARRAY_CONST_PTR(shared); goto makeroom_if_need; } } - rb_ary_modify(ary); capa = ARY_CAPA(ary); if (capa - (capa >> 6) <= new_len) { ary_double_capa(ary, new_len); @@ -1426,13 +1137,11 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) /* use shared array for big "queues" */ if (new_len > ARY_DEFAULT_SIZE * 4) { - ary_verify(ary); - - /* make a room for unshifted items */ + /* make a room for unshifted items */ capa = ARY_CAPA(ary); ary_make_shared(ary); - head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary); + head = sharedp = RARRAY_CONST_PTR(ary); goto makeroom; makeroom_if_need: if (head - sharedp < argc) { @@ -1444,18 +1153,15 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) head = sharedp + argc + room; } ARY_SET_PTR(ary, head - argc); - assert(ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary))); - - ary_verify(ary); - return ARY_SHARED_ROOT(ary); + assert(ARY_SHARED_OCCUPIED(ARY_SHARED(ary))); + return ARY_SHARED(ary); } else { /* sliding items */ - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + argc, ptr, VALUE, len); }); - ary_verify(ary); return ary; } } @@ -1463,7 +1169,6 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) /* * call-seq: * ary.unshift(obj, ...) -> ary - * ary.prepend(obj, ...) -> ary * * Prepends objects to the front of +self+, moving other elements upwards. * See also Array#shift for the opposite effect. @@ -1511,7 +1216,17 @@ rb_ary_elt(VALUE ary, long offset) VALUE rb_ary_entry(VALUE ary, long offset) { - return rb_ary_entry_internal(ary, offset); + long len = RARRAY_LEN(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); + if (len == 0) return Qnil; + if (offset < 0) { + offset += len; + if (offset < 0) return Qnil; + } + else if (len <= offset) { + return Qnil; + } + return ptr[offset]; } VALUE @@ -1532,8 +1247,6 @@ rb_ary_subseq(VALUE ary, long beg, long len) return ary_make_partial(ary, klass, beg, len); } -static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e); - /* * call-seq: * ary[index] -> obj or nil @@ -1591,7 +1304,7 @@ rb_ary_aref2(VALUE ary, VALUE b, VALUE e) return rb_ary_subseq(ary, beg, len); } -MJIT_FUNC_EXPORTED VALUE +VALUE rb_ary_aref1(VALUE ary, VALUE arg) { long beg, len; @@ -1690,7 +1403,7 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) * call-seq: * ary.fetch(index) -> obj * ary.fetch(index, default) -> obj - * ary.fetch(index) {|index| block} -> obj + * ary.fetch(index) { |index| block } -> obj * * Tries to return the element at position +index+, but throws an IndexError * exception if the referenced +index+ lies outside of the array bounds. This @@ -1706,7 +1419,7 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) * a.fetch(1) #=> 22 * a.fetch(-1) #=> 44 * a.fetch(4, 'cat') #=> "cat" - * a.fetch(100) {|i| puts "#{i} is out of bounds"} + * a.fetch(100) { |i| puts "#{i} is out of bounds" } * #=> "100 is out of bounds" */ @@ -1741,10 +1454,10 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary) /* * call-seq: * ary.find_index(obj) -> int or nil - * ary.find_index {|item| block} -> int or nil + * ary.find_index { |item| block } -> int or nil * ary.find_index -> Enumerator * ary.index(obj) -> int or nil - * ary.index {|item| block} -> int or nil + * ary.index { |item| block } -> int or nil * ary.index -> Enumerator * * Returns the _index_ of the first object in +ary+ such that the object is @@ -1761,7 +1474,7 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary) * a = [ "a", "b", "c" ] * a.index("b") #=> 1 * a.index("z") #=> nil - * a.index {|x| x == "b"} #=> 1 + * a.index { |x| x == "b" } #=> 1 */ static VALUE @@ -1795,7 +1508,7 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) /* * call-seq: * ary.rindex(obj) -> int or nil - * ary.rindex {|item| block} -> int or nil + * ary.rindex { |item| block } -> int or nil * ary.rindex -> Enumerator * * Returns the _index_ of the last object in +self+ <code>==</code> to +obj+. @@ -1813,7 +1526,7 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) * a = [ "a", "b", "b", "b", "c" ] * a.rindex("b") #=> 3 * a.rindex("z") #=> nil - * a.rindex {|x| x == "b"} #=> 3 + * a.rindex { |x| x == "b" } #=> 3 */ static VALUE @@ -1842,9 +1555,6 @@ rb_ary_rindex(int argc, VALUE *argv, VALUE ary) if (rb_equal(e, val)) { return LONG2NUM(i); } - if (i > RARRAY_LEN(ary)) { - break; - } } return Qnil; } @@ -1878,7 +1588,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) } { - const VALUE *optr = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *optr = RARRAY_CONST_PTR(ary); rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1; } @@ -1891,7 +1601,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) len = beg + rlen; ary_mem_clear(ary, olen, beg - olen); if (rlen > 0) { - if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs; + if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; ary_memcpy0(ary, beg, rlen, rptr, target_ary); } ARY_SET_LEN(ary, len); @@ -1909,21 +1619,14 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) } if (len != rlen) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, - MEMMOVE(ptr + beg + rlen, ptr + beg + len, - VALUE, olen - (beg + len))); + RARRAY_PTR_USE(ary, ptr, + MEMMOVE(ptr + beg + rlen, ptr + beg + len, + VALUE, olen - (beg + len))); ARY_SET_LEN(ary, alen); } if (rlen > 0) { - if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs; - /* give up wb-protected ary */ - RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary); - - /* do not use RARRAY_PTR() because it can causes GC. - * ary can contain T_NONE object because it is not cleared. - */ - RARRAY_PTR_USE_TRANSIENT(ary, ptr, - MEMMOVE(ptr + beg, rptr, VALUE, rlen)); + if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; + MEMMOVE(RARRAY_PTR(ary) + beg, rptr, VALUE, rlen); } } } @@ -1981,12 +1684,11 @@ rb_ary_resize(VALUE ary, long len) } else { if (olen > len + ARY_DEFAULT_SIZE) { - ary_heap_realloc(ary, len); + SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, len, RARRAY(ary)->as.heap.aux.capa); ARY_SET_CAPA(ary, len); } ARY_SET_HEAP_LEN(ary, len); } - ary_verify(ary); return ary; } @@ -2047,7 +1749,7 @@ rb_ary_aset(int argc, VALUE *argv, VALUE ary) /* check if idx is Range */ range: rpl = rb_ary_to_ary(argv[argc-1]); - rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl)); + rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl)); RB_GC_GUARD(rpl); return argv[argc-1]; } @@ -2109,7 +1811,7 @@ ary_enum_length(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * ary.each {|item| block} -> ary + * ary.each { |item| block } -> ary * ary.each -> Enumerator * * Calls the given block once for each element in +self+, passing that element @@ -2129,7 +1831,7 @@ VALUE rb_ary_each(VALUE ary) { long i; - ary_verify(ary); + RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(RARRAY_AREF(ary, i)); @@ -2139,7 +1841,7 @@ rb_ary_each(VALUE ary) /* * call-seq: - * ary.each_index {|index| block} -> ary + * ary.each_index { |index| block } -> ary * ary.each_index -> Enumerator * * Same as Array#each, but passes the +index+ of the element instead of the @@ -2169,7 +1871,7 @@ rb_ary_each_index(VALUE ary) /* * call-seq: - * ary.reverse_each {|item| block} -> ary + * ary.reverse_each { |item| block } -> ary * ary.reverse_each -> Enumerator * * Same as Array#each, but traverses +self+ in reverse order. @@ -2239,18 +1941,15 @@ rb_ary_dup(VALUE ary) { long len = RARRAY_LEN(ary); VALUE dup = rb_ary_new2(len); - ary_memcpy(dup, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary)); + ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(dup, len); - - ary_verify(ary); - ary_verify(dup); return dup; } VALUE rb_ary_resurrect(VALUE ary) { - return ary_make_partial(ary, rb_cArray, 0, RARRAY_LEN(ary)); + return rb_ary_new4(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary)); } extern VALUE rb_output_fs; @@ -2287,6 +1986,7 @@ ary_join_0(VALUE ary, VALUE sep, long max, VALUE result) if (i > 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); rb_str_buf_append(result, val); + if (OBJ_TAINTED(val)) OBJ_TAINT(result); } } @@ -2347,9 +2047,11 @@ VALUE rb_ary_join(VALUE ary, VALUE sep) { long len = 1, i; + int taint = FALSE; VALUE val, tmp, result; if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0); + if (OBJ_TAINTED(ary)) taint = TRUE; if (!NIL_P(sep)) { StringValue(sep); @@ -2363,6 +2065,7 @@ rb_ary_join(VALUE ary, VALUE sep) int first; result = rb_str_buf_new(len + (RARRAY_LEN(ary)-i)*10); rb_enc_associate(result, rb_usascii_encoding()); + if (taint) OBJ_TAINT(result); ary_join_0(ary, sep, i, result); first = i == 0; ary_join_1(ary, ary, sep, i, result, &first); @@ -2372,9 +2075,8 @@ rb_ary_join(VALUE ary, VALUE sep) len += RSTRING_LEN(tmp); } - result = rb_str_new(0, len); - rb_str_set_len(result, 0); - + result = rb_str_buf_new(len); + if (taint) OBJ_TAINT(result); ary_join_0(ary, sep, RARRAY_LEN(ary), result); return result; @@ -2403,12 +2105,8 @@ rb_ary_join_m(int argc, VALUE *argv, VALUE ary) { VALUE sep; - if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) { - sep = rb_output_fs; - if (!NIL_P(sep)) { - rb_warn("$, is set to non-nil value"); - } - } + rb_scan_args(argc, argv, "01", &sep); + if (NIL_P(sep)) sep = rb_output_fs; return rb_ary_join(ary, sep); } @@ -2416,6 +2114,7 @@ rb_ary_join_m(int argc, VALUE *argv, VALUE ary) static VALUE inspect_ary(VALUE ary, VALUE dummy, int recur) { + int tainted = OBJ_TAINTED(ary); long i; VALUE s, str; @@ -2423,11 +2122,13 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) str = rb_str_buf_new2("["); for (i=0; i<RARRAY_LEN(ary); i++) { s = rb_inspect(RARRAY_AREF(ary, i)); + if (OBJ_TAINTED(s)) tainted = TRUE; if (i > 0) rb_str_buf_cat2(str, ", "); else rb_enc_copy(str, s); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); + if (tainted) OBJ_TAINT(str); return str; } @@ -2436,8 +2137,7 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) * ary.inspect -> string * ary.to_s -> string * - * Creates a string representation of +self+, by calling #inspect - * on each element. + * Creates a string representation of +self+. * * [ "a", "b", "c" ].to_s #=> "[\"a\", \"b\", \"c\"]" */ @@ -2477,20 +2177,13 @@ rb_ary_to_a(VALUE ary) /* * call-seq: - * ary.to_h -> hash - * ary.to_h {|item| block } -> hash + * ary.to_h -> hash * * Returns the result of interpreting <i>ary</i> as an array of * <tt>[key, value]</tt> pairs. * * [[:foo, :bar], [1, 2]].to_h * # => {:foo => :bar, 1 => 2} - * - * If a block is given, the results of the block on each element of - * the array will be used as pairs. - * - * ["foo", "bar"].to_h {|s| [s.ord, s]} - * # => {102=>"foo", 98=>"bar"} */ static VALUE @@ -2498,11 +2191,8 @@ rb_ary_to_h(VALUE ary) { long i; VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary)); - int block_given = rb_block_given_p(); - for (i=0; i<RARRAY_LEN(ary); i++) { - const VALUE e = rb_ary_elt(ary, i); - const VALUE elt = block_given ? rb_yield_force_blockarg(e) : e; + const VALUE elt = rb_ary_elt(ary, i); const VALUE key_value_pair = rb_check_array_type(elt); if (NIL_P(key_value_pair)) { rb_raise(rb_eTypeError, "wrong element type %"PRIsVALUE" at %ld (expected array)", @@ -2548,9 +2238,9 @@ rb_ary_reverse(VALUE ary) rb_ary_modify(ary); if (len > 1) { - RARRAY_PTR_USE_TRANSIENT(ary, p1, { - p2 = p1 + len - 1; /* points last item */ - ary_reverse(p1, p2); + RARRAY_PTR_USE(ary, p1, { + p2 = p1 + len - 1; /* points last item */ + ary_reverse(p1, p2); }); /* WB: no new reference */ } return ary; @@ -2590,8 +2280,8 @@ rb_ary_reverse_m(VALUE ary) VALUE dup = rb_ary_new2(len); if (len > 0) { - const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary); - VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1; + const VALUE *p1 = RARRAY_CONST_PTR(ary); + VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1; do *p2-- = *p1++; while (--len > 0); } ARY_SET_LEN(dup, RARRAY_LEN(ary)); @@ -2604,27 +2294,24 @@ rotate_count(long cnt, long len) return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len); } -static void -ary_rotate_ptr(VALUE *ptr, long len, long cnt) -{ - --len; - if (cnt < len) ary_reverse(ptr + cnt, ptr + len); - if (--cnt > 0) ary_reverse(ptr, ptr + cnt); - if (len > 0) ary_reverse(ptr, ptr + len); -} - VALUE rb_ary_rotate(VALUE ary, long cnt) { rb_ary_modify(ary); if (cnt != 0) { - long len = RARRAY_LEN(ary); - if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt)); - return ary; - } + VALUE *ptr = RARRAY_PTR(ary); + long len = RARRAY_LEN(ary); + + if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) { + --len; + if (cnt < len) ary_reverse(ptr + cnt, ptr + len); + if (--cnt > 0) ary_reverse(ptr, ptr + cnt); + if (len > 0) ary_reverse(ptr, ptr + len); + return ary; + } } + return Qnil; } @@ -2648,7 +2335,13 @@ rb_ary_rotate(VALUE ary, long cnt) static VALUE rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary) { - long n = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1); + long n = 1; + + switch (argc) { + case 1: n = NUM2LONG(argv[0]); + case 0: break; + default: rb_scan_args(argc, argv, "01", NULL); + } rb_ary_rotate(ary, n); return ary; } @@ -2675,14 +2368,19 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) { VALUE rotated; const VALUE *ptr; - long len; - long cnt = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1); + long len, cnt = 1; + + switch (argc) { + case 1: cnt = NUM2LONG(argv[0]); + case 0: break; + default: rb_scan_args(argc, argv, "01", NULL); + } len = RARRAY_LEN(ary); rotated = rb_ary_new2(len); if (len > 0) { cnt = rotate_count(cnt, len); - ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + ptr = RARRAY_CONST_PTR(ary); len -= cnt; ary_memcpy(rotated, 0, len, ptr + cnt); ary_memcpy(rotated, len, cnt, ptr); @@ -2752,7 +2450,7 @@ sort_2(const void *ap, const void *bp, void *dummy) /* * call-seq: * ary.sort! -> ary - * ary.sort! {|a, b| block} -> ary + * ary.sort! { |a, b| block } -> ary * * Sorts +self+ in place. * @@ -2768,7 +2466,7 @@ sort_2(const void *ap, const void *bp, void *dummy) * * ary = [ "d", "a", "e", "c", "b" ] * ary.sort! #=> ["a", "b", "c", "d", "e"] - * ary.sort! {|a, b| b <=> a} #=> ["e", "d", "c", "b", "a"] + * ary.sort! { |a, b| b <=> a } #=> ["e", "d", "c", "b", "a"] * * See also Enumerable#sort_by. */ @@ -2782,13 +2480,14 @@ rb_ary_sort_bang(VALUE ary) VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */ struct ary_sort_data data; long len = RARRAY_LEN(ary); + RBASIC_CLEAR_CLASS(tmp); data.ary = tmp; data.cmp_opt.opt_methods = 0; data.cmp_opt.opt_inited = 0; RARRAY_PTR_USE(tmp, ptr, { - ruby_qsort(ptr, len, sizeof(VALUE), - rb_block_given_p()?sort_1:sort_2, &data); + ruby_qsort(ptr, len, sizeof(VALUE), + rb_block_given_p()?sort_1:sort_2, &data); }); /* WB: no new reference */ rb_ary_modify(ary); if (ARY_EMBED_P(tmp)) { @@ -2814,29 +2513,28 @@ rb_ary_sort_bang(VALUE ary) rb_ary_unshare(ary); } else { - ary_heap_free(ary); + ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary)); } - ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp)); + ARY_SET_PTR(ary, RARRAY_CONST_PTR(tmp)); ARY_SET_HEAP_LEN(ary, len); - ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp)); + ARY_SET_CAPA(ary, RARRAY_LEN(tmp)); } /* tmp was lost ownership for the ptr */ FL_UNSET(tmp, FL_FREEZE); FL_SET_EMBED(tmp); ARY_SET_EMBED_LEN(tmp, 0); FL_SET(tmp, FL_FREEZE); - } + } /* tmp will be GC'ed. */ RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */ } - ary_verify(ary); return ary; } /* * call-seq: * ary.sort -> new_ary - * ary.sort {|a, b| block} -> new_ary + * ary.sort { |a, b| block } -> new_ary * * Returns a new array created by sorting +self+. * @@ -2852,12 +2550,7 @@ rb_ary_sort_bang(VALUE ary) * * ary = [ "d", "a", "e", "c", "b" ] * ary.sort #=> ["a", "b", "c", "d", "e"] - * ary.sort {|a, b| b <=> a} #=> ["e", "d", "c", "b", "a"] - * - * To produce the reverse order, the following can also be used - * (and may be faster): - * - * ary.sort.reverse! #=> ["e", "d", "c", "b", "a"] + * ary.sort { |a, b| b <=> a } #=> ["e", "d", "c", "b", "a"] * * See also Enumerable#sort_by. */ @@ -3005,7 +2698,7 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy)) /* * call-seq: - * ary.sort_by! {|obj| block} -> ary + * ary.sort_by! { |obj| block } -> ary * ary.sort_by! -> Enumerator * * Sorts +self+ in place using a set of keys generated by mapping the @@ -3034,8 +2727,8 @@ rb_ary_sort_by_bang(VALUE ary) /* * call-seq: - * ary.collect {|item| block} -> new_ary - * ary.map {|item| block} -> new_ary + * ary.collect { |item| block } -> new_ary + * ary.map { |item| block } -> new_ary * ary.collect -> Enumerator * ary.map -> Enumerator * @@ -3048,8 +2741,8 @@ rb_ary_sort_by_bang(VALUE ary) * If no block is given, an Enumerator is returned instead. * * a = [ "a", "b", "c", "d" ] - * a.collect {|x| x + "!"} #=> ["a!", "b!", "c!", "d!"] - * a.map.with_index {|x, i| x * i} #=> ["", "b", "cc", "ddd"] + * a.collect { |x| x + "!" } #=> ["a!", "b!", "c!", "d!"] + * a.map.with_index { |x, i| x * i } #=> ["", "b", "cc", "ddd"] * a #=> ["a", "b", "c", "d"] */ @@ -3062,7 +2755,7 @@ rb_ary_collect(VALUE ary) RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); collect = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { - rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i))); + rb_ary_push(collect, rb_yield_force_blockarg(RARRAY_AREF(ary, i))); } return collect; } @@ -3128,34 +2821,6 @@ rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func return result; } -static VALUE -append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx) -{ - long beg, len; - if (FIXNUM_P(idx)) { - beg = FIX2LONG(idx); - } - /* check if idx is Range */ - else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) { - if (len > 0) { - const VALUE *const src = RARRAY_CONST_PTR_TRANSIENT(ary); - const long end = beg + len; - const long prevlen = RARRAY_LEN(result); - if (beg < olen) { - rb_ary_cat(result, src + beg, end > olen ? olen-beg : len); - } - if (end > olen) { - rb_ary_store(result, prevlen + len - 1, Qnil); - } - } - return result; - } - else { - beg = NUM2LONG(idx); - } - return rb_ary_push(result, rb_ary_entry(ary, beg)); -} - /* * call-seq: * ary.values_at(selector, ...) -> new_ary @@ -3177,36 +2842,26 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx) static VALUE rb_ary_values_at(int argc, VALUE *argv, VALUE ary) { - long i, olen = RARRAY_LEN(ary); - VALUE result = rb_ary_new_capa(argc); - for (i = 0; i < argc; ++i) { - append_values_at_single(result, ary, olen, argv[i]); - } - RB_GC_GUARD(ary); - return result; + return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry); } /* * call-seq: - * ary.select {|item| block} -> new_ary + * ary.select { |item| block } -> new_ary * ary.select -> Enumerator - * ary.filter {|item| block} -> new_ary - * ary.filter -> Enumerator * * Returns a new array containing all elements of +ary+ * for which the given +block+ returns a true value. * * If no block is given, an Enumerator is returned instead. * - * [1,2,3,4,5].select {|num| num.even? } #=> [2, 4] + * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4] * - * a = %w[ a b c d e f ] - * a.select {|v| v =~ /[aeiou]/ } #=> ["a", "e"] + * a = %w{ a b c d e f } + * a.select { |v| v =~ /[aeiou]/ } #=> ["a", "e"] * * See also Enumerable#select. - * - * Array#filter is an alias for Array#select. */ static VALUE @@ -3260,7 +2915,7 @@ select_bang_ensure(VALUE a) long tail = 0; if (i1 < len) { tail = len - i1; - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + i2, ptr + i1, VALUE, tail); }); } @@ -3271,10 +2926,8 @@ select_bang_ensure(VALUE a) /* * call-seq: - * ary.select! {|item| block } -> ary or nil - * ary.select! -> Enumerator - * ary.filter! {|item| block } -> ary or nil - * ary.filter! -> Enumerator + * ary.select! {|item| block } -> ary or nil + * ary.select! -> Enumerator * * Invokes the given block passing in successive elements from +self+, * deleting elements for which the block returns a +false+ value. @@ -3283,11 +2936,10 @@ select_bang_ensure(VALUE a) * * If changes were made, it will return +self+, otherwise it returns +nil+. * - * If no block is given, an Enumerator is returned instead. + * See also Array#keep_if * - * See also Array#keep_if. + * If no block is given, an Enumerator is returned instead. * - * Array#filter! is an alias for Array#select!. */ static VALUE @@ -3305,19 +2957,18 @@ rb_ary_select_bang(VALUE ary) /* * call-seq: - * ary.keep_if {|item| block} -> ary + * ary.keep_if { |item| block } -> ary * ary.keep_if -> Enumerator * * Deletes every element of +self+ for which the given block evaluates to - * +false+, and returns +self+. + * +false+. * - * If no block is given, an Enumerator is returned instead. + * See also Array#select! * - * a = %w[ a b c d e f ] - * a.keep_if {|v| v =~ /[aeiou]/ } #=> ["a", "e"] - * a #=> ["a", "e"] + * If no block is given, an Enumerator is returned instead. * - * See also Array#select!. + * a = %w{ a b c d e f } + * a.keep_if { |v| v =~ /[aeiou]/ } #=> ["a", "e"] */ static VALUE @@ -3344,7 +2995,7 @@ ary_resize_smaller(VALUE ary, long len) /* * call-seq: * ary.delete(obj) -> item or nil - * ary.delete(obj) {block} -> item or result of block + * ary.delete(obj) { block } -> item or result of block * * Deletes all items from +self+ that are equal to +obj+. * @@ -3358,7 +3009,7 @@ ary_resize_smaller(VALUE ary, long len) * a.delete("b") #=> "b" * a #=> ["a", "c"] * a.delete("z") #=> nil - * a.delete("z") {"not found"} #=> "not found" + * a.delete("z") { "not found" } #=> "not found" */ VALUE @@ -3388,7 +3039,6 @@ rb_ary_delete(VALUE ary, VALUE item) ary_resize_smaller(ary, i2); - ary_verify(ary); return v; } @@ -3429,11 +3079,11 @@ rb_ary_delete_at(VALUE ary, long pos) rb_ary_modify(ary); del = RARRAY_AREF(ary, pos); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { - MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1); + RARRAY_PTR_USE(ary, ptr, { + MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1); }); ARY_INCREASE_LEN(ary, -1); - ary_verify(ary); + return del; } @@ -3501,13 +3151,16 @@ rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary) len = orig_len - pos; } if (len == 0) return rb_ary_new2(0); - arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos); + arg2 = rb_ary_new4(len, RARRAY_CONST_PTR(ary)+pos); RBASIC_SET_CLASS(arg2, rb_obj_class(ary)); rb_ary_splice(ary, pos, len, 0, 0); return arg2; } - rb_check_arity(argc, 1, 2); + if (argc != 1) { + /* error report */ + rb_scan_args(argc, argv, "11", NULL, NULL); + } arg1 = argv[0]; if (!FIXNUM_P(arg1)) { @@ -3534,8 +3187,7 @@ ary_reject(VALUE orig, VALUE result) for (i = 0; i < RARRAY_LEN(orig); i++) { VALUE v = RARRAY_AREF(orig, i); - - if (!RTEST(rb_yield(v))) { + if (!RTEST(rb_yield(v))) { rb_ary_push(result, v); } } @@ -3564,6 +3216,7 @@ static VALUE ary_reject_bang(VALUE ary) { struct select_bang_arg args; + rb_ary_modify_check(ary); args.ary = ary; args.len[0] = args.len[1] = 0; @@ -3572,7 +3225,7 @@ ary_reject_bang(VALUE ary) /* * call-seq: - * ary.reject! {|item| block} -> ary or nil + * ary.reject! { |item| block } -> ary or nil * ary.reject! -> Enumerator * * Deletes every element of +self+ for which the block evaluates to +true+, @@ -3619,7 +3272,7 @@ rb_ary_reject(VALUE ary) /* * call-seq: - * ary.delete_if {|item| block} -> ary + * ary.delete_if { |item| block } -> ary * ary.delete_if -> Enumerator * * Deletes every element of +self+ for which block evaluates to +true+. @@ -3638,7 +3291,6 @@ rb_ary_reject(VALUE ary) static VALUE rb_ary_delete_if(VALUE ary) { - ary_verify(ary); RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); ary_reject_bang(ary); return ary; @@ -3648,8 +3300,7 @@ static VALUE take_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, cbarg)) { VALUE *args = (VALUE *)cbarg; - if (args[1] == 0) rb_iter_break(); - else args[1]--; + if (args[1]-- == 0) rb_iter_break(); if (argc > 1) val = rb_ary_new4(argc, argv); rb_ary_push(args[0], val); return Qnil; @@ -3674,7 +3325,7 @@ take_items(VALUE obj, long n) /* * call-seq: * ary.zip(arg, ...) -> new_ary - * ary.zip(arg, ...) {|arr| block} -> nil + * ary.zip(arg, ...) { |arr| block } -> nil * * Converts any arguments to arrays, then merges elements of +self+ with * corresponding elements from each argument. @@ -3815,36 +3466,35 @@ rb_ary_replace(VALUE copy, VALUE orig) if (copy == orig) return copy; if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) { - VALUE shared_root = 0; + VALUE shared = 0; if (ARY_OWNS_HEAP_P(copy)) { - ary_heap_free(copy); + RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy))); } else if (ARY_SHARED_P(copy)) { - shared_root = ARY_SHARED_ROOT(copy); + shared = ARY_SHARED(copy); FL_UNSET_SHARED(copy); } FL_SET_EMBED(copy); - ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig)); - if (shared_root) { - rb_ary_decrement_share(shared_root); + ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig)); + if (shared) { + rb_ary_decrement_share(shared); } ARY_SET_LEN(copy, RARRAY_LEN(orig)); } else { - VALUE shared_root = ary_make_shared(orig); + VALUE shared = ary_make_shared(orig); if (ARY_OWNS_HEAP_P(copy)) { - ary_heap_free(copy); + RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy))); } else { rb_ary_unshare_safe(copy); } FL_UNSET_EMBED(copy); - ARY_SET_PTR(copy, ARY_HEAP_PTR(orig)); - ARY_SET_LEN(copy, ARY_HEAP_LEN(orig)); - rb_ary_set_shared(copy, shared_root); + ARY_SET_PTR(copy, RARRAY_CONST_PTR(orig)); + ARY_SET_LEN(copy, RARRAY_LEN(orig)); + rb_ary_set_shared(copy, shared); } - ary_verify(copy); return copy; } @@ -3862,20 +3512,16 @@ VALUE rb_ary_clear(VALUE ary) { rb_ary_modify_check(ary); + ARY_SET_LEN(ary, 0); if (ARY_SHARED_P(ary)) { if (!ARY_EMBED_P(ary)) { rb_ary_unshare(ary); FL_SET_EMBED(ary); - ARY_SET_EMBED_LEN(ary, 0); } } - else { - ARY_SET_LEN(ary, 0); - if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { - ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); - } + else if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { + ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); } - ary_verify(ary); return ary; } @@ -3883,10 +3529,10 @@ rb_ary_clear(VALUE ary) * call-seq: * ary.fill(obj) -> ary * ary.fill(obj, start [, length]) -> ary - * ary.fill(obj, range) -> ary - * ary.fill {|index| block} -> ary - * ary.fill(start [, length]) {|index| block} -> ary - * ary.fill(range) {|index| block} -> ary + * ary.fill(obj, range ) -> ary + * ary.fill { |index| block } -> ary + * ary.fill(start [, length] ) { |index| block } -> ary + * ary.fill(range) { |index| block } -> ary * * The first three forms set the selected elements of +self+ (which * may be the entire array) to +obj+. @@ -3905,8 +3551,8 @@ rb_ary_clear(VALUE ary) * a.fill("x") #=> ["x", "x", "x", "x"] * a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] * a.fill("y", 0..1) #=> ["y", "y", "z", "z"] - * a.fill {|i| i*i} #=> [0, 1, 4, 9] - * a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27] + * a.fill { |i| i*i } #=> [0, 1, 4, 9] + * a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27] */ static VALUE @@ -4008,8 +3654,8 @@ rb_ary_plus(VALUE x, VALUE y) len = xlen + ylen; z = rb_ary_new2(len); - ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR_TRANSIENT(x)); - ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y)); + ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x)); + ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y)); ARY_SET_LEN(z, len); return z; } @@ -4019,23 +3665,23 @@ ary_append(VALUE x, VALUE y) { long n = RARRAY_LEN(y); if (n > 0) { - rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n); + rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n); } return x; } /* * call-seq: - * ary.concat(other_ary1, other_ary2, ...) -> ary + * ary.concat(other_ary1, other_ary2,...) -> ary * - * Appends the elements of <code>other_ary</code>s to +self+. + * Appends the elements of +other_ary+s to +self+. * - * [ "a", "b" ].concat( ["c", "d"]) #=> [ "a", "b", "c", "d" ] - * [ "a" ].concat( ["b"], ["c", "d"]) #=> [ "a", "b", "c", "d" ] + * [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ] + * [ "a" ].concat( ["b"], ["c", "d"] ) #=> [ "a", "b", "c", "d" ] * [ "a" ].concat #=> [ "a" ] * * a = [ 1, 2, 3 ] - * a.concat( [ 4, 5 ]) + * a.concat( [ 4, 5 ] ) * a #=> [ 1, 2, 3, 4, 5 ] * * a = [ 1, 2 ] @@ -4061,7 +3707,6 @@ rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary) ary_append(ary, args); } - ary_verify(ary); return ary; } @@ -4116,19 +3761,21 @@ rb_ary_times(VALUE ary, VALUE times) ary2 = ary_new(rb_obj_class(ary), len); ARY_SET_LEN(ary2, len); - ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + ptr = RARRAY_CONST_PTR(ary); t = RARRAY_LEN(ary); if (0 < t) { ary_memcpy(ary2, 0, t, ptr); while (t <= len/2) { - ary_memcpy(ary2, t, t, RARRAY_CONST_PTR_TRANSIENT(ary2)); + ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2)); t *= 2; } if (t < len) { - ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2)); + ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2)); } } out: + OBJ_INFECT(ary2, ary); + return ary2; } @@ -4209,7 +3856,6 @@ recursive_equal(VALUE ary1, VALUE ary2, int recur) if (recur) return Qtrue; /* Subtle! */ - /* rb_equal() can evacuate ptrs */ p1 = RARRAY_CONST_PTR(ary1); p2 = RARRAY_CONST_PTR(ary2); len1 = RARRAY_LEN(ary1); @@ -4222,8 +3868,8 @@ recursive_equal(VALUE ary1, VALUE ary2, int recur) return Qfalse; if (len1 < i) return Qtrue; - p1 = RARRAY_CONST_PTR(ary1) + i; - p2 = RARRAY_CONST_PTR(ary2) + i; + p1 = RARRAY_CONST_PTR(ary1) + i; + p2 = RARRAY_CONST_PTR(ary2) + i; } else { return Qfalse; @@ -4260,7 +3906,7 @@ rb_ary_equal(VALUE ary1, VALUE ary2) return rb_equal(ary2, ary1); } if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; - if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue; + if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2); } @@ -4291,7 +3937,7 @@ rb_ary_eql(VALUE ary1, VALUE ary2) if (ary1 == ary2) return Qtrue; if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse; if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; - if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue; + if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } @@ -4485,11 +4131,11 @@ static inline void ary_recycle_hash(VALUE hash) { assert(RBASIC_CLASS(hash) == 0); - if (RHASH_ST_TABLE_P(hash)) { - st_table *tbl = RHASH_ST_TABLE(hash); + if (RHASH(hash)->ntbl) { + st_table *tbl = RHASH(hash)->ntbl; st_free_table(tbl); - RHASH_ST_CLEAR(hash); } + rb_gc_force_recycle(hash); } /* @@ -4498,21 +4144,15 @@ ary_recycle_hash(VALUE hash) * * Array Difference * - * Returns a new array that is a copy of the original array, removing all - * occurrences of any item that also appear in +other_ary+. The order is - * preserved from the original array. + * Returns a new array that is a copy of the original array, removing any + * items that also appear in +other_ary+. The order is preserved from the + * original array. * * It compares elements using their #hash and #eql? methods for efficiency. * * [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] * - * Note that while 1 and 2 were only present once in the array argument, and - * were present twice in the receiver array, all occurrences of each Integer are - * removed in the returned array. - * * If you need set-like behavior, see the library class Set. - * - * See also Array#difference. */ static VALUE @@ -4536,7 +4176,7 @@ rb_ary_diff(VALUE ary1, VALUE ary2) hash = ary_make_hash(ary2); for (i=0; i<RARRAY_LEN(ary1); i++) { - if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue; + if (st_lookup(rb_hash_tbl_raw(hash), RARRAY_AREF(ary1, i), 0)) continue; rb_ary_push(ary3, rb_ary_elt(ary1, i)); } ary_recycle_hash(hash); @@ -4545,72 +4185,6 @@ rb_ary_diff(VALUE ary1, VALUE ary2) /* * call-seq: - * ary.difference(other_ary1, other_ary2, ...) -> new_ary - * - * Array Difference - * - * Returns a new array that is a copy of the original array, removing all - * occurrences of any item that also appear in +other_ary+. The order is - * preserved from the original array. - * - * It compares elements using their #hash and #eql? methods for efficiency. - * - * [ 1, 1, 2, 2, 3, 3, 4, 5 ].difference([ 1, 2, 4 ]) #=> [ 3, 3, 5 ] - * - * Note that while 1 and 2 were only present once in the array argument, and - * were present twice in the receiver array, all occurrences of each Integer are - * removed in the returned array. - * - * Multiple array arguments can be supplied and all occurrences of any element - * in those supplied arrays that match the receiver will be removed from the - * returned array. - * - * [ 1, 'c', :s, 'yep' ].difference([ 1 ], [ 'a', 'c' ]) #=> [ :s, "yep" ] - * - * If you need set-like behavior, see the library class Set. - * - * See also Array#-. - */ - -static VALUE -rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary) -{ - VALUE ary_diff; - long i, length; - volatile VALUE t0; - bool *is_hash = ALLOCV_N(bool, t0, argc); - ary_diff = rb_ary_new(); - length = RARRAY_LEN(ary); - - for (i = 0; i < argc; i++) { - argv[i] = to_ary(argv[i]); - is_hash[i] = (length > SMALL_ARRAY_LEN && RARRAY_LEN(argv[i]) > SMALL_ARRAY_LEN); - if (is_hash[i]) argv[i] = ary_make_hash(argv[i]); - } - - for (i = 0; i < RARRAY_LEN(ary); i++) { - int j; - VALUE elt = rb_ary_elt(ary, i); - for (j = 0; j < argc; j++) { - if (is_hash[j]) { - if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL)) - break; - } - else { - if (rb_ary_includes_by_eql(argv[j], elt)) break; - } - } - if (j == argc) rb_ary_push(ary_diff, elt); - } - - ALLOCV_END(t0); - - return ary_diff; -} - - -/* - * call-seq: * ary & other_ary -> new_ary * * Set Intersection --- Returns a new array containing unique elements common to the @@ -4629,12 +4203,13 @@ static VALUE rb_ary_and(VALUE ary1, VALUE ary2) { VALUE hash, ary3, v; + st_table *table; st_data_t vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new(); - if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return ary3; + if (RARRAY_LEN(ary2) == 0) return ary3; if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { for (i=0; i<RARRAY_LEN(ary1); i++) { @@ -4647,11 +4222,12 @@ rb_ary_and(VALUE ary1, VALUE ary2) } hash = ary_make_hash(ary2); + table = rb_hash_tbl_raw(hash); for (i=0; i<RARRAY_LEN(ary1); i++) { v = RARRAY_AREF(ary1, i); vv = (st_data_t)v; - if (rb_hash_stlike_delete(hash, &vv, 0)) { + if (st_delete(table, &vv, 0)) { rb_ary_push(ary3, v); } } @@ -4660,36 +4236,6 @@ rb_ary_and(VALUE ary1, VALUE ary2) return ary3; } -/* - * call-seq: - * ary.intersection(other_ary1, other_ary2, ...) -> new_ary - * - * Set Intersection --- Returns a new array containing unique elements common - * to +self+ and <code>other_ary</code>s. Order is preserved from the original - * array. - * - * It compares elements using their #hash and #eql? methods for efficiency. - * - * [ 1, 1, 3, 5 ].intersection([ 3, 2, 1 ]) # => [ 1, 3 ] - * [ "a", "b", "z" ].intersection([ "a", "b", "c" ], [ "b" ]) # => [ "b" ] - * [ "a" ].intersection #=> [ "a" ] - * - * See also Array#&. - */ - -static VALUE -rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary) -{ - VALUE result = rb_ary_dup(ary); - int i; - - for (i = 0; i < argc; i++) { - result = rb_ary_and(result, argv[i]); - } - - return result; -} - static int ary_hash_orset(st_data_t *key, st_data_t *value, st_data_t arg, int existing) { @@ -4698,29 +4244,6 @@ ary_hash_orset(st_data_t *key, st_data_t *value, st_data_t arg, int existing) return ST_CONTINUE; } -static void -rb_ary_union(VALUE ary_union, VALUE ary) -{ - long i; - for (i = 0; i < RARRAY_LEN(ary); i++) { - VALUE elt = rb_ary_elt(ary, i); - if (rb_ary_includes_by_eql(ary_union, elt)) continue; - rb_ary_push(ary_union, elt); - } -} - -static void -rb_ary_union_hash(VALUE hash, VALUE ary2) -{ - long i; - for (i = 0; i < RARRAY_LEN(ary2); i++) { - VALUE elt = RARRAY_AREF(ary2, i); - if (!rb_hash_stlike_update(hash, (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) { - RB_OBJ_WRITTEN(hash, Qundef, elt); - } - } -} - /* * call-seq: * ary | other_ary -> new_ary @@ -4733,25 +4256,38 @@ rb_ary_union_hash(VALUE hash, VALUE ary2) * [ "a", "b", "c" ] | [ "c", "d", "a" ] #=> [ "a", "b", "c", "d" ] * [ "c", "d", "a" ] | [ "a", "b", "c" ] #=> [ "c", "d", "a", "b" ] * - * See also Array#union. + * See also Array#uniq. */ static VALUE rb_ary_or(VALUE ary1, VALUE ary2) { VALUE hash, ary3; + long i; ary2 = to_ary(ary2); if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { ary3 = rb_ary_new(); - rb_ary_union(ary3, ary1); - rb_ary_union(ary3, ary2); + for (i=0; i<RARRAY_LEN(ary1); i++) { + VALUE elt = rb_ary_elt(ary1, i); + if (rb_ary_includes_by_eql(ary3, elt)) continue; + rb_ary_push(ary3, elt); + } + for (i=0; i<RARRAY_LEN(ary2); i++) { + VALUE elt = rb_ary_elt(ary2, i); + if (rb_ary_includes_by_eql(ary3, elt)) continue; + rb_ary_push(ary3, elt); + } return ary3; } hash = ary_make_hash(ary1); - rb_ary_union_hash(hash, ary2); - + for (i=0; i<RARRAY_LEN(ary2); i++) { + VALUE elt = RARRAY_AREF(ary2, i); + if (!st_update(RHASH_TBL_RAW(hash), (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) { + RB_OBJ_WRITTEN(hash, Qundef, elt); + } + } ary3 = rb_hash_values(hash); ary_recycle_hash(hash); return ary3; @@ -4759,64 +4295,18 @@ rb_ary_or(VALUE ary1, VALUE ary2) /* * call-seq: - * ary.union(other_ary1, other_ary2, ...) -> new_ary - * - * Set Union --- Returns a new array by joining <code>other_ary</code>s with +self+, - * excluding any duplicates and preserving the order from the given arrays. - * - * It compares elements using their #hash and #eql? methods for efficiency. - * - * [ "a", "b", "c" ].union( [ "c", "d", "a" ] ) #=> [ "a", "b", "c", "d" ] - * [ "a" ].union( ["e", "b"], ["a", "c", "b"] ) #=> [ "a", "e", "b", "c" ] - * [ "a" ].union #=> [ "a" ] - * - * See also Array#|. - */ - -static VALUE -rb_ary_union_multi(int argc, VALUE *argv, VALUE ary) -{ - int i; - long sum; - VALUE hash, ary_union; - - sum = RARRAY_LEN(ary); - for (i = 0; i < argc; i++) { - argv[i] = to_ary(argv[i]); - sum += RARRAY_LEN(argv[i]); - } - - if (sum <= SMALL_ARRAY_LEN) { - ary_union = rb_ary_new(); - - rb_ary_union(ary_union, ary); - for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]); - - return ary_union; - } - - hash = ary_make_hash(ary); - for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]); - - ary_union = rb_hash_values(hash); - ary_recycle_hash(hash); - return ary_union; -} - -/* - * call-seq: * ary.max -> obj - * ary.max {|a, b| block} -> obj + * ary.max { |a, b| block } -> obj * ary.max(n) -> array - * ary.max(n) {|a, b| block} -> array + * ary.max(n) { |a, b| block } -> array * * Returns the object in _ary_ with the maximum value. The - * first form assumes all objects implement Comparable; + * first form assumes all objects implement <code>Comparable</code>; * the second uses the block to return <em>a <=> b</em>. * * ary = %w(albatross dog horse) * ary.max #=> "horse" - * ary.max {|a, b| a.length <=> b.length} #=> "albatross" + * ary.max { |a, b| a.length <=> b.length } #=> "albatross" * * If the +n+ argument is given, maximum +n+ elements are returned * as an array. @@ -4833,7 +4323,9 @@ rb_ary_max(int argc, VALUE *argv, VALUE ary) VALUE num; long i; - if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0])) + rb_scan_args(argc, argv, "01", &num); + + if (!NIL_P(num)) return rb_nmin_run(ary, num, 0, 1, 1); if (rb_block_given_p()) { @@ -4864,12 +4356,12 @@ rb_ary_max(int argc, VALUE *argv, VALUE ary) * ary.min(n) {| a,b | block } -> array * * Returns the object in _ary_ with the minimum value. The - * first form assumes all objects implement Comparable; + * first form assumes all objects implement <code>Comparable</code>; * the second uses the block to return <em>a <=> b</em>. * * ary = %w(albatross dog horse) * ary.min #=> "albatross" - * ary.min {|a, b| a.length <=> b.length} #=> "dog" + * ary.min { |a, b| a.length <=> b.length } #=> "dog" * * If the +n+ argument is given, minimum +n+ elements are returned * as an array. @@ -4886,7 +4378,9 @@ rb_ary_min(int argc, VALUE *argv, VALUE ary) VALUE num; long i; - if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0])) + rb_scan_args(argc, argv, "01", &num); + + if (!NIL_P(num)) return rb_nmin_run(ary, num, 0, 0, 1); if (rb_block_given_p()) { @@ -4909,26 +4403,6 @@ rb_ary_min(int argc, VALUE *argv, VALUE ary) return result; } -/* - * call-seq: - * ary.minmax -> [obj, obj] - * ary.minmax {| a,b | block } -> [obj, obj] - * - * Returns a two element array which contains the minimum and the - * maximum value in the array. - * - * Can be given an optional block to override the default comparison - * method <code>a <=> b</code>. - */ -static VALUE -rb_ary_minmax(VALUE ary) -{ - if (rb_block_given_p()) { - return rb_call_super(0, NULL); - } - return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary)); -} - static int push_value(st_data_t key, st_data_t val, st_data_t ary) { @@ -4939,7 +4413,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary) /* * call-seq: * ary.uniq! -> ary or nil - * ary.uniq! {|item| ...} -> ary or nil + * ary.uniq! { |item| ... } -> ary or nil * * Removes duplicate elements from +self+. * @@ -4959,7 +4433,7 @@ push_value(st_data_t key, st_data_t val, st_data_t ary) * b.uniq! # => nil * * c = [["student","sam"], ["student","george"], ["teacher","matz"]] - * c.uniq! {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]] + * c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] * */ @@ -4988,7 +4462,7 @@ rb_ary_uniq_bang(VALUE ary) FL_SET_EMBED(ary); } ary_resize_capa(ary, hash_size); - rb_hash_foreach(hash, push_value, ary); + st_foreach(rb_hash_tbl_raw(hash), push_value, ary); ary_recycle_hash(hash); return ary; @@ -4997,7 +4471,7 @@ rb_ary_uniq_bang(VALUE ary) /* * call-seq: * ary.uniq -> new_ary - * ary.uniq {|item| ...} -> new_ary + * ary.uniq { |item| ... } -> new_ary * * Returns a new array by removing duplicate values in +self+. * @@ -5011,7 +4485,7 @@ rb_ary_uniq_bang(VALUE ary) * a.uniq # => ["a", "b", "c"] * * b = [["student","sam"], ["student","george"], ["teacher","matz"]] - * b.uniq {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]] + * b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] * */ @@ -5020,11 +4494,9 @@ rb_ary_uniq(VALUE ary) { VALUE hash, uniq; - if (RARRAY_LEN(ary) <= 1) { - hash = 0; - uniq = rb_ary_dup(ary); - } - else if (rb_block_given_p()) { + if (RARRAY_LEN(ary) <= 1) + return rb_ary_dup(ary); + if (rb_block_given_p()) { hash = ary_make_hash_by(ary); uniq = rb_hash_values(hash); } @@ -5033,9 +4505,7 @@ rb_ary_uniq(VALUE ary) uniq = rb_hash_values(hash); } RBASIC_SET_CLASS(uniq, rb_obj_class(ary)); - if (hash) { - ary_recycle_hash(hash); - } + ary_recycle_hash(hash); return uniq; } @@ -5059,14 +4529,14 @@ rb_ary_compact_bang(VALUE ary) long n; rb_ary_modify(ary); - p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); /* WB: no new reference */ + p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */ end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } - n = p - RARRAY_CONST_PTR_TRANSIENT(ary); + n = p - RARRAY_CONST_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } @@ -5097,7 +4567,7 @@ rb_ary_compact(VALUE ary) * call-seq: * ary.count -> int * ary.count(obj) -> int - * ary.count {|item| block} -> int + * ary.count { |item| block } -> int * * Returns the number of elements. * @@ -5110,7 +4580,7 @@ rb_ary_compact(VALUE ary) * ary = [1, 2, 4, 2] * ary.count #=> 4 * ary.count(2) #=> 2 - * ary.count {|x| x%2 == 0} #=> 3 + * ary.count { |x| x%2 == 0 } #=> 3 * */ @@ -5119,7 +4589,7 @@ rb_ary_count(int argc, VALUE *argv, VALUE ary) { long i, n = 0; - if (rb_check_arity(argc, 0, 1) == 0) { + if (argc == 0) { VALUE v; if (!rb_block_given_p()) @@ -5131,8 +4601,9 @@ rb_ary_count(int argc, VALUE *argv, VALUE ary) } } else { - VALUE obj = argv[0]; + VALUE obj; + rb_scan_args(argc, argv, "1", &obj); if (rb_block_given_p()) { rb_warn("given block not used"); } @@ -5145,43 +4616,18 @@ rb_ary_count(int argc, VALUE *argv, VALUE ary) } static VALUE -flatten(VALUE ary, int level) +flatten(VALUE ary, int level, int *modified) { - long i; - VALUE stack, result, tmp, elt, vmemo; - st_table *memo = 0; + long i = 0; + VALUE stack, result, tmp, elt; + st_table *memo; st_data_t id; - for (i = 0; i < RARRAY_LEN(ary); i++) { - elt = RARRAY_AREF(ary, i); - tmp = rb_check_array_type(elt); - if (!NIL_P(tmp)) { - break; - } - } - if (i == RARRAY_LEN(ary)) { - return ary; - } - - result = ary_new(0, RARRAY_LEN(ary)); - ary_memcpy(result, 0, i, RARRAY_CONST_PTR_TRANSIENT(ary)); - ARY_SET_LEN(result, i); - stack = ary_new(0, ARY_DEFAULT_SIZE); - rb_ary_push(stack, ary); - rb_ary_push(stack, LONG2NUM(i + 1)); - - if (level < 0) { - vmemo = rb_hash_new(); - RBASIC_CLEAR_CLASS(vmemo); - memo = st_init_numtable(); - rb_hash_st_table_set(vmemo, memo); - st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue); - st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue); - } - - ary = tmp; - i = 0; + result = ary_new(0, RARRAY_LEN(ary)); + memo = st_init_numtable(); + st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue); + *modified = 0; while (1) { while (i < RARRAY_LEN(ary)) { @@ -5192,24 +4638,19 @@ flatten(VALUE ary, int level) } tmp = rb_check_array_type(elt); if (RBASIC(result)->klass) { - if (memo) { - RB_GC_GUARD(vmemo); - st_clear(memo); - } rb_raise(rb_eRuntimeError, "flatten reentered"); } if (NIL_P(tmp)) { rb_ary_push(result, elt); } else { - if (memo) { - id = (st_data_t)tmp; - if (st_is_member(memo, id)) { - st_clear(memo); - rb_raise(rb_eArgError, "tried to flatten recursive array"); - } - st_insert(memo, id, (st_data_t)Qtrue); + *modified = 1; + id = (st_data_t)tmp; + if (st_lookup(memo, id, 0)) { + st_free_table(memo); + rb_raise(rb_eArgError, "tried to flatten recursive array"); } + st_insert(memo, id, (st_data_t)Qtrue); rb_ary_push(stack, ary); rb_ary_push(stack, LONG2NUM(i)); ary = tmp; @@ -5219,18 +4660,14 @@ flatten(VALUE ary, int level) if (RARRAY_LEN(stack) == 0) { break; } - if (memo) { - id = (st_data_t)ary; - st_delete(memo, &id, 0); - } + id = (st_data_t)ary; + st_delete(memo, &id, 0); tmp = rb_ary_pop(stack); i = NUM2LONG(tmp); ary = rb_ary_pop(stack); } - if (memo) { - st_clear(memo); - } + st_free_table(memo); RBASIC_SET_CLASS(result, rb_obj_class(ary)); return result; @@ -5262,13 +4699,14 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary) int mod = 0, level = -1; VALUE result, lv; - lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil); + rb_scan_args(argc, argv, "01", &lv); rb_ary_modify_check(ary); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return Qnil; - result = flatten(ary, level); - if (result == ary) { + result = flatten(ary, level, &mod); + if (mod == 0) { + ary_discard(result); return Qnil; } if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result); @@ -5303,18 +4741,15 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary) static VALUE rb_ary_flatten(int argc, VALUE *argv, VALUE ary) { - int level = -1; - VALUE result; + int mod = 0, level = -1; + VALUE result, lv; - if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) { - level = NUM2INT(argv[0]); - if (level == 0) return ary_make_shared_copy(ary); - } + rb_scan_args(argc, argv, "01", &lv); + if (!NIL_P(lv)) level = NUM2INT(lv); + if (level == 0) return ary_make_shared_copy(ary); - result = flatten(ary, level); - if (result == ary) { - result = ary_make_shared_copy(ary); - } + result = flatten(ary, level, &mod); + OBJ_INFECT(result, ary); return result; } @@ -5364,8 +4799,8 @@ rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary) while (i) { long j = RAND_UPTO(i); VALUE tmp; - if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) { - rb_raise(rb_eRuntimeError, "modified during shuffle"); + if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) { + rb_raise(rb_eRuntimeError, "modified during shuffle"); } tmp = ptr[--i]; ptr[i] = ptr[j]; @@ -5417,14 +4852,11 @@ rb_ary_shuffle(int argc, VALUE *argv, VALUE ary) * If the array is empty the first form returns +nil+ and the second form * returns an empty array. * + * The optional +rng+ argument will be used as the random number generator. + * * a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] * a.sample #=> 7 * a.sample(4) #=> [6, 4, 2, 5] - * - * The optional +rng+ argument will be used as the random number generator. - * - * a.sample(random: Random.new(1)) #=> 6 - * a.sample(4, random: Random.new(1)) #=> [6, 10, 9, 2] */ @@ -5448,7 +4880,7 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) } } len = RARRAY_LEN(ary); - if (rb_check_arity(argc, 0, 1) == 0) { + if (argc == 0) { if (len < 2) i = 0; else @@ -5456,7 +4888,7 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) return rb_ary_elt(ary, i); } - nv = argv[0]; + rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n < 0) rb_raise(rb_eArgError, "negative sample number"); if (n > len) n = len; @@ -5513,7 +4945,7 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) sorted[j] = idx[i] = k; } result = rb_ary_new_capa(n); - RARRAY_PTR_USE_TRANSIENT(result, ptr_result, { + RARRAY_PTR_USE(result, ptr_result, { for (i=0; i<n; i++) { ptr_result[i] = RARRAY_AREF(ary, idx[i]); } @@ -5536,7 +4968,7 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) len = RARRAY_LEN(ary); if (len <= max_idx) n = 0; else if (n > len) n = len; - RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, { + RARRAY_PTR_USE(ary, ptr_ary, { for (i=0; i<n; i++) { long j2 = j = ptr_result[i]; long i2 = i; @@ -5579,7 +5011,7 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj) n = RARRAY_AREF(args, 0); } if (RARRAY_LEN(self) == 0) return INT2FIX(0); - if (n == Qnil) return DBL2NUM(HUGE_VAL); + if (n == Qnil) return DBL2NUM(INFINITY); mul = NUM2LONG(n); if (mul <= 0) return INT2FIX(0); n = LONG2FIX(mul); @@ -5588,7 +5020,7 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj) /* * call-seq: - * ary.cycle(n=nil) {|obj| block} -> nil + * ary.cycle(n=nil) { |obj| block } -> nil * ary.cycle(n=nil) -> Enumerator * * Calls the given block for each element +n+ times or forever if +nil+ is @@ -5601,8 +5033,8 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj) * If no block is given, an Enumerator is returned instead. * * a = ["a", "b", "c"] - * a.cycle {|x| puts x} # print, a, b, c, a, b, c,.. forever. - * a.cycle(2) {|x| puts x} # print, a, b, c, a, b, c. + * a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever. + * a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c. * */ @@ -5610,15 +5042,16 @@ static VALUE rb_ary_cycle(int argc, VALUE *argv, VALUE ary) { long n, i; + VALUE nv = Qnil; - rb_check_arity(argc, 0, 1); + rb_scan_args(argc, argv, "01", &nv); RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size); - if (argc == 0 || NIL_P(argv[0])) { + if (NIL_P(nv)) { n = -1; } else { - n = NUM2LONG(argv[0]); + n = NUM2LONG(nv); if (n <= 0) return Qnil; } @@ -5630,6 +5063,8 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) return Qnil; } +#define tmpbuf(n, size) rb_str_tmp_new((n)*(size)) +#define tmpbuf_discard(s) (rb_str_resize((s), 0L), RBASIC_SET_CLASS_RAW(s, rb_cString)) #define tmpary(n) rb_ary_tmp_new(n) #define tmpary_discard(a) (ary_discard(a), RBASIC_SET_CLASS_RAW(a, rb_cArray)) @@ -5642,9 +5077,11 @@ static int yield_indexed_values(const VALUE values, const long r, const long *const p) { const VALUE result = rb_ary_new2(r); + VALUE *const result_array = RARRAY_PTR(result); + const VALUE *const values_array = RARRAY_CONST_PTR(values); long i; - for (i = 0; i < r; i++) ARY_SET(result, i, RARRAY_AREF(values, p[i])); + for (i = 0; i < r; i++) result_array[i] = values_array[p[i]]; ARY_SET_LEN(result, r); rb_yield(result); return !RBASIC(values)->klass; @@ -5751,9 +5188,9 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * ary.permutation {|p| block} -> ary + * ary.permutation { |p| block } -> ary * ary.permutation -> Enumerator - * ary.permutation(n) {|p| block} -> ary + * ary.permutation(n) { |p| block } -> ary * ary.permutation(n) -> Enumerator * * When invoked with a block, yield all permutations of length +n+ of the @@ -5780,13 +5217,13 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj) static VALUE rb_ary_permutation(int argc, VALUE *argv, VALUE ary) { + VALUE num; long r, n, i; n = RARRAY_LEN(ary); /* Array length */ RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* Return enumerator if no block */ - r = n; - if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) - r = NUM2LONG(argv[0]); /* Permutation size from argument */ + rb_scan_args(argc, argv, "01", &num); + r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */ if (r < 0 || n < r) { /* no permutations: yield nothing */ @@ -5847,7 +5284,7 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * ary.combination(n) {|c| block} -> ary + * ary.combination(n) { |c| block } -> ary * ary.combination(n) -> Enumerator * * When invoked with a block, yields all combinations of length +n+ of elements @@ -5954,7 +5391,7 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * ary.repeated_permutation(n) {|p| block} -> ary + * ary.repeated_permutation(n) { |p| block } -> ary * ary.repeated_permutation(n) -> Enumerator * * When invoked with a block, yield all repeated permutations of length +n+ of @@ -6044,7 +5481,7 @@ rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * ary.repeated_combination(n) {|c| block} -> ary + * ary.repeated_combination(n) { |c| block } -> ary * ary.repeated_combination(n) -> Enumerator * * When invoked with a block, yields all repeated combinations of length +n+ of @@ -6107,7 +5544,7 @@ rb_ary_repeated_combination(VALUE ary, VALUE num) /* * call-seq: * ary.product(other_ary, ...) -> new_ary - * ary.product(other_ary, ...) {|p| block} -> ary + * ary.product(other_ary, ...) { |p| block } -> ary * * Returns an array of all combinations of elements from all arrays. * @@ -6130,14 +5567,15 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) { int n = argc+1; /* How many arrays we're operating on */ volatile VALUE t0 = tmpary(n); - volatile VALUE t1 = Qundef; + volatile VALUE t1 = tmpbuf(n, sizeof(int)); VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */ - int *counters = ALLOCV_N(int, t1, n); /* The current position in each one */ + int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */ VALUE result = Qnil; /* The array we'll be returning, when no block given */ long i,j; long resultlen = 1; RBASIC_CLEAR_CLASS(t0); + RBASIC_CLEAR_CLASS(t1); /* initialize the arrays of arrays */ ARY_SET_LEN(t0, n); @@ -6208,7 +5646,7 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) } done: tmpary_discard(t0); - ALLOCV_END(t1); + tmpbuf_discard(t1); return NIL_P(result) ? ary : result; } @@ -6240,7 +5678,7 @@ rb_ary_take(VALUE obj, VALUE n) /* * call-seq: - * ary.take_while {|obj| block} -> new_ary + * ary.take_while { |obj| block } -> new_ary * ary.take_while -> Enumerator * * Passes elements to the block until the block returns +nil+ or +false+, then @@ -6251,7 +5689,7 @@ rb_ary_take(VALUE obj, VALUE n) * See also Array#drop_while * * a = [1, 2, 3, 4, 5, 0] - * a.take_while {|i| i < 3} #=> [1, 2] + * a.take_while { |i| i < 3 } #=> [1, 2] * */ @@ -6299,7 +5737,7 @@ rb_ary_drop(VALUE ary, VALUE n) /* * call-seq: - * ary.drop_while {|obj| block} -> new_ary + * ary.drop_while { |obj| block } -> new_ary * ary.drop_while -> Enumerator * * Drops elements up to, but not including, the first element for which the @@ -6329,8 +5767,7 @@ rb_ary_drop_while(VALUE ary) /* * call-seq: - * ary.any? [{|obj| block} ] -> true or false - * ary.any?(pattern) -> true or false + * ary.any? [{ |obj| block }] -> true or false * * See also Enumerable#any? */ @@ -6339,21 +5776,17 @@ static VALUE rb_ary_any_p(int argc, VALUE *argv, VALUE ary) { long i, len = RARRAY_LEN(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); rb_check_arity(argc, 0, 1); if (!len) return Qfalse; if (argc) { - if (rb_block_given_p()) { - rb_warn("given block not used"); - } for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qtrue; } } else if (!rb_block_given_p()) { - for (i = 0; i < len; ++i) { - if (RTEST(RARRAY_AREF(ary, i))) return Qtrue; - } + for (i = 0; i < len; ++i) if (RTEST(ptr[i])) return Qtrue; } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { @@ -6364,124 +5797,6 @@ rb_ary_any_p(int argc, VALUE *argv, VALUE ary) } /* - * call-seq: - * ary.all? [{|obj| block} ] -> true or false - * ary.all?(pattern) -> true or false - * - * See also Enumerable#all? - */ - -static VALUE -rb_ary_all_p(int argc, VALUE *argv, VALUE ary) -{ - long i, len = RARRAY_LEN(ary); - - rb_check_arity(argc, 0, 1); - if (!len) return Qtrue; - if (argc) { - if (rb_block_given_p()) { - rb_warn("given block not used"); - } - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (!RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse; - } - } - else if (!rb_block_given_p()) { - for (i = 0; i < len; ++i) { - if (!RTEST(RARRAY_AREF(ary, i))) return Qfalse; - } - } - else { - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse; - } - } - return Qtrue; -} - -/* - * call-seq: - * ary.none? [{|obj| block} ] -> true or false - * ary.none?(pattern) -> true or false - * - * See also Enumerable#none? - */ - -static VALUE -rb_ary_none_p(int argc, VALUE *argv, VALUE ary) -{ - long i, len = RARRAY_LEN(ary); - - rb_check_arity(argc, 0, 1); - if (!len) return Qtrue; - if (argc) { - if (rb_block_given_p()) { - rb_warn("given block not used"); - } - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse; - } - } - else if (!rb_block_given_p()) { - for (i = 0; i < len; ++i) { - if (RTEST(RARRAY_AREF(ary, i))) return Qfalse; - } - } - else { - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse; - } - } - return Qtrue; -} - -/* - * call-seq: - * ary.one? [{|obj| block} ] -> true or false - * ary.one?(pattern) -> true or false - * - * See also Enumerable#one? - */ - -static VALUE -rb_ary_one_p(int argc, VALUE *argv, VALUE ary) -{ - long i, len = RARRAY_LEN(ary); - VALUE result = Qfalse; - - rb_check_arity(argc, 0, 1); - if (!len) return Qfalse; - if (argc) { - if (rb_block_given_p()) { - rb_warn("given block not used"); - } - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) { - if (result) return Qfalse; - result = Qtrue; - } - } - } - else if (!rb_block_given_p()) { - for (i = 0; i < len; ++i) { - if (RTEST(RARRAY_AREF(ary, i))) { - if (result) return Qfalse; - result = Qtrue; - } - } - } - else { - for (i = 0; i < RARRAY_LEN(ary); ++i) { - if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { - if (result) return Qfalse; - result = Qtrue; - } - } - } - return result; -} - -/* * call-seq: * ary.dig(idx, ...) -> object * @@ -6497,7 +5812,7 @@ rb_ary_one_p(int argc, VALUE *argv, VALUE ary) * [42, {foo: :bar}].dig(1, :foo) #=> :bar */ -static VALUE +VALUE rb_ary_dig(int argc, VALUE *argv, VALUE self) { rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); @@ -6576,7 +5891,8 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary) long i, n; int block_given; - v = (rb_check_arity(argc, 0, 1) ? argv[0] : LONG2FIX(0)); + if (rb_scan_args(argc, argv, "01", &v) == 0) + v = LONG2FIX(0); block_given = rb_block_given_p(); @@ -6619,12 +5935,12 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary) * See http://link.springer.com/article/10.1007/s00607-005-0139-x */ double f, c; - double x, t; f = NUM2DBL(v); c = 0.0; goto has_float_value; for (; i < RARRAY_LEN(ary); i++) { + double x, t; e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); @@ -6679,12 +5995,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary) return v; } -static VALUE -rb_ary_deconstruct(VALUE ary) -{ - return ary; -} - /* * Arrays are ordered, integer-indexed collections of any object. * @@ -6718,12 +6028,12 @@ rb_ary_deconstruct(VALUE ary) * This method is safe to use with mutable objects such as hashes, strings or * other arrays: * - * Array.new(4) {Hash.new} #=> [{}, {}, {}, {}] + * Array.new(4) { Hash.new } #=> [{}, {}, {}, {}] * Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"] * * This is also a quick way to build up multi-dimensional arrays: * - * empty_table = Array.new(3) {Array.new(3)} + * empty_table = Array.new(3) { Array.new(3) } * #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]] * * An array can also be created by using the Array() method, provided by @@ -6870,7 +6180,7 @@ rb_ary_deconstruct(VALUE ary) * Note that this operation leaves the array unchanged. * * arr = [1, 2, 3, 4, 5] - * arr.each {|a| print a -= 10, " "} + * arr.each { |a| print a -= 10, " " } * # prints: -9 -8 -7 -6 -5 * #=> [1, 2, 3, 4, 5] * @@ -6879,15 +6189,15 @@ rb_ary_deconstruct(VALUE ary) * * words = %w[first second third fourth fifth sixth] * str = "" - * words.reverse_each {|word| str += "#{word} "} + * words.reverse_each { |word| str += "#{word} " } * p str #=> "sixth fifth fourth third second first " * * The #map method can be used to create a new array based on the original * array, but with the values modified by the supplied block: * - * arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10] + * arr.map { |a| 2*a } #=> [2, 4, 6, 8, 10] * arr #=> [1, 2, 3, 4, 5] - * arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25] + * arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25] * arr #=> [1, 4, 9, 16, 25] * * == Selecting Items from an Array @@ -6901,9 +6211,9 @@ rb_ary_deconstruct(VALUE ary) * === Non-destructive Selection * * arr = [1, 2, 3, 4, 5, 6] - * arr.select {|a| a > 3} #=> [4, 5, 6] - * arr.reject {|a| a < 3} #=> [3, 4, 5, 6] - * arr.drop_while {|a| a < 4} #=> [4, 5, 6] + * arr.select { |a| a > 3 } #=> [4, 5, 6] + * arr.reject { |a| a < 3 } #=> [3, 4, 5, 6] + * arr.drop_while { |a| a < 4 } #=> [4, 5, 6] * arr #=> [1, 2, 3, 4, 5, 6] * * === Destructive Selection @@ -6914,11 +6224,11 @@ rb_ary_deconstruct(VALUE ary) * Similar to #select vs. #reject, #delete_if and #keep_if have the exact * opposite result when supplied with the same block: * - * arr.delete_if {|a| a < 4} #=> [4, 5, 6] + * arr.delete_if { |a| a < 4 } #=> [4, 5, 6] * arr #=> [4, 5, 6] * * arr = [1, 2, 3, 4, 5, 6] - * arr.keep_if {|a| a < 4} #=> [1, 2, 3] + * arr.keep_if { |a| a < 4 } #=> [1, 2, 3] * arr #=> [1, 2, 3] * */ @@ -6943,6 +6253,7 @@ Init_Array(void) rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0); rb_define_method(rb_cArray, "to_h", rb_ary_to_h, 0); rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0); + rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0); rb_define_method(rb_cArray, "==", rb_ary_equal, 1); rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1); @@ -6955,9 +6266,6 @@ Init_Array(void) rb_define_method(rb_cArray, "first", rb_ary_first, -1); rb_define_method(rb_cArray, "last", rb_ary_last, -1); rb_define_method(rb_cArray, "concat", rb_ary_concat_multi, -1); - rb_define_method(rb_cArray, "union", rb_ary_union_multi, -1); - rb_define_method(rb_cArray, "difference", rb_ary_difference_multi, -1); - rb_define_method(rb_cArray, "intersection", rb_ary_intersection_multi, -1); rb_define_method(rb_cArray, "<<", rb_ary_push, 1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); rb_define_alias(rb_cArray, "append", "push"); @@ -6989,8 +6297,6 @@ Init_Array(void) rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "select", rb_ary_select, 0); rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0); - rb_define_method(rb_cArray, "filter", rb_ary_select, 0); - rb_define_method(rb_cArray, "filter!", rb_ary_select_bang, 0); rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); @@ -7021,7 +6327,6 @@ Init_Array(void) rb_define_method(rb_cArray, "max", rb_ary_max, -1); rb_define_method(rb_cArray, "min", rb_ary_min, -1); - rb_define_method(rb_cArray, "minmax", rb_ary_minmax, 0); rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); @@ -7047,13 +6352,8 @@ Init_Array(void) rb_define_method(rb_cArray, "bsearch", rb_ary_bsearch, 0); rb_define_method(rb_cArray, "bsearch_index", rb_ary_bsearch_index, 0); rb_define_method(rb_cArray, "any?", rb_ary_any_p, -1); - rb_define_method(rb_cArray, "all?", rb_ary_all_p, -1); - rb_define_method(rb_cArray, "none?", rb_ary_none_p, -1); - rb_define_method(rb_cArray, "one?", rb_ary_one_p, -1); rb_define_method(rb_cArray, "dig", rb_ary_dig, -1); rb_define_method(rb_cArray, "sum", rb_ary_sum, -1); - rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0); - id_random = rb_intern("random"); } |
