diff options
Diffstat (limited to 'array.c')
| -rw-r--r-- | array.c | 1423 |
1 files changed, 800 insertions, 623 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; } /* @@ -1512,35 +1530,40 @@ rb_ary_shift(VALUE ary) /* * call-seq: - * array.shift -> object or nil - * array.shift(n) -> new_array - * - * Removes and returns leading elements. + * shift -> object or nil + * shift(count) -> new_array or nil * - * When no argument is given, removes and returns the first element: + * Removes and returns leading elements from +self+. * - * a = [:foo, 'bar', 2] - * a.shift # => :foo - * a # => ['bar', 2] + * With no argument, removes and returns one element, if available, + * or +nil+ otherwise: * - * Returns +nil+ if +self+ is empty. + * a = [0, 1, 2, 3] + * a.shift # => 0 + * a # => [1, 2, 3] + * [].shift # => nil * - * When positive Integer argument +n+ is given, removes the first +n+ elements; - * returns those elements in a new +Array+: + * With non-negative numeric argument +count+ given, + * removes and returns the first +count+ elements: * - * a = [:foo, 'bar', 2] - * a.shift(2) # => [:foo, 'bar'] - * a # => [2] + * a = [0, 1, 2, 3] + * a.shift(2) # => [0, 1] + * a # => [2, 3] + * a.shift(1.1) # => [2] + * a # => [3] + * a.shift(0) # => [] + * a # => [3] * - * If +n+ is as large as or larger than <tt>self.length</tt>, - * removes all elements; returns those elements in a new +Array+: + * If +count+ is large, + * removes and returns all elements: * - * a = [:foo, 'bar', 2] - * a.shift(3) # => [:foo, 'bar', 2] + * a = [0, 1, 2, 3] + * a.shift(50) # => [0, 1, 2, 3] + * a # => [] * - * If +n+ is zero, returns a new empty +Array+; +self+ is unmodified. + * If +self+ is empty, returns a new empty array. * - * Related: #push, #pop, #unshift. + * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting]. */ static VALUE @@ -1766,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+. * @@ -1781,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 @@ -1809,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: * @@ -1861,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'] @@ -2066,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 @@ -2299,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); @@ -2403,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+: * @@ -2438,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+: * @@ -2599,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) { @@ -2633,6 +2774,7 @@ rb_ary_each(VALUE ary) * * a = [:foo, 'bar', 2] * a.each_index {|index| puts index; a.clear if index > 0 } + * a # => [] * * Output: * @@ -2658,47 +2800,26 @@ rb_ary_each_index(VALUE ary) /* * call-seq: - * array.reverse_each {|element| ... } -> self - * array.reverse_each -> Enumerator - * - * Iterates backwards over array elements. + * reverse_each {|element| ... } -> self + * reverse_each -> Enumerator * - * When a block given, passes, in reverse order, each element to the block; + * When a block given, iterates backwards over the elements of +self+, + * passing, in reverse order, each element to the block; * returns +self+: * - * a = [:foo, 'bar', 2] - * a.reverse_each {|element| puts "#{element.class} #{element}" } - * - * Output: - * - * Integer 2 - * String bar - * Symbol foo + * a = [] + * [0, 1, 2].reverse_each {|element| a.push(element) } + * a # => [2, 1, 0] * * Allows the array to be modified during iteration: * - * a = [:foo, 'bar', 2] - * a.reverse_each {|element| puts element; a.clear if element.to_s.start_with?('b') } - * - * Output: - * - * 2 - * bar + * a = ['a', 'b', 'c'] + * a.reverse_each {|element| a.clear if element.start_with?('b') } + * a # => [] * - * When no block given, returns a new Enumerator: + * When no block given, returns a new Enumerator. * - * a = [:foo, 'bar', 2] - * e = a.reverse_each - * e # => #<Enumerator: [:foo, "bar", 2]:reverse_each> - * a1 = e.each {|element| puts "#{element.class} #{element}" } - * - * Output: - * - * Integer 2 - * String bar - * Symbol foo - * - * Related: #each, #each_index. + * Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating]. */ static VALUE @@ -2741,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. @@ -2881,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); @@ -2910,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+: @@ -2973,6 +3099,7 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) /* * call-seq: * inspect -> new_string + * to_s -> new_string * * Returns the new string formed by calling method <tt>#inspect</tt> * on each array element: @@ -2980,7 +3107,7 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) * a = [:foo, 'bar', 2] * a.inspect # => "[:foo, \"bar\", 2]" * - * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying]. + * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. */ static VALUE @@ -3000,21 +3127,17 @@ 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+. * - * a = [:foo, 'bar', 2] - * a.to_a # => [:foo, "bar", 2] - * - * Otherwise, returns a new +Array+ containing the elements of +self+: + * Otherwise, returns a new array containing the elements of +self+: * * class MyArray < Array; end - * a = MyArray.new(['foo', 'bar', 'two']) - * a.instance_of?(Array) # => false - * a.kind_of?(Array) # => true - * a1 = a.to_a - * a1 # => ["foo", "bar", "two"] - * a1.class # => Array # Not MyArray + * my_a = MyArray.new(['foo', 'bar', 'two']) + * a = my_a.to_a + * a # => ["foo", "bar", "two"] + * a.class # => Array # Not MyArray. * + * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. */ static VALUE @@ -3030,27 +3153,27 @@ rb_ary_to_a(VALUE ary) /* * call-seq: - * array.to_h -> new_hash - * array.to_h {|item| ... } -> new_hash + * to_h -> new_hash + * to_h {|element| ... } -> new_hash * - * Returns a new Hash formed from +self+. + * Returns a new hash formed from +self+. * - * When a block is given, calls the block with each array element; - * the block must return a 2-element +Array+ whose two elements - * form a key-value pair in the returned Hash: + * With no block given, each element of +self+ must be a 2-element sub-array; + * forms each sub-array into a key-value pair in the new hash: * - * a = ['foo', :bar, 1, [2, 3], {baz: 4}] - * h = a.to_h {|item| [item, item] } - * h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}} + * a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']] + * a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"} + * [].to_h # => {} * - * When no block is given, +self+ must be an +Array+ of 2-element sub-arrays, - * each sub-array is formed into a key-value pair in the new Hash: + * With a block given, the block must return a 2-element array; + * calls the block with each element of +self+; + * forms each returned array into a key-value pair in the returned hash: * - * [].to_h # => {} - * a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']] - * h = a.to_h - * h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"} + * a = ['foo', :bar, 1, [2, 3], {baz: 4}] + * a.to_h {|element| [element, element.class] } + * # => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash} * + * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. */ static VALUE @@ -3079,7 +3202,7 @@ rb_ary_to_h(VALUE ary) /* * call-seq: - * array.to_ary -> self + * to_ary -> self * * Returns +self+. */ @@ -3206,48 +3329,34 @@ rb_ary_rotate(VALUE ary, long cnt) /* * call-seq: - * array.rotate! -> self - * array.rotate!(count) -> self + * rotate!(count = 1) -> self * * Rotates +self+ in place by moving elements from one end to the other; returns +self+. * - * When no argument given, rotates the first element to the last position: - * - * a = [:foo, 'bar', 2, 'bar'] - * a.rotate! # => ["bar", 2, "bar", :foo] - * - * When given a non-negative Integer +count+, + * With non-negative numeric +count+, * rotates +count+ elements from the beginning to the end: * - * a = [:foo, 'bar', 2] - * a.rotate!(2) - * a # => [2, :foo, "bar"] + * [0, 1, 2, 3].rotate!(2) # => [2, 3, 0, 1] + [0, 1, 2, 3].rotate!(2.1) # => [2, 3, 0, 1] * * If +count+ is large, uses <tt>count % array.size</tt> as the count: * - * a = [:foo, 'bar', 2] - * a.rotate!(20) - * a # => [2, :foo, "bar"] + * [0, 1, 2, 3].rotate!(21) # => [1, 2, 3, 0] * - * If +count+ is zero, returns +self+ unmodified: + * If +count+ is zero, rotates no elements: * - * a = [:foo, 'bar', 2] - * a.rotate!(0) - * a # => [:foo, "bar", 2] + * [0, 1, 2, 3].rotate!(0) # => [0, 1, 2, 3] * - * When given a negative Integer +count+, rotates in the opposite direction, + * With a negative numeric +count+, rotates in the opposite direction, * from end to beginning: * - * a = [:foo, 'bar', 2] - * a.rotate!(-2) - * a # => ["bar", 2, :foo] + * [0, 1, 2, 3].rotate!(-1) # => [3, 0, 1, 2] * * If +count+ is small (far from zero), uses <tt>count % array.size</tt> as the count: * - * a = [:foo, 'bar', 2] - * a.rotate!(-5) - * a # => ["bar", 2, :foo] + * [0, 1, 2, 3].rotate!(-21) # => [3, 0, 1, 2] * + * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning]. */ static VALUE @@ -3260,51 +3369,35 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * array.rotate -> new_array - * array.rotate(count) -> new_array + * rotate(count = 1) -> new_array * - * Returns a new +Array+ formed from +self+ with elements + * Returns a new array formed from +self+ with elements * rotated from one end to the other. * - * When no argument given, returns a new +Array+ that is like +self+, - * except that the first element has been rotated to the last position: - * - * a = [:foo, 'bar', 2, 'bar'] - * a1 = a.rotate - * a1 # => ["bar", 2, "bar", :foo] - * - * When given a non-negative Integer +count+, - * returns a new +Array+ with +count+ elements rotated from the beginning to the end: + * With non-negative numeric +count+, + * rotates elements from the beginning to the end: * - * a = [:foo, 'bar', 2] - * a1 = a.rotate(2) - * a1 # => [2, :foo, "bar"] + * [0, 1, 2, 3].rotate(2) # => [2, 3, 0, 1] + * [0, 1, 2, 3].rotate(2.1) # => [2, 3, 0, 1] * * If +count+ is large, uses <tt>count % array.size</tt> as the count: * - * a = [:foo, 'bar', 2] - * a1 = a.rotate(20) - * a1 # => [2, :foo, "bar"] + * [0, 1, 2, 3].rotate(22) # => [2, 3, 0, 1] * - * If +count+ is zero, returns a copy of +self+, unmodified: + * With a +count+ of zero, rotates no elements: * - * a = [:foo, 'bar', 2] - * a1 = a.rotate(0) - * a1 # => [:foo, "bar", 2] + * [0, 1, 2, 3].rotate(0) # => [0, 1, 2, 3] * - * When given a negative Integer +count+, rotates in the opposite direction, - * from end to beginning: + * With negative numeric +count+, rotates in the opposite direction, + * from the end to the beginning: * - * a = [:foo, 'bar', 2] - * a1 = a.rotate(-2) - * a1 # => ["bar", 2, :foo] + * [0, 1, 2, 3].rotate(-1) # => [3, 0, 1, 2] * * If +count+ is small (far from zero), uses <tt>count % array.size</tt> as the count: * - * a = [:foo, 'bar', 2] - * a1 = a.rotate(-5) - * a1 # => ["bar", 2, :foo] + * [0, 1, 2, 3].rotate(-21) # => [3, 0, 1, 2] * + * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ static VALUE @@ -3397,43 +3490,12 @@ sort_2(const void *ap, const void *bp, void *dummy) /* * call-seq: - * array.sort! -> self - * array.sort! {|a, b| ... } -> self - * - * Returns +self+ with its elements sorted in place. - * - * With no block, compares elements using operator <tt>#<=></tt> - * (see Comparable): - * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a.sort! - * a # => ["a", "b", "c", "d", "e"] - * - * With a block, calls the block with each element pair; - * for each element pair +a+ and +b+, the block should return an integer: - * - * - Negative when +b+ is to follow +a+. - * - Zero when +a+ and +b+ are equivalent. - * - Positive when +a+ is to follow +b+. + * sort! -> self + * sort! {|a, b| ... } -> self * - * Example: - * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a.sort! {|a, b| a <=> b } - * a # => ["a", "b", "c", "d", "e"] - * a.sort! {|a, b| b <=> a } - * a # => ["e", "d", "c", "b", "a"] - * - * When the block returns zero, the order for +a+ and +b+ is indeterminate, - * and may be unstable: - * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a.sort! {|a, b| 0 } - * a # => ["d", "e", "c", "a", "b"] + * Like Array#sort, but returns +self+ with its elements sorted in place. * + * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning]. */ VALUE @@ -3486,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 */ @@ -3500,21 +3561,18 @@ rb_ary_sort_bang(VALUE ary) /* * call-seq: - * array.sort -> new_array - * array.sort {|a, b| ... } -> new_array + * sort -> new_array + * sort {|a, b| ... } -> new_array * - * Returns a new +Array+ whose elements are those from +self+, sorted. + * Returns a new array containing the elements of +self+, sorted. * - * With no block, compares elements using operator <tt>#<=></tt> - * (see Comparable): + * With no block given, compares elements using operator <tt>#<=></tt> + * (see Object#<=>): * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a1 = a.sort - * a1 # => ["a", "b", "c", "d", "e"] + * [0, 2, 3, 1].sort # => [0, 1, 2, 3] * - * With a block, calls the block with each element pair; - * for each element pair +a+ and +b+, the block should return an integer: + * With a block given, calls the block with each combination of pairs of elements from +self+; + * for each pair +a+ and +b+, the block should return a numeric: * * - Negative when +b+ is to follow +a+. * - Zero when +a+ and +b+ are equivalent. @@ -3522,22 +3580,17 @@ rb_ary_sort_bang(VALUE ary) * * Example: * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a1 = a.sort {|a, b| a <=> b } - * a1 # => ["a", "b", "c", "d", "e"] - * a2 = a.sort {|a, b| b <=> a } - * a2 # => ["e", "d", "c", "b", "a"] + * a = [3, 2, 0, 1] + * a.sort {|a, b| a <=> b } # => [0, 1, 2, 3] + * a.sort {|a, b| b <=> a } # => [3, 2, 1, 0] * * When the block returns zero, the order for +a+ and +b+ is indeterminate, - * and may be unstable: + * and may be unstable. * - * a = 'abcde'.split('').shuffle - * a # => ["e", "b", "d", "a", "c"] - * a1 = a.sort {|a, b| 0 } - * a1 # => ["c", "e", "b", "d", "a"] + * See an example in Numeric#nonzero? for the idiom to sort more + * complex structure. * - * Related: Enumerable#sort_by. + * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ VALUE @@ -3558,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]. */ @@ -3582,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]. */ @@ -3643,28 +3696,24 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy)) /* * call-seq: - * array.sort_by! {|element| ... } -> self - * array.sort_by! -> new_enumerator + * sort_by! {|element| ... } -> self + * sort_by! -> new_enumerator * - * Sorts the elements of +self+ in place, - * using an ordering determined by the block; returns self. + * With a block given, sorts the elements of +self+ in place; + * returns self. * * Calls the block with each successive element; - * sorts elements based on the values returned from the block. - * - * For duplicates returned by the block, the ordering is indeterminate, and may be unstable. - * - * This example sorts strings based on their sizes: + * sorts elements based on the values returned from the block: * * a = ['aaaa', 'bbb', 'cc', 'd'] * a.sort_by! {|element| element.size } * a # => ["d", "cc", "bbb", "aaaa"] * - * Returns a new Enumerator if no block given: + * For duplicate values returned by the block, the ordering is indeterminate, and may be unstable. * - * a = ['aaaa', 'bbb', 'cc', 'd'] - * a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!> + * With no block given, returns a new Enumerator. * + * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning]. */ static VALUE @@ -3674,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; } @@ -3717,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+ @@ -3804,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: * - * Assigns +nil+ for an +index+ that is too small: + * a = ['a', 'b', 'c', 'd'] + * a.values_at # => [] * - * a = [:foo, 'bar', 2] - * a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2] + * For each numeric specifier +index+, includes an element: * - * The given +indexes+ may have a mixture of signs: + * - For each non-negative numeric specifier +index+ that is in-range (less than <tt>self.size</tt>), + * includes the element at offset +index+: * - * a = [:foo, 'bar', 2] - * a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2] + * a.values_at(0, 2) # => ["a", "c"] + * a.values_at(0.1, 2.9) # => ["a", "c"] + * + * - 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 @@ -4190,71 +4304,94 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len) /* * call-seq: - * array.slice!(n) -> object or nil - * array.slice!(start, length) -> new_array or nil - * array.slice!(range) -> new_array or nil + * slice!(index) -> object or nil + * slice!(start, length) -> new_array or nil + * slice!(range) -> new_array or nil * * Removes and returns elements from +self+. * - * When the only argument is an Integer +n+, - * removes and returns the _nth_ element in +self+: + * With numeric argument +index+ given, + * removes and returns the element at offset +index+: * - * a = [:foo, 'bar', 2] - * a.slice!(1) # => "bar" - * a # => [:foo, 2] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(2) # => "c" + * a # => ["a", "b", "d"] + * a.slice!(2.1) # => "d" + * a # => ["a", "b"] * - * If +n+ is negative, counts backwards from the end of +self+: + * If +index+ is negative, counts backwards from the end of +self+: * - * a = [:foo, 'bar', 2] - * a.slice!(-1) # => 2 - * a # => [:foo, "bar"] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(-2) # => "c" + * a # => ["a", "b", "d"] * - * If +n+ is out of range, returns +nil+. + * If +index+ is out of range, returns +nil+. * - * When the only arguments are Integers +start+ and +length+, - * removes +length+ elements from +self+ beginning at offset +start+; - * returns the deleted objects in a new +Array+: + * With numeric arguments +start+ and +length+ given, + * removes +length+ elements from +self+ beginning at zero-based offset +start+; + * returns the removed objects in a new array: * - * a = [:foo, 'bar', 2] - * a.slice!(0, 2) # => [:foo, "bar"] - * a # => [2] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(1, 2) # => ["b", "c"] + * a # => ["a", "d"] + * a.slice!(0.1, 1.1) # => ["a"] + * a # => ["d"] + * + * If +start+ is negative, counts backwards from the end of +self+: + * + * a = ['a', 'b', 'c', 'd'] + * a.slice!(-2, 1) # => ["c"] + * a # => ["a", "b", "d"] + * + * If +start+ is out-of-range, returns +nil+: + * + * a = ['a', 'b', 'c', 'd'] + * a.slice!(5, 1) # => nil + * a.slice!(-5, 1) # => nil * * If <tt>start + length</tt> exceeds the array size, * removes and returns all elements from offset +start+ to the end: * - * a = [:foo, 'bar', 2] - * a.slice!(1, 50) # => ["bar", 2] - * a # => [:foo] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(2, 50) # => ["c", "d"] + * a # => ["a", "b"] * * If <tt>start == a.size</tt> and +length+ is non-negative, - * returns a new empty +Array+. + * returns a new empty array. * * If +length+ is negative, returns +nil+. * - * When the only argument is a Range object +range+, - * treats <tt>range.min</tt> as +start+ above and <tt>range.size</tt> as +length+ above: + * With Range argument +range+ given, + * treats <tt>range.min</tt> as +start+ (as above) + * and <tt>range.size</tt> as +length+ (as above): * - * a = [:foo, 'bar', 2] - * a.slice!(1..2) # => ["bar", 2] - * a # => [:foo] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(1..2) # => ["b", "c"] + * a # => ["a", "d"] * - * If <tt>range.start == a.size</tt>, returns a new empty +Array+. + * If <tt>range.start == a.size</tt>, returns a new empty array: * - * If <tt>range.start</tt> is larger than the array size, returns +nil+. + * a = ['a', 'b', 'c', 'd'] + * a.slice!(4..5) # => [] * - * If <tt>range.end</tt> is negative, counts backwards from the end of the array: + * If <tt>range.start</tt> is larger than the array size, returns +nil+: * - * a = [:foo, 'bar', 2] - * a.slice!(0..-2) # => [:foo, "bar"] - * a # => [2] + * a = ['a', 'b', 'c', 'd'] + a.slice!(5..6) # => nil * * If <tt>range.start</tt> is negative, - * calculates the start index backwards from the end of the array: + * calculates the start index by counting backwards from the end of +self+: * - * a = [:foo, 'bar', 2] - * a.slice!(-2..2) # => ["bar", 2] - * a # => [:foo] + * a = ['a', 'b', 'c', 'd'] + * a.slice!(-2..2) # => ["c"] + * + * If <tt>range.end</tt> is negative, + * calculates the end index by counting backwards from the end of +self+: * + * a = ['a', 'b', 'c', 'd'] + * a.slice!(0..-2) # => ["a", "b", "c"] + * + * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting]. */ static VALUE @@ -4444,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]] + * + * Returned: + * + * - 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): * - * When no block given, returns a new +Array+ +new_array+ of size <tt>self.size</tt> - * whose elements are Arrays. + * - The _nth_ element of +self+. + * - The _nth_ element of each of the other arrays, as available. * - * Each nested array <tt>new_array[n]</tt> is of size <tt>other_arrays.size+1</tt>, - * and contains: + * Example: * - * - The _nth_ element of +self+. - * - The _nth_ element of each of the +other_arrays+. + * 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. * - * If all +other_arrays+ and +self+ are the same size: + * 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 @@ -4565,14 +4732,17 @@ rb_ary_zip(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * array.transpose -> new_array + * transpose -> new_array * - * Transposes the rows and columns in an +Array+ of Arrays; - * the nested Arrays must all be the same size: + * Returns a new array that is +self+ + * as a {transposed matrix}[https://en.wikipedia.org/wiki/Transpose]: * * a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] * a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]] * + * The elements of +self+ must all be the same size. + * + * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting]. */ static VALUE @@ -4656,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; @@ -4694,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+; @@ -5032,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}" * */ @@ -5259,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; @@ -5271,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 @@ -5294,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); } /* @@ -5551,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 { @@ -5692,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>: * @@ -5702,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 @@ -5726,18 +5909,25 @@ rb_ary_or(VALUE ary1, VALUE ary2) /* * call-seq: - * array.union(*other_arrays) -> new_array + * union(*other_arrays) -> new_array * - * Returns a new +Array+ that is the union of +self+ and all given Arrays +other_arrays+; - * duplicates are removed; order is preserved; items are compared using <tt>eql?</tt>: + * Returns a new array that is the union of the elements of +self+ + * and all given arrays +other_arrays+; + * items are compared using <tt>eql?</tt>: * * [0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7] + * + * Removes duplicates (preserving the first found): + * * [0, 1, 1].union([2, 1], [3, 1]) # => [0, 1, 2, 3] - * [0, 1, 2, 3].union([3, 2], [1, 0]) # => [0, 1, 2, 3] * - * Returns a copy of +self+ if no arguments given. + * Preserves order (preserving the position of the first found): + * + * [3, 2, 1, 0].union([5, 3], [4, 2]) # => [3, 2, 1, 0, 5, 4] * - * Related: Array#|. + * With no arguments given, returns a copy of +self+. + * + * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining]. */ static VALUE @@ -5914,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: * @@ -5933,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] @@ -5950,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 } @@ -6091,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: * @@ -6110,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] @@ -6127,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 } @@ -6216,32 +6406,30 @@ push_value(st_data_t key, st_data_t val, st_data_t ary) /* * call-seq: - * array.uniq! -> self or nil - * array.uniq! {|element| ... } -> self or nil + * uniq! -> self or nil + * uniq! {|element| ... } -> self or nil * * Removes duplicate elements from +self+, the first occurrence always being retained; * returns +self+ if any elements removed, +nil+ otherwise. * * With no block given, identifies and removes elements using method <tt>eql?</tt> - * to compare. - * - * Returns +self+ if any elements removed: + * to compare elements: * * a = [0, 0, 1, 1, 2, 2] * a.uniq! # => [0, 1, 2] - * - * Returns +nil+ if no elements removed. + * a.uniq! # => nil * * With a block given, calls the block for each element; - * identifies (using method <tt>eql?</tt>) and removes - * elements for which the block returns duplicate values. - * - * Returns +self+ if any elements removed: + * identifies and omits "duplicate" elements using method <tt>eql?</tt> + * to compare <i>block return values</i>; + * that is, an element is a duplicate if its block return value + * is the same as that of a previous element: * * a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] - * a.uniq! {|element| element.size } # => ['a', 'aa', 'aaa'] + * a.uniq! {|element| element.size } # => ["a", "aa", "aaa"] + * a.uniq! {|element| element.size } # => nil * - * Returns +nil+ if no elements removed. + * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting]. */ static VALUE rb_ary_uniq_bang(VALUE ary) @@ -6275,25 +6463,28 @@ rb_ary_uniq_bang(VALUE ary) /* * call-seq: - * array.uniq -> new_array - * array.uniq {|element| ... } -> new_array + * uniq -> new_array + * uniq {|element| ... } -> new_array * - * Returns a new +Array+ containing those elements from +self+ that are not duplicates, + * Returns a new array containing those elements from +self+ that are not duplicates, * the first occurrence always being retained. * - * With no block given, identifies and omits duplicates using method <tt>eql?</tt> - * to compare: + * With no block given, identifies and omits duplicate elements using method <tt>eql?</tt> + * to compare elements: * * a = [0, 0, 1, 1, 2, 2] * a.uniq # => [0, 1, 2] * * With a block given, calls the block for each element; - * identifies (using method <tt>eql?</tt>) and omits duplicate values, - * that is, those elements for which the block returns the same value: + * identifies and omits "duplicate" elements using method <tt>eql?</tt> + * to compare <i>block return values</i>; + * that is, an element is a duplicate if its block return value + * is the same as that of a previous element: * * a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] * a.uniq {|element| element.size } # => ["a", "aa", "aaa"] * + * Related: {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ static VALUE @@ -6641,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)) { @@ -6801,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); @@ -6997,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] @@ -7020,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' } @@ -7107,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"] @@ -7127,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 } @@ -7137,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"] @@ -7233,68 +7430,41 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj) /* * call-seq: - * array.repeated_permutation(n) {|permutation| ... } -> self - * array.repeated_permutation(n) -> new_enumerator + * repeated_permutation(size) {|permutation| ... } -> self + * repeated_permutation(size) -> new_enumerator * - * Calls the block with each repeated permutation of length +n+ of the elements of +self+; - * each permutation is an +Array+; + * With a block given, calls the block with each repeated permutation of length +size+ + * of the elements of +self+; + * each permutation is an array; * returns +self+. The order of the permutations is indeterminate. * - * When a block and a positive Integer argument +n+ are given, calls the block with each - * +n+-tuple repeated permutation of the elements of +self+. - * The number of permutations is <tt>self.size**n</tt>. - * - * +n+ = 1: - * - * a = [0, 1, 2] - * a.repeated_permutation(1) {|permutation| p permutation } - * - * Output: - * - * [0] - * [1] - * [2] - * - * +n+ = 2: - * - * a.repeated_permutation(2) {|permutation| p permutation } + * If a positive integer argument +size+ is given, + * calls the block with each +size+-tuple repeated permutation of the elements of +self+. + * The number of permutations is <tt>self.size**size</tt>. * - * Output: + * Examples: * - * [0, 0] - * [0, 1] - * [0, 2] - * [1, 0] - * [1, 1] - * [1, 2] - * [2, 0] - * [2, 1] - * [2, 2] + * - +size+ is 1: * - * If +n+ is zero, calls the block once with an empty +Array+. + * p = [] + * [0, 1, 2].repeated_permutation(1) {|permutation| p.push(permutation) } + * p # => [[0], [1], [2]] * - * If +n+ is negative, does not call the block: + * - +size+ is 2: * - * a.repeated_permutation(-1) {|permutation| fail 'Cannot happen' } + * p = [] + * [0, 1, 2].repeated_permutation(2) {|permutation| p.push(permutation) } + * p # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]] * - * Returns a new Enumerator if no block given: + * If +size+ is zero, calls the block once with an empty array. * - * a = [0, 1, 2] - * a.repeated_permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)> + * If +size+ is negative, does not call the block: * - * Using Enumerators, it's convenient to show the permutations and counts - * for some values of +n+: + * [0, 1, 2].repeated_permutation(-1) {|permutation| fail 'Cannot happen' } * - * e = a.repeated_permutation(0) - * e.size # => 1 - * e.to_a # => [[]] - * e = a.repeated_permutation(1) - * e.size # => 3 - * e.to_a # => [[0], [1], [2]] - * e = a.repeated_permutation(2) - * e.size # => 9 - * e.to_a # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]] + * With no block given, returns a new Enumerator. * + * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining]. */ static VALUE rb_ary_repeated_permutation(VALUE ary, VALUE num) @@ -7580,20 +7750,20 @@ done: /* * call-seq: - * array.take(n) -> new_array + * take(count) -> new_array * - * Returns a new +Array+ containing the first +n+ element of +self+, - * where +n+ is a non-negative Integer; - * does not modify +self+. + * Returns a new array containing the first +count+ element of +self+ + * (as available); + * +count+ must be a non-negative numeric; + * does not modify +self+: * - * Examples: - * - * a = [0, 1, 2, 3, 4, 5] - * a.take(1) # => [0] - * a.take(2) # => [0, 1] - * a.take(50) # => [0, 1, 2, 3, 4, 5] - * a # => [0, 1, 2, 3, 4, 5] + * a = ['a', 'b', 'c', 'd'] + * a.take(2) # => ["a", "b"] + * a.take(2.1) # => ["a", "b"] + * a.take(50) # => ["a", "b", "c", "d"] + * a.take(0) # => [] * + * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ static VALUE @@ -7608,25 +7778,23 @@ rb_ary_take(VALUE obj, VALUE n) /* * call-seq: - * array.take_while {|element| ... } -> new_array - * array.take_while -> new_enumerator - * - * Returns a new +Array+ containing zero or more leading elements of +self+; - * does not modify +self+. + * take_while {|element| ... } -> new_array + * take_while -> new_enumerator * * With a block given, calls the block with each successive element of +self+; - * stops if the block returns +false+ or +nil+; - * returns a new +Array+ containing those elements for which the block returned a truthy value: + * stops iterating if the block returns +false+ or +nil+; + * returns a new array containing those elements for which the block returned a truthy value: * * a = [0, 1, 2, 3, 4, 5] * a.take_while {|element| element < 3 } # => [0, 1, 2] - * a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5] - * a # => [0, 1, 2, 3, 4, 5] + * a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5] + * a.take_while {|element| false } # => [] * - * With no block given, returns a new Enumerator: + * With no block given, returns a new Enumerator. * - * [0, 1].take_while # => #<Enumerator: [0, 1]:take_while> + * Does not modify +self+. * + * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching]. */ static VALUE @@ -7643,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: @@ -7975,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+; @@ -8019,40 +8187,41 @@ finish_exact_sum(long n, VALUE r, VALUE v, int z) /* * call-seq: - * array.sum(init = 0) -> object - * array.sum(init = 0) {|element| ... } -> object + * sum(init = 0) -> object + * sum(init = 0) {|element| ... } -> object * - * When no block is given, returns the object equivalent to: + * With no block given, returns the sum of +init+ and all elements of +self+; + * for array +array+ and value +init+, equivalent to: * * sum = init * array.each {|element| sum += element } * sum * - * For example, <tt>[e1, e2, e3].sum</tt> returns <tt>init + e1 + e2 + e3</tt>. + * For example, <tt>[e0, e1, e2].sum</tt> returns <tt>init + e0 + e1 + e2</tt>. * * Examples: * - * a = [0, 1, 2, 3] - * a.sum # => 6 - * a.sum(100) # => 106 + * [0, 1, 2, 3].sum # => 6 + * [0, 1, 2, 3].sum(100) # => 106 + * ['abc', 'def', 'ghi'].sum('jkl') # => "jklabcdefghi" + * [[:foo, :bar], ['foo', 'bar']].sum([2, 3]) + * # => [2, 3, :foo, :bar, "foo", "bar"] * - * The elements need not be numeric, but must be <tt>+</tt>-compatible - * with each other and with +init+: + * The +init+ value and elements need not be numeric, but must all be <tt>+</tt>-compatible: * - * a = ['abc', 'def', 'ghi'] - * a.sum('jkl') # => "jklabcdefghi" + * # Raises TypeError: Array can't be coerced into Integer. + * [[:foo, :bar], ['foo', 'bar']].sum(2) * - * When a block is given, it is called with each element - * and the block's return value (instead of the element itself) is used as the addend: + * With a block given, calls the block with each element of +self+; + * the block's return value (instead of the element itself) is used as the addend: * - * a = ['zero', 1, :two] - * s = a.sum('Coerced and concatenated: ') {|element| element.to_s } - * s # => "Coerced and concatenated: zero1two" + * ['zero', 1, :two].sum('Coerced and concatenated: ') {|element| element.to_s } + * # => "Coerced and concatenated: zero1two" * * Notes: * * - Array#join and Array#flatten may be faster than Array#sum - * for an +Array+ of Strings or an +Array+ of Arrays. + * for an array of strings or an array of arrays. * - Array#sum method may not respect method redefinition of "+" methods such as Integer#+. * */ @@ -8182,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: * - * == +Array+ Indexes + * - {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)]. * - * +Array+ indexing starts at 0, as in C or Java. + * There are also array-like data structures: * - * A positive index is an offset from the first element: + * - {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 Indexes + * + * \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. @@ -8202,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: * @@ -8214,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] @@ -8247,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] @@ -8302,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. @@ -8351,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'] @@ -8368,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 #<< * @@ -8389,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: * @@ -8429,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. @@ -8460,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 @@ -8493,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] @@ -8512,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. @@ -8522,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 * @@ -8659,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 * @@ -8722,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); @@ -8808,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); } |
