diff options
Diffstat (limited to 'array.c')
| -rw-r--r-- | array.c | 793 |
1 files changed, 529 insertions, 264 deletions
@@ -27,7 +27,9 @@ #include "probes.h" #include "ruby/encoding.h" #include "ruby/st.h" +#include "ruby/thread.h" #include "ruby/util.h" +#include "ruby/ractor.h" #include "vm_core.h" #include "builtin.h" @@ -42,12 +44,12 @@ VALUE rb_cArray_empty_frozen; /* Flags of RArray * + * 0: RARRAY_SHARED_FLAG (equal to ELTS_SHARED) + * The array is shared. The buffer this array points to is owned by + * another array (the shared root). * 1: RARRAY_EMBED_FLAG * The array is embedded (its contents follow the header, rather than * being on a separately allocated buffer). - * 2: RARRAY_SHARED_FLAG (equal to ELTS_SHARED) - * The array is shared. The buffer this array points to is owned by - * another array (the shared root). * 3-9: RARRAY_EMBED_LEN * The length of the array when RARRAY_EMBED_FLAG is set. * 12: RARRAY_SHARED_ROOT_FLAG @@ -106,10 +108,12 @@ should_be_T_ARRAY(VALUE ary) } while (0) #define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG) +#define ARY_SET_PTR_FORCE(ary, p) \ + (RARRAY(ary)->as.heap.ptr = (p)) #define ARY_SET_PTR(ary, p) do { \ RUBY_ASSERT(!ARY_EMBED_P(ary)); \ RUBY_ASSERT(!OBJ_FROZEN(ary)); \ - RARRAY(ary)->as.heap.ptr = (p); \ + ARY_SET_PTR_FORCE(ary, p); \ } while (0) #define ARY_SET_EMBED_LEN(ary, n) do { \ long tmp_n = (n); \ @@ -147,11 +151,13 @@ should_be_T_ARRAY(VALUE ary) #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? ary_embed_capa(ary) : \ ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary)) +#define ARY_SET_CAPA_FORCE(ary, n) \ + RARRAY(ary)->as.heap.aux.capa = (n); #define ARY_SET_CAPA(ary, n) do { \ RUBY_ASSERT(!ARY_EMBED_P(ary)); \ RUBY_ASSERT(!ARY_SHARED_P(ary)); \ RUBY_ASSERT(!OBJ_FROZEN(ary)); \ - RARRAY(ary)->as.heap.aux.capa = (n); \ + ARY_SET_CAPA_FORCE(ary, n); \ } while (0) #define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1) @@ -188,7 +194,9 @@ ary_embed_capa(VALUE ary) static size_t ary_embed_size(long capa) { - return offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa); + size_t size = offsetof(struct RArray, as.ary) + (sizeof(VALUE) * capa); + if (size < sizeof(struct RArray)) size = sizeof(struct RArray); + return size; } static bool @@ -263,12 +271,6 @@ ary_verify_(VALUE ary, const char *file, int line) return ary; } - -void -rb_ary_verify(VALUE ary) -{ - ary_verify(ary); -} #else #define ary_verify(ary) ((void)0) #endif @@ -527,6 +529,8 @@ rb_ary_set_shared(VALUE ary, VALUE shared_root) static inline void rb_ary_modify_check(VALUE ary) { + RUBY_ASSERT(ruby_thread_has_gvl_p()); + rb_check_frozen(ary); ary_verify(ary); } @@ -563,8 +567,8 @@ rb_ary_cancel_sharing(VALUE ary) VALUE *ptr = ary_heap_alloc_buffer(len); MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len); rb_ary_unshare(ary); - ARY_SET_CAPA(ary, len); - ARY_SET_PTR(ary, ptr); + ARY_SET_CAPA_FORCE(ary, len); + ARY_SET_PTR_FORCE(ary, ptr); } rb_gc_writebarrier_remember(ary); @@ -698,6 +702,11 @@ ary_alloc_heap(VALUE klass) NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0), sizeof(struct RArray), 0); + + ary->as.heap.len = 0; + ary->as.heap.aux.capa = 0; + ary->as.heap.ptr = NULL; + return (VALUE)ary; } @@ -711,6 +720,8 @@ empty_ary_alloc(VALUE klass) static VALUE ary_new(VALUE klass, long capa) { + RUBY_ASSERT(ruby_thread_has_gvl_p()); + VALUE ary; if (capa < 0) { @@ -809,6 +820,11 @@ ec_ary_alloc_heap(rb_execution_context_t *ec, VALUE klass) NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0), sizeof(struct RArray), ec); + + ary->as.heap.len = 0; + ary->as.heap.aux.capa = 0; + ary->as.heap.ptr = NULL; + return (VALUE)ary; } @@ -1440,10 +1456,12 @@ rb_ary_pop(VALUE ary) { ary_resize_capa(ary, n * 2); } - --n; - ARY_SET_LEN(ary, n); + + VALUE obj = RARRAY_AREF(ary, n - 1); + + ARY_SET_LEN(ary, n - 1); ary_verify(ary); - return RARRAY_AREF(ary, n); + return obj; } /* @@ -1771,14 +1789,10 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e); /* * call-seq: - * self[index] -> object or nil - * self[start, length] -> object or nil + * self[offset] -> object or nil + * self[offset, size] -> object or nil * self[range] -> object or nil * self[aseq] -> object or nil - * slice(index) -> object or nil - * slice(start, length) -> object or nil - * slice(range) -> object or nil - * slice(aseq) -> object or nil * * Returns elements from +self+; does not modify +self+. * @@ -1786,27 +1800,27 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e); * * a = [:foo, 'bar', 2] * - * # Single argument index: returns one element. + * # Single argument offset: returns one element. * a[0] # => :foo # Zero-based index. * a[-1] # => 2 # Negative index counts backwards from end. * - * # Arguments start and length: returns an array. + * # Arguments offset and size: returns an array. * a[1, 2] # => ["bar", 2] - * a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. + * a[-2, 2] # => ["bar", 2] # Negative offset counts backwards from end. * * # Single argument range: returns an array. * a[0..1] # => [:foo, "bar"] * a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. * a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end. * - * When a single integer argument +index+ is given, returns the element at offset +index+: + * When a single integer argument +offset+ is given, returns the element at offset +offset+: * * a = [:foo, 'bar', 2] * a[0] # => :foo * a[2] # => 2 * a # => [:foo, "bar", 2] * - * If +index+ is negative, counts backwards from the end of +self+: + * If +offset+ is negative, counts backwards from the end of +self+: * * a = [:foo, 'bar', 2] * a[-1] # => 2 @@ -1814,35 +1828,35 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e); * * If +index+ is out of range, returns +nil+. * - * When two Integer arguments +start+ and +length+ are given, - * returns a new +Array+ of size +length+ containing successive elements beginning at offset +start+: + * When two Integer arguments +offset+ and +size+ are given, + * returns a new array of size +size+ containing successive elements beginning at offset +offset+: * * a = [:foo, 'bar', 2] * a[0, 2] # => [:foo, "bar"] * a[1, 2] # => ["bar", 2] * - * If <tt>start + length</tt> is greater than <tt>self.length</tt>, - * returns all elements from offset +start+ to the end: + * If <tt>offset + size</tt> is greater than <tt>self.size</tt>, + * returns all elements from offset +offset+ to the end: * * a = [:foo, 'bar', 2] * a[0, 4] # => [:foo, "bar", 2] * a[1, 3] # => ["bar", 2] * a[2, 2] # => [2] * - * If <tt>start == self.size</tt> and <tt>length >= 0</tt>, - * returns a new empty +Array+. + * If <tt>offset == self.size</tt> and <tt>size >= 0</tt>, + * returns a new empty array. * - * If +length+ is negative, returns +nil+. + * If +size+ is negative, returns +nil+. * * When a single Range argument +range+ is given, - * treats <tt>range.min</tt> as +start+ above - * and <tt>range.size</tt> as +length+ above: + * treats <tt>range.min</tt> as +offset+ above + * and <tt>range.size</tt> as +size+ above: * * a = [:foo, 'bar', 2] * a[0..1] # => [:foo, "bar"] * a[1..2] # => ["bar", 2] * - * Special case: If <tt>range.start == a.size</tt>, returns a new empty +Array+. + * Special case: If <tt>range.start == a.size</tt>, returns a new empty array. * * If <tt>range.end</tt> is negative, calculates the end index from the end: * @@ -1866,7 +1880,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e); * a[4..-1] # => nil * * When a single Enumerator::ArithmeticSequence argument +aseq+ is given, - * returns an +Array+ of elements corresponding to the indexes produced by + * returns an array of elements corresponding to the indexes produced by * the sequence. * * a = ['--', 'data1', '--', 'data2', '--', 'data3'] @@ -2071,6 +2085,95 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary) } /* + * call-seq: + * find(if_none_proc = nil) {|element| ... } -> object or nil + * find(if_none_proc = nil) -> enumerator + * + * Returns the first element for which the block returns a truthy value. + * + * With a block given, calls the block with successive elements of the array; + * returns the first element for which the block returns a truthy value: + * + * [1, 3, 5].find {|element| element > 2} # => 3 + * + * If no such element is found, calls +if_none_proc+ and returns its return value. + * + * [1, 3, 5].find(proc {-1}) {|element| element > 12} # => -1 + * + * With no block given, returns an Enumerator. + * + */ + +static VALUE +rb_ary_find(int argc, VALUE *argv, VALUE ary) +{ + VALUE if_none; + long idx; + + RETURN_ENUMERATOR(ary, argc, argv); + if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil; + + for (idx = 0; idx < RARRAY_LEN(ary); idx++) { + VALUE elem = RARRAY_AREF(ary, idx); + if (RTEST(rb_yield(elem))) { + return elem; + } + } + + if (!NIL_P(if_none)) { + return rb_funcallv(if_none, idCall, 0, 0); + } + return Qnil; +} + +/* + * call-seq: + * rfind(if_none_proc = nil) {|element| ... } -> object or nil + * rfind(if_none_proc = nil) -> enumerator + * + * Returns the last element for which the block returns a truthy value. + * + * With a block given, calls the block with successive elements of the array in + * reverse order; returns the first element for which the block returns a truthy + * value: + * + * [1, 2, 3, 4, 5, 6].rfind {|element| element < 5} # => 4 + * + * If no such element is found, calls +if_none_proc+ and returns its return value. + * + * [1, 2, 3, 4].rfind(proc {0}) {|element| element < -2} # => 0 + * + * With no block given, returns an Enumerator. + * + */ + +static VALUE +rb_ary_rfind(int argc, VALUE *argv, VALUE ary) +{ + VALUE if_none; + long len, idx; + + RETURN_ENUMERATOR(ary, argc, argv); + if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil; + + idx = RARRAY_LEN(ary); + while (idx--) { + VALUE elem = RARRAY_AREF(ary, idx); + if (RTEST(rb_yield(elem))) { + return elem; + } + + len = RARRAY_LEN(ary); + idx = (idx >= len) ? len : idx; + } + + if (!NIL_P(if_none)) { + return rb_funcallv(if_none, idCall, 0, 0); + } + return Qnil; +} + +/* * call-seq: * find_index(object) -> integer or nil * find_index {|element| ... } -> integer or nil @@ -2304,7 +2407,7 @@ rb_ary_resize(VALUE ary, long len) rb_raise(rb_eIndexError, "index %ld too big", len); } if (len > olen) { - if (len >= ARY_CAPA(ary)) { + if (len > ARY_CAPA(ary)) { ary_double_capa(ary, len); } ary_mem_clear(ary, olen, len - olen); @@ -2408,7 +2511,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val) * a[-1] = 'two' # => "two" * a # => [:foo, "bar", "two"] * - * When Integer arguments +start+ and +length+ are given and +object+ is not an +Array+, + * When Integer arguments +start+ and +length+ are given and +object+ is not an array, * removes <tt>length - 1</tt> elements beginning at offset +start+, * and assigns +object+ at offset +start+: * @@ -2443,7 +2546,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val) * a[1, 5] = 'foo' # => "foo" * a # => [:foo, "foo"] * - * When Range argument +range+ is given and +object+ is not an +Array+, + * When Range argument +range+ is given and +object+ is not an array, * removes <tt>length - 1</tt> elements beginning at offset +start+, * and assigns +object+ at offset +start+: * @@ -2604,6 +2707,39 @@ ary_fetch_next(VALUE self, VALUE *index, VALUE *value) return Qtrue; } +/* + * call-seq: + * each {|element| ... } -> self + * each -> new_enumerator + * + * With a block given, iterates over the elements of +self+, + * passing each element to the block; + * returns +self+: + * + * a = [:foo, 'bar', 2] + * a.each {|element| puts "#{element.class} #{element}" } + * + * Output: + * + * Symbol foo + * String bar + * Integer 2 + * + * Allows the array to be modified during iteration: + * + * a = [:foo, 'bar', 2] + * a.each {|element| puts element; a.clear if element.to_s.start_with?('b') } + * + * Output: + * + * foo + * bar + * + * With no block given, returns a new Enumerator. + * + * Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating]. + */ + VALUE rb_ary_each(VALUE ary) { @@ -2726,7 +2862,7 @@ rb_ary_length(VALUE ary) /* * call-seq: - * array.empty? -> true or false + * empty? -> true or false * * Returns +true+ if the count of elements in +self+ is zero, * +false+ otherwise. @@ -2866,23 +3002,28 @@ rb_ary_join(VALUE ary, VALUE sep) StringValue(sep); len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1); } - for (i=0; i<RARRAY_LEN(ary); i++) { + long len_memo = RARRAY_LEN(ary); + for (i=0; i < len_memo; i++) { val = RARRAY_AREF(ary, i); - tmp = rb_check_string_type(val); - - if (NIL_P(tmp) || tmp != val) { - int first; - long n = RARRAY_LEN(ary); - if (i > n) i = n; - result = rb_str_buf_new(len + (n-i)*10); - rb_enc_associate(result, rb_usascii_encoding()); - i = ary_join_0(ary, sep, i, result); - first = i == 0; - ary_join_1(ary, ary, sep, i, result, &first); - return result; + if (RB_UNLIKELY(!RB_TYPE_P(val, T_STRING))) { + tmp = rb_check_string_type(val); + if (NIL_P(tmp) || tmp != val) { + int first; + long n = RARRAY_LEN(ary); + if (i > n) i = n; + result = rb_str_buf_new(len + (n-i)*10); + rb_enc_associate(result, rb_usascii_encoding()); + i = ary_join_0(ary, sep, i, result); + first = i == 0; + ary_join_1(ary, ary, sep, i, result, &first); + return result; + } + len += RSTRING_LEN(tmp); + len_memo = RARRAY_LEN(ary); + } + else { + len += RSTRING_LEN(val); } - - len += RSTRING_LEN(tmp); } result = rb_str_new(0, len); @@ -2895,7 +3036,7 @@ rb_ary_join(VALUE ary, VALUE sep) /* * call-seq: - * array.join(separator = $,) -> new_string + * join(separator = $,) -> new_string * * Returns the new string formed by joining the converted elements of +self+; * for each element +element+: @@ -2986,7 +3127,7 @@ rb_ary_to_s(VALUE ary) * call-seq: * to_a -> self or new_array * - * When +self+ is an instance of +Array+, returns +self+. + * When +self+ is an instance of \Array, returns +self+. * * Otherwise, returns a new array containing the elements of +self+: * @@ -3061,7 +3202,7 @@ rb_ary_to_h(VALUE ary) /* * call-seq: - * array.to_ary -> self + * to_ary -> self * * Returns +self+. */ @@ -3407,10 +3548,9 @@ rb_ary_sort_bang(VALUE ary) ARY_SET_CAPA(ary, ARY_HEAP_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); + OBJ_FREEZE(tmp); } /* tmp will be GC'ed. */ RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */ @@ -3447,6 +3587,9 @@ rb_ary_sort_bang(VALUE ary) * When the block returns zero, the order for +a+ and +b+ is indeterminate, * and may be unstable. * + * See an example in Numeric#nonzero? for the idiom to sort more + * complex structure. + * * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ @@ -3468,7 +3611,7 @@ static VALUE rb_ary_bsearch_index(VALUE ary); * Returns the element from +self+ found by a binary search, * or +nil+ if the search found no suitable element. * - * See {Binary Searching}[rdoc-ref:bsearch.rdoc]. + * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc]. * * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ @@ -3492,7 +3635,7 @@ rb_ary_bsearch(VALUE ary) * Returns the integer index of the element from +self+ found by a binary search, * or +nil+ if the search found no suitable element. * - * See {Binary Searching}[rdoc-ref:bsearch.rdoc]. + * See {Binary Searching}[rdoc-ref:language/bsearch.rdoc]. * * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ @@ -3580,8 +3723,10 @@ rb_ary_sort_by_bang(VALUE ary) RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); - sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0); - rb_ary_replace(ary, sorted); + if (RARRAY_LEN(ary) > 1) { + sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0); + rb_ary_replace(ary, sorted); + } return ary; } @@ -3623,9 +3768,9 @@ rb_ary_collect(VALUE ary) /* * call-seq: - * collect! {|element| ... } -> new_array + * collect! {|element| ... } -> self * collect! -> new_enumerator - * map! {|element| ... } -> new_array + * map! {|element| ... } -> self * map! -> new_enumerator * * With a block given, calls the block with each element of +self+ @@ -3710,45 +3855,108 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx) /* * call-seq: - * array.values_at(*indexes) -> new_array + * values_at(*specifiers) -> new_array * - * Returns a new +Array+ whose elements are the elements - * of +self+ at the given Integer or Range +indexes+. + * Returns elements from +self+ in a new array; does not modify +self+. * - * For each positive +index+, returns the element at offset +index+: + * The objects included in the returned array are the elements of +self+ + * selected by the given +specifiers+, + * each of which must be a numeric index or a Range. * - * a = [:foo, 'bar', 2] - * a.values_at(0, 2) # => [:foo, 2] - * a.values_at(0..1) # => [:foo, "bar"] + * In brief: * - * The given +indexes+ may be in any order, and may repeat: + * a = ['a', 'b', 'c', 'd'] * - * a = [:foo, 'bar', 2] - * a.values_at(2, 0, 1, 0, 2) # => [2, :foo, "bar", :foo, 2] - * a.values_at(1, 0..2) # => ["bar", :foo, "bar", 2] + * # Index specifiers. + * a.values_at(2, 0, 2, 0) # => ["c", "a", "c", "a"] # May repeat. + * a.values_at(-4, -3, -2, -1) # => ["a", "b", "c", "d"] # Counts backwards if negative. + * a.values_at(-50, 50) # => [nil, nil] # Outside of self. * - * Assigns +nil+ for an +index+ that is too large: + * # Range specifiers. + * a.values_at(1..3) # => ["b", "c", "d"] # From range.begin to range.end. + * a.values_at(1...3) # => ["b", "c"] # End excluded. + * a.values_at(3..1) # => [] # No such elements. * - * a = [:foo, 'bar', 2] - * a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil] + * a.values_at(-3..3) # => ["b", "c", "d"] # Negative range.begin counts backwards. + * a.values_at(-50..3) # Raises RangeError. * - * Returns a new empty +Array+ if no arguments given. + * a.values_at(1..-2) # => ["b", "c"] # Negative range.end counts backwards. + * a.values_at(1..-50) # => [] # No such elements. * - * For each negative +index+, counts backward from the end of the array: + * # Mixture of specifiers. + * a.values_at(2..3, 3, 0..1, 0) # => ["c", "d", "d", "a", "b", "a"] * - * a = [:foo, 'bar', 2] - * a.values_at(-1, -3) # => [2, :foo] + * With no +specifiers+ given, returns a new empty array: + * + * a = ['a', 'b', 'c', 'd'] + * a.values_at # => [] * - * Assigns +nil+ for an +index+ that is too small: + * For each numeric specifier +index+, includes an element: * - * a = [:foo, 'bar', 2] - * a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2] + * - For each non-negative numeric specifier +index+ that is in-range (less than <tt>self.size</tt>), + * includes the element at offset +index+: * - * The given +indexes+ may have a mixture of signs: + * a.values_at(0, 2) # => ["a", "c"] + * a.values_at(0.1, 2.9) # => ["a", "c"] * - * a = [:foo, 'bar', 2] - * a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2] + * - For each negative numeric +index+ that is in-range (greater than or equal to <tt>- self.size</tt>), + * counts backwards from the end of +self+: * + * a.values_at(-1, -4) # => ["d", "a"] + * + * The given indexes may be in any order, and may repeat: + * + * a.values_at(2, 0, 1, 0, 2) # => ["c", "a", "b", "a", "c"] + * + * For each +index+ that is out-of-range, includes +nil+: + * + * a.values_at(4, -5) # => [nil, nil] + * + * For each Range specifier +range+, includes elements + * according to <tt>range.begin</tt> and <tt>range.end</tt>: + * + * - If both <tt>range.begin</tt> and <tt>range.end</tt> + * are non-negative and in-range (less than <tt>self.size</tt>), + * includes elements from index <tt>range.begin</tt> + * through <tt>range.end - 1</tt> (if <tt>range.exclude_end?</tt>), + * or through <tt>range.end</tt> (otherwise): + * + * a.values_at(1..2) # => ["b", "c"] + * a.values_at(1...2) # => ["b"] + * + * - If <tt>range.begin</tt> is negative and in-range (greater than or equal to <tt>- self.size</tt>), + * counts backwards from the end of +self+: + * + * a.values_at(-2..3) # => ["c", "d"] + * + * - If <tt>range.begin</tt> is negative and out-of-range, raises an exception: + * + * a.values_at(-5..3) # Raises RangeError. + * + * - If <tt>range.end</tt> is positive and out-of-range, + * extends the returned array with +nil+ elements: + * + * a.values_at(1..5) # => ["b", "c", "d", nil, nil] + * + * - If <tt>range.end</tt> is negative and in-range, + * counts backwards from the end of +self+: + * + * a.values_at(1..-2) # => ["b", "c"] + * + * - If <tt>range.end</tt> is negative and out-of-range, + * returns an empty array: + * + * a.values_at(1..-5) # => [] + * + * The given ranges may be in any order and may repeat: + * + * a.values_at(2..3, 0..1, 2..3) # => ["c", "d", "a", "b", "c", "d"] + * + * The given specifiers may be any mixture of indexes and ranges: + * + * a.values_at(3, 1..2, 0, 2..3) # => ["d", "b", "c", "a", "c", "d"] + * + * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ static VALUE @@ -4373,65 +4581,95 @@ take_items(VALUE obj, long n) /* * call-seq: - * array.zip(*other_arrays) -> new_array - * array.zip(*other_arrays) {|other_array| ... } -> nil + * zip(*other_arrays) -> new_array + * zip(*other_arrays) {|sub_array| ... } -> nil + * + * With no block given, combines +self+ with the collection of +other_arrays+; + * returns a new array of sub-arrays: + * + * [0, 1].zip(['zero', 'one'], [:zero, :one]) + * # => [[0, "zero", :zero], [1, "one", :one]] * - * When no block given, returns a new +Array+ +new_array+ of size <tt>self.size</tt> - * whose elements are Arrays. + * Returned: * - * Each nested array <tt>new_array[n]</tt> is of size <tt>other_arrays.size+1</tt>, - * and contains: + * - The outer array is of size <tt>self.size</tt>. + * - Each sub-array is of size <tt>other_arrays.size + 1</tt>. + * - The _nth_ sub-array contains (in order): * - * - The _nth_ element of +self+. - * - The _nth_ element of each of the +other_arrays+. + * - The _nth_ element of +self+. + * - The _nth_ element of each of the other arrays, as available. * - * If all +other_arrays+ and +self+ are the same size: + * Example: + * + * a = [0, 1] + * zipped = a.zip(['zero', 'one'], [:zero, :one]) + * # => [[0, "zero", :zero], [1, "one", :one]] + * zipped.size # => 2 # Same size as a. + * zipped.first.size # => 3 # Size of other arrays plus 1. + * + * When the other arrays are all the same size as +self+, + * the returned sub-arrays are a rearrangement containing exactly elements of all the arrays + * (including +self+), with no omissions or additions: * * a = [:a0, :a1, :a2, :a3] * b = [:b0, :b1, :b2, :b3] * c = [:c0, :c1, :c2, :c3] * d = a.zip(b, c) - * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]] + * pp d + * # => + * [[:a0, :b0, :c0], + * [:a1, :b1, :c1], + * [:a2, :b2, :c2], + * [:a3, :b3, :c3]] * - * If any array in +other_arrays+ is smaller than +self+, - * fills to <tt>self.size</tt> with +nil+: + * When one of the other arrays is smaller than +self+, + * pads the corresponding sub-array with +nil+ elements: * * a = [:a0, :a1, :a2, :a3] * b = [:b0, :b1, :b2] * c = [:c0, :c1] * d = a.zip(b, c) - * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]] + * pp d + * # => + * [[:a0, :b0, :c0], + * [:a1, :b1, :c1], + * [:a2, :b2, nil], + * [:a3, nil, nil]] * - * If any array in +other_arrays+ is larger than +self+, - * its trailing elements are ignored: + * When one of the other arrays is larger than +self+, + * _ignores_ its trailing elements: * * a = [:a0, :a1, :a2, :a3] * b = [:b0, :b1, :b2, :b3, :b4] * c = [:c0, :c1, :c2, :c3, :c4, :c5] * d = a.zip(b, c) - * d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]] - * - * If an argument is not an array, it extracts the values by calling #each: + * pp d + * # => + * [[:a0, :b0, :c0], + * [:a1, :b1, :c1], + * [:a2, :b2, :c2], + * [:a3, :b3, :c3]] * - * a = [:a0, :a1, :a2, :a2] - * b = 1..4 - * c = a.zip(b) - * c # => [[:a0, 1], [:a1, 2], [:a2, 3], [:a2, 4]] - * - * When a block is given, calls the block with each of the sub-arrays (formed as above); returns +nil+: + * With a block given, calls the block with each of the other arrays; + * returns +nil+: * + * d = [] * a = [:a0, :a1, :a2, :a3] * b = [:b0, :b1, :b2, :b3] * c = [:c0, :c1, :c2, :c3] - * a.zip(b, c) {|sub_array| p sub_array} # => nil - * - * Output: - * - * [:a0, :b0, :c0] - * [:a1, :b1, :c1] - * [:a2, :b2, :c2] - * [:a3, :b3, :c3] + * a.zip(b, c) {|sub_array| d.push(sub_array.reverse) } # => nil + * pp d + * # => + * [[:c0, :b0, :a0], + * [:c1, :b1, :a1], + * [:c2, :b2, :a2], + * [:c3, :b3, :a3]] + * + * For an *object* in *other_arrays* that is not actually an array, + * forms the "other array" as <tt>object.to_ary</tt>, if defined, + * or as <tt>object.each.to_a</tt> otherwise. * + * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. */ static VALUE @@ -4588,6 +4826,8 @@ rb_ary_replace(VALUE copy, VALUE orig) ARY_SET_PTR(copy, ARY_HEAP_PTR(orig)); ARY_SET_LEN(copy, ARY_HEAP_LEN(orig)); rb_ary_set_shared(copy, shared_root); + + RUBY_ASSERT(RB_OBJ_SHAREABLE_P(copy) ? RB_OBJ_SHAREABLE_P(shared_root) : 1); } ary_verify(copy); return copy; @@ -4626,10 +4866,10 @@ rb_ary_clear(VALUE ary) /* * call-seq: - * fill(object, start = nil, count = nil) -> new_array - * fill(object, range) -> new_array - * fill(start = nil, count = nil) {|element| ... } -> new_array - * fill(range) {|element| ... } -> new_array + * fill(object, start = nil, count = nil) -> self + * fill(object, range) -> self + * fill(start = nil, count = nil) {|element| ... } -> self + * fill(range) {|element| ... } -> self * * Replaces selected elements in +self+; * may add elements to +self+; @@ -4964,7 +5204,7 @@ rb_ary_concat(VALUE x, VALUE y) * When string argument +string_separator+ is given, * equivalent to <tt>self.join(string_separator)</tt>: * - * [0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {:foo=>0}" + * [0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {foo: 0}" * */ @@ -5191,8 +5431,8 @@ rb_ary_eql(VALUE ary1, VALUE ary2) return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } -VALUE -rb_ary_hash_values(long len, const VALUE *elements) +static VALUE +ary_hash_values(long len, const VALUE *elements, const VALUE ary) { long i; st_index_t h; @@ -5203,11 +5443,21 @@ rb_ary_hash_values(long len, const VALUE *elements) for (i=0; i<len; i++) { n = rb_hash(elements[i]); h = rb_hash_uint(h, NUM2LONG(n)); + if (ary) { + len = RARRAY_LEN(ary); + elements = RARRAY_CONST_PTR(ary); + } } h = rb_hash_end(h); return ST2FIX(h); } +VALUE +rb_ary_hash_values(long len, const VALUE *elements) +{ + return ary_hash_values(len, elements, 0); +} + /* * call-seq: * hash -> integer @@ -5226,7 +5476,8 @@ rb_ary_hash_values(long len, const VALUE *elements) static VALUE rb_ary_hash(VALUE ary) { - return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary)); + RBIMPL_ASSERT_OR_ASSUME(ary); + return ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), ary); } /* @@ -5483,7 +5734,7 @@ rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary) 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)) + if (rb_hash_stlike_lookup(argv[j], elt, NULL)) break; } else { @@ -5624,9 +5875,9 @@ rb_ary_union_hash(VALUE hash, VALUE ary2) /* * call-seq: - * array | other_array -> new_array + * self | other_array -> new_array * - * Returns the union of +array+ and +Array+ +other_array+; + * Returns the union of +self+ and +other_array+; * duplicates are removed; order is preserved; * items are compared using <tt>eql?</tt>: * @@ -5634,7 +5885,7 @@ rb_ary_union_hash(VALUE hash, VALUE ary2) * [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3] * [0, 1, 2] | [3, 2, 1, 0] # => [0, 1, 2, 3] * - * Related: Array#union. + * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining]. */ static VALUE @@ -5853,9 +6104,9 @@ ary_max_opt_string(VALUE ary, long i, VALUE vmax) /* * call-seq: * max -> element - * max(n) -> new_array + * max(count) -> new_array * max {|a, b| ... } -> element - * max(n) {|a, b| ... } -> new_array + * max(count) {|a, b| ... } -> new_array * * Returns one of the following: * @@ -5872,8 +6123,8 @@ ary_max_opt_string(VALUE ary, long i, VALUE vmax) * * [1, 0, 3, 2].max # => 3 * - * With non-negative numeric argument +n+ and no block, - * returns a new array with at most +n+ elements, + * With non-negative numeric argument +count+ and no block, + * returns a new array with at most +count+ elements, * in descending order, per method <tt>#<=></tt>: * * [1, 0, 3, 2].max(3) # => [3, 2, 1] @@ -5889,8 +6140,8 @@ ary_max_opt_string(VALUE ary, long i, VALUE vmax) * ['0', '', '000', '00'].max {|a, b| a.size <=> b.size } * # => "000" * - * With non-negative numeric argument +n+ and a block, - * returns a new array with at most +n+ elements, + * With non-negative numeric argument +count+ and a block, + * returns a new array with at most +count+ elements, * in descending order, per the block: * * ['0', '', '000', '00'].max(2) {|a, b| a.size <=> b.size } @@ -6030,9 +6281,9 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin) /* * call-seq: * min -> element - * min(n) -> new_array + * min(count) -> new_array * min {|a, b| ... } -> element - * min(n) {|a, b| ... } -> new_array + * min(count) {|a, b| ... } -> new_array * * Returns one of the following: * @@ -6049,8 +6300,8 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin) * * [1, 0, 3, 2].min # => 0 * - * With non-negative numeric argument +n+ and no block, - * returns a new array with at most +n+ elements, + * With non-negative numeric argument +count+ and no block, + * returns a new array with at most +count+ elements, * in ascending order, per method <tt>#<=></tt>: * * [1, 0, 3, 2].min(3) # => [0, 1, 2] @@ -6066,8 +6317,8 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin) * ['0', '', '000', '00'].min {|a, b| a.size <=> b.size } * # => "" * - * With non-negative numeric argument +n+ and a block, - * returns a new array with at most +n+ elements, + * With non-negative numeric argument +count+ and a block, + * returns a new array with at most +count+ elements, * in ascending order, per the block: * * ['0', '', '000', '00'].min(2) {|a, b| a.size <=> b.size } @@ -6581,7 +6832,7 @@ rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen) rb_ary_modify(ary); i = len = RARRAY_LEN(ary); RARRAY_PTR_USE(ary, ptr, { - while (i) { + while (i > 1) { long j = RAND_UPTO(i); VALUE tmp; if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) { @@ -6741,6 +6992,12 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE } static VALUE +ary_sized_alloc(rb_execution_context_t *ec, VALUE self) +{ + return rb_ary_new2(RARRAY_LEN(self)); +} + +static VALUE ary_sample0(rb_execution_context_t *ec, VALUE ary) { return ary_sample(ec, ary, rb_cRandom, Qfalse, Qfalse); @@ -6937,14 +7194,14 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * permutation(n = self.size) {|permutation| ... } -> self - * permutation(n = self.size) -> new_enumerator + * permutation(count = self.size) {|permutation| ... } -> self + * permutation(count = self.size) -> new_enumerator * * Iterates over permutations of the elements of +self+; * the order of permutations is indeterminate. * - * With a block and an in-range positive integer argument +n+ (<tt>0 < n <= self.size</tt>) given, - * calls the block with each +n+-tuple permutations of +self+; + * With a block and an in-range positive integer argument +count+ (<tt>0 < count <= self.size</tt>) given, + * calls the block with each permutation of +self+ of size +count+; * returns +self+: * * a = [0, 1, 2] @@ -6960,13 +7217,13 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj) * a.permutation(3) {|perm| perms.push(perm) } * perms # => [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] * - * When +n+ is zero, calls the block once with a new empty array: + * When +count+ is zero, calls the block once with a new empty array: * * perms = [] * a.permutation(0) {|perm| perms.push(perm) } * perms # => [[]] * - * When +n+ is out of range (negative or larger than <tt>self.size</tt>), + * When +count+ is out of range (negative or larger than <tt>self.size</tt>), * does not call the block: * * a.permutation(-1) {|permutation| fail 'Cannot happen' } @@ -7047,13 +7304,13 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * combination(n) {|element| ... } -> self - * combination(n) -> new_enumerator + * combination(count) {|element| ... } -> self + * combination(count) -> new_enumerator * * When a block and a positive * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects] - * argument +n+ (<tt>0 < n <= self.size</tt>) - * are given, calls the block with all +n+-tuple combinations of +self+; + * argument +count+ (<tt>0 < count <= self.size</tt>) + * are given, calls the block with each combination of +self+ of size +count+; * returns +self+: * * a = %w[a b c] # => ["a", "b", "c"] @@ -7067,7 +7324,7 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj) * * The order of the yielded combinations is not guaranteed. * - * When +n+ is zero, calls the block once with a new empty array: + * When +count+ is zero, calls the block once with a new empty array: * * a.combination(0) {|combination| p combination } * [].combination(0) {|combination| p combination } @@ -7077,7 +7334,7 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj) * [] * [] * - * When +n+ is negative or larger than +self.size+ and +self+ is non-empty, + * When +count+ is negative or larger than +self.size+ and +self+ is non-empty, * does not call the block: * * a.combination(-1) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"] @@ -7554,10 +7811,10 @@ rb_ary_take_while(VALUE ary) /* * call-seq: - * drop(n) -> new_array + * drop(count) -> new_array * - * Returns a new array containing all but the first +n+ element of +self+, - * where +n+ is a non-negative Integer; + * Returns a new array containing all but the first +count+ element of +self+, + * where +count+ is a non-negative integer; * does not modify +self+. * * Examples: @@ -7886,7 +8143,7 @@ rb_ary_one_p(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * array.dig(index, *identifiers) -> object + * dig(index, *identifiers) -> object * * Finds and returns the object in nested object * specified by +index+ and +identifiers+; @@ -8094,15 +8351,37 @@ rb_ary_deconstruct(VALUE ary) } /* - * An +Array+ is an ordered, integer-indexed collection of objects, called _elements_. - * Any object (even another array) may be an array element, - * and an array can contain objects of different types. + * An \Array object is an ordered, integer-indexed collection of objects, + * called _elements_; + * the object represents + * an {array data structure}[https://en.wikipedia.org/wiki/Array_(data_structure)]. + * + * An element may be any object (even another array); + * elements may be any mixture of objects of different types. + * + * Important data structures that use arrays include: + * + * - {Coordinate vector}[https://en.wikipedia.org/wiki/Coordinate_vector]. + * - {Matrix}[https://en.wikipedia.org/wiki/Matrix_(mathematics)]. + * - {Heap}[https://en.wikipedia.org/wiki/Heap_(data_structure)]. + * - {Hash table}[https://en.wikipedia.org/wiki/Hash_table]. + * - {Deque (double-ended queue)}[https://en.wikipedia.org/wiki/Double-ended_queue]. + * - {Queue}[https://en.wikipedia.org/wiki/Queue_(abstract_data_type)]. + * - {Stack}[https://en.wikipedia.org/wiki/Stack_(abstract_data_type)]. + * + * There are also array-like data structures: * - * == +Array+ Indexes + * - {Associative array}[https://en.wikipedia.org/wiki/Associative_array] (see Hash). + * - {Directory}[https://en.wikipedia.org/wiki/Directory_(computing)] (see Dir). + * - {Environment}[https://en.wikipedia.org/wiki/Environment_variable] (see ENV). + * - {Set}[https://en.wikipedia.org/wiki/Set_(abstract_data_type)] (see Set). + * - {String}[https://en.wikipedia.org/wiki/String_(computer_science)] (see String). * - * +Array+ indexing starts at 0, as in C or Java. + * == \Array Indexes * - * A positive index is an offset from the first element: + * \Array indexing starts at 0, as in C or Java. + * + * A non-negative index is an offset from the first element: * * - Index 0 indicates the first element. * - Index 1 indicates the second element. @@ -8114,6 +8393,9 @@ rb_ary_deconstruct(VALUE ary) * - Index -2 indicates the next-to-last element. * - ... * + * + * === In-Range and Out-of-Range Indexes + * * A non-negative index is <i>in range</i> if and only if it is smaller than * the size of the array. For a 3-element array: * @@ -8126,31 +8408,32 @@ rb_ary_deconstruct(VALUE ary) * - Indexes -1 through -3 are in range. * - Index -4 is out of range. * + * === Effective Index + * * Although the effective index into an array is always an integer, - * some methods (both within and outside of class +Array+) + * some methods (both within class \Array and elsewhere) * accept one or more non-integer arguments that are * {integer-convertible objects}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]. * - * * == Creating Arrays * - * You can create an +Array+ object explicitly with: + * You can create an \Array object explicitly with: * - * - An {array literal}[rdoc-ref:literals.rdoc@Array+Literals]: + * - An {array literal}[rdoc-ref:syntax/literals.rdoc@Array+Literals]: * * [1, 'one', :one, [2, 'two', :two]] * - * - A {%w or %W: string-array Literal}[rdoc-ref:literals.rdoc@25w+and+-25W-3A+String-Array+Literals]: + * - A {%w or %W string-array Literal}[rdoc-ref:syntax/literals.rdoc@25w+and+-25W-3A+String-Array+Literals]: * * %w[foo bar baz] # => ["foo", "bar", "baz"] * %w[1 % *] # => ["1", "%", "*"] * - * - A {%i pr %I: symbol-array Literal}[rdoc-ref:literals.rdoc@25i+and+-25I-3A+Symbol-Array+Literals]: + * - A {%i or %I symbol-array Literal}[rdoc-ref:syntax/literals.rdoc@25i+and+-25I-3A+Symbol-Array+Literals]: * * %i[foo bar baz] # => [:foo, :bar, :baz] * %i[1 % *] # => [:"1", :%, :*] * - * - \Method Kernel#Array: + * - Method Kernel#Array: * * Array(["a", "b"]) # => ["a", "b"] * Array(1..5) # => [1, 2, 3, 4, 5] @@ -8159,7 +8442,7 @@ rb_ary_deconstruct(VALUE ary) * Array(1) # => [1] * Array({:a => "a", :b => "b"}) # => [[:a, "a"], [:b, "b"]] * - * - \Method Array.new: + * - Method Array.new: * * Array.new # => [] * Array.new(3) # => [nil, nil, nil] @@ -8214,8 +8497,8 @@ rb_ary_deconstruct(VALUE ary) * * == Example Usage * - * In addition to the methods it mixes in through the Enumerable module, the - * +Array+ class has proprietary methods for accessing, searching and otherwise + * In addition to the methods it mixes in through the Enumerable module, + * class \Array has proprietary methods for accessing, searching and otherwise * manipulating arrays. * * Some of the more common ones are illustrated below. @@ -8263,9 +8546,9 @@ rb_ary_deconstruct(VALUE ary) * * arr.drop(3) #=> [4, 5, 6] * - * == Obtaining Information about an +Array+ + * == Obtaining Information about an \Array * - * Arrays keep track of their own length at all times. To query an array + * An array keeps track of its own length at all times. To query an array * about the number of elements it contains, use #length, #count or #size. * * browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] @@ -8280,7 +8563,7 @@ rb_ary_deconstruct(VALUE ary) * * browsers.include?('Konqueror') #=> false * - * == Adding Items to Arrays + * == Adding Items to an \Array * * Items can be added to the end of an array by using either #push or #<< * @@ -8301,7 +8584,7 @@ rb_ary_deconstruct(VALUE ary) * arr.insert(3, 'orange', 'pear', 'grapefruit') * #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6] * - * == Removing Items from an +Array+ + * == Removing Items from an \Array * * The method #pop removes the last element in an array and returns it: * @@ -8341,11 +8624,11 @@ rb_ary_deconstruct(VALUE ary) * arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] * arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123] * - * == Iterating over Arrays + * == Iterating over an \Array * - * Like all classes that include the Enumerable module, +Array+ has an each + * Like all classes that include the Enumerable module, class \Array has an each * method, which defines what elements should be iterated over and how. In - * case of Array's #each, all elements in the +Array+ instance are yielded to + * case of Array#each, all elements in +self+ are yielded to * the supplied block in sequence. * * Note that this operation leaves the array unchanged. @@ -8372,7 +8655,7 @@ rb_ary_deconstruct(VALUE ary) * arr #=> [1, 4, 9, 16, 25] * * - * == Selecting Items from an +Array+ + * == Selecting Items from an \Array * * Elements can be selected from an array according to criteria defined in a * block. The selection can happen in a destructive or a non-destructive @@ -8405,13 +8688,13 @@ rb_ary_deconstruct(VALUE ary) * * == What's Here * - * First, what's elsewhere. \Class +Array+: + * First, what's elsewhere. Class \Array: * * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here]. * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here], * which provides dozens of additional methods. * - * Here, class +Array+ provides methods that are useful for: + * Here, class \Array provides methods that are useful for: * * - {Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array] * - {Querying}[rdoc-ref:Array@Methods+for+Querying] @@ -8424,7 +8707,7 @@ rb_ary_deconstruct(VALUE ary) * - {Converting}[rdoc-ref:Array@Methods+for+Converting] * - {And more....}[rdoc-ref:Array@Other+Methods] * - * === Methods for Creating an +Array+ + * === Methods for Creating an \Array * * - ::[]: Returns a new array populated with given objects. * - ::new: Returns a new array. @@ -8434,136 +8717,115 @@ rb_ary_deconstruct(VALUE ary) * * === Methods for Querying * - * - #length (aliased as #size): Returns the count of elements. - * - #include?: Returns whether any element <tt>==</tt> a given object. - * - #empty?: Returns whether there are no elements. * - #all?: Returns whether all elements meet a given criterion. * - #any?: Returns whether any element meets a given criterion. - * - #none?: Returns whether no element <tt>==</tt> a given object. - * - #one?: Returns whether exactly one element <tt>==</tt> a given object. * - #count: Returns the count of elements that meet a given criterion. + * - #empty?: Returns whether there are no elements. * - #find_index (aliased as #index): Returns the index of the first element that meets a given criterion. - * - #rindex: Returns the index of the last element that meets a given criterion. * - #hash: Returns the integer hash code. + * - #include?: Returns whether any element <tt>==</tt> a given object. + * - #length (aliased as #size): Returns the count of elements. + * - #none?: Returns whether no element <tt>==</tt> a given object. + * - #one?: Returns whether exactly one element <tt>==</tt> a given object. + * - #rindex: Returns the index of the last element that meets a given criterion. * * === Methods for Comparing * - * - #<=>: Returns -1, 0, or 1, as +self+ is less than, equal to, or - * greater than a given object. - * - #==: Returns whether each element in +self+ is <tt>==</tt> to the corresponding element - * in a given object. - * - #eql?: Returns whether each element in +self+ is <tt>eql?</tt> to the corresponding - * element in a given object. + * - #<=>: Returns -1, 0, or 1, as +self+ is less than, equal to, or greater than a given object. + * - #==: Returns whether each element in +self+ is <tt>==</tt> to the corresponding element in a given object. + * - #eql?: Returns whether each element in +self+ is <tt>eql?</tt> to the corresponding element in a given object. * === Methods for Fetching * * These methods do not modify +self+. * * - #[] (aliased as #slice): Returns consecutive elements as determined by a given argument. + * - #assoc: Returns the first element that is an array whose first element <tt>==</tt> a given object. + * - #at: Returns the element at a given offset. + * - #bsearch: Returns an element selected via a binary search as determined by a given block. + * - #bsearch_index: Returns the index of an element selected via a binary search as determined by a given block. + * - #compact: Returns an array containing all non-+nil+ elements. + * - #dig: Returns the object in nested objects that is specified by a given index and additional arguments. + * - #drop: Returns trailing elements as determined by a given index. + * - #drop_while: Returns trailing elements as determined by a given block. * - #fetch: Returns the element at a given offset. * - #fetch_values: Returns elements at given offsets. * - #first: Returns one or more leading elements. * - #last: Returns one or more trailing elements. - * - #max: Returns one or more maximum-valued elements, - * as determined by <tt>#<=></tt> or a given block. - * - #min: Returns one or more minimum-valued elements, - * as determined by <tt>#<=></tt> or a given block. - * - #minmax: Returns the minimum-valued and maximum-valued elements, - * as determined by <tt>#<=></tt> or a given block. - * - #assoc: Returns the first element that is an array - * whose first element <tt>==</tt> a given object. - * - #rassoc: Returns the first element that is an array - * whose second element <tt>==</tt> a given object. - * - #at: Returns the element at a given offset. - * - #values_at: Returns the elements at given offsets. - * - #dig: Returns the object in nested objects - * that is specified by a given index and additional arguments. - * - #drop: Returns trailing elements as determined by a given index. - * - #take: Returns leading elements as determined by a given index. - * - #drop_while: Returns trailing elements as determined by a given block. - * - #take_while: Returns leading elements as determined by a given block. - * - #sort: Returns all elements in an order determined by <tt>#<=></tt> or a given block. + * - #max: Returns one or more maximum-valued elements, as determined by <tt>#<=></tt> or a given block. + * - #min: Returns one or more minimum-valued elements, as determined by <tt>#<=></tt> or a given block. + * - #minmax: Returns the minimum-valued and maximum-valued elements, as determined by <tt>#<=></tt> or a given block. + * - #rassoc: Returns the first element that is an array whose second element <tt>==</tt> a given object. + * - #reject: Returns an array containing elements not rejected by a given block. * - #reverse: Returns all elements in reverse order. - * - #compact: Returns an array containing all non-+nil+ elements. - * - #select (aliased as #filter): Returns an array containing elements selected by a given block. - * - #uniq: Returns an array containing non-duplicate elements. * - #rotate: Returns all elements with some rotated from one end to the other. - * - #bsearch: Returns an element selected via a binary search - * as determined by a given block. - * - #bsearch_index: Returns the index of an element selected via a binary search - * as determined by a given block. * - #sample: Returns one or more random elements. + * - #select (aliased as #filter): Returns an array containing elements selected by a given block. * - #shuffle: Returns elements in a random order. - * - #reject: Returns an array containing elements not rejected by a given block. + * - #sort: Returns all elements in an order determined by <tt>#<=></tt> or a given block. + * - #take: Returns leading elements as determined by a given index. + * - #take_while: Returns leading elements as determined by a given block. + * - #uniq: Returns an array containing non-duplicate elements. + * - #values_at: Returns the elements at given offsets. * * === Methods for Assigning * * These methods add, replace, or reorder elements in +self+. * - * - #[]=: Assigns specified elements with a given object. * - #<<: Appends an element. - * - #push (aliased as #append): Appends elements. - * - #unshift (aliased as #prepend): Prepends leading elements. - * - #insert: Inserts given objects at a given offset; does not replace elements. + * - #[]=: Assigns specified elements with a given object. * - #concat: Appends all elements from given arrays. * - #fill: Replaces specified elements with specified objects. * - #flatten!: Replaces each nested array in +self+ with the elements from that array. * - #initialize_copy (aliased as #replace): Replaces the content of +self+ with the content of a given array. + * - #insert: Inserts given objects at a given offset; does not replace elements. + * - #push (aliased as #append): Appends elements. * - #reverse!: Replaces +self+ with its elements reversed. * - #rotate!: Replaces +self+ with its elements rotated. * - #shuffle!: Replaces +self+ with its elements in random order. - * - #sort!: Replaces +self+ with its elements sorted, - * as determined by <tt>#<=></tt> or a given block. + * - #sort!: Replaces +self+ with its elements sorted, as determined by <tt>#<=></tt> or a given block. * - #sort_by!: Replaces +self+ with its elements sorted, as determined by a given block. + * - #unshift (aliased as #prepend): Prepends leading elements. * * === Methods for Deleting * * Each of these methods removes elements from +self+: * - * - #pop: Removes and returns the last element. - * - #shift: Removes and returns the first element. + * - #clear: Removes all elements. * - #compact!: Removes all +nil+ elements. * - #delete: Removes elements equal to a given object. * - #delete_at: Removes the element at a given offset. * - #delete_if: Removes elements specified by a given block. - * - #clear: Removes all elements. * - #keep_if: Removes elements not specified by a given block. + * - #pop: Removes and returns the last element. * - #reject!: Removes elements specified by a given block. * - #select! (aliased as #filter!): Removes elements not specified by a given block. + * - #shift: Removes and returns the first element. * - #slice!: Removes and returns a sequence of elements. * - #uniq!: Removes duplicates. * * === Methods for Combining * * - #&: Returns an array containing elements found both in +self+ and a given array. - * - #intersection: Returns an array containing elements found both in +self+ - * and in each given array. * - #+: Returns an array containing all elements of +self+ followed by all elements of a given array. * - #-: Returns an array containing all elements of +self+ that are not found in a given array. - * - #|: Returns an array containing all elements of +self+ and all elements of a given array, - * duplicates removed. - * - #union: Returns an array containing all elements of +self+ and all elements of given arrays, - * duplicates removed. - * - #difference: Returns an array containing all elements of +self+ that are not found - * in any of the given arrays.. + * - #|: Returns an array containing all element of +self+ and all elements of a given array, duplicates removed. + * - #difference: Returns an array containing all elements of +self+ that are not found in any of the given arrays.. + * - #intersection: Returns an array containing elements found both in +self+ and in each given array. * - #product: Returns or yields all combinations of elements from +self+ and given arrays. * - #reverse: Returns an array containing all elements of +self+ in reverse order. + * - #union: Returns an array containing all elements of +self+ and all elements of given arrays, duplicates removed. * * === Methods for Iterating * + * - #combination: Calls a given block with combinations of elements of +self+; a combination does not use the same element more than once. + * - #cycle: Calls a given block with each element, then does so again, for a specified number of times, or forever. * - #each: Passes each element to a given block. - * - #reverse_each: Passes each element, in reverse order, to a given block. * - #each_index: Passes each element index to a given block. - * - #cycle: Calls a given block with each element, then does so again, - * for a specified number of times, or forever. - * - #combination: Calls a given block with combinations of elements of +self+; - * a combination does not use the same element more than once. - * - #permutation: Calls a given block with permutations of elements of +self+; - * a permutation does not use the same element more than once. - * - #repeated_combination: Calls a given block with combinations of elements of +self+; - * a combination may use the same element more than once. - * - #repeated_permutation: Calls a given block with permutations of elements of +self+; - * a permutation may use the same element more than once. + * - #permutation: Calls a given block with permutations of elements of +self+; a permutation does not use the same element more than once. + * - #repeated_combination: Calls a given block with combinations of elements of +self+; a combination may use the same element more than once. + * - #repeated_permutation: Calls a given block with permutations of elements of +self+; a permutation may use the same element more than once. + * - #reverse_each: Passes each element, in reverse order, to a given block. * * === Methods for Converting * @@ -8571,13 +8833,12 @@ rb_ary_deconstruct(VALUE ary) * - #collect! (aliased as #map!): Replaces each element with a block return-value. * - #flatten: Returns an array that is a recursive flattening of +self+. * - #inspect (aliased as #to_s): Returns a new String containing the elements. - * - #join: Returns a newsString containing the elements joined by the field separator. + * - #join: Returns a new String containing the elements joined by the field separator. * - #to_a: Returns +self+ or a new array containing all elements. * - #to_ary: Returns +self+. * - #to_h: Returns a new hash formed from the elements. * - #transpose: Transposes +self+, which must be an array of arrays. - * - #zip: Returns a new array of arrays containing +self+ and given arrays; - * follow the link for details. + * - #zip: Returns a new array of arrays containing +self+ and given arrays. * * === Other Methods * @@ -8634,11 +8895,15 @@ Init_Array(void) rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1); rb_define_alias(rb_cArray, "prepend", "unshift"); rb_define_method(rb_cArray, "insert", rb_ary_insert, -1); + rb_define_method(rb_cArray, "each", rb_ary_each, 0); rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0); rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0); rb_define_method(rb_cArray, "length", rb_ary_length, 0); rb_define_method(rb_cArray, "size", rb_ary_length, 0); rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0); + rb_define_method(rb_cArray, "find", rb_ary_find, -1); + rb_define_method(rb_cArray, "detect", rb_ary_find, -1); + rb_define_method(rb_cArray, "rfind", rb_ary_rfind, -1); rb_define_method(rb_cArray, "find_index", rb_ary_index, -1); rb_define_method(rb_cArray, "index", rb_ary_index, -1); rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1); @@ -8720,7 +8985,7 @@ Init_Array(void) rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0); - rb_cArray_empty_frozen = rb_ary_freeze(rb_ary_new()); + rb_cArray_empty_frozen = RB_OBJ_SET_SHAREABLE(rb_ary_freeze(rb_ary_new())); rb_vm_register_global_object(rb_cArray_empty_frozen); } |
