diff options
Diffstat (limited to 'array.c')
| -rw-r--r-- | array.c | 2223 |
1 files changed, 639 insertions, 1584 deletions
@@ -14,21 +14,15 @@ #include "ruby/ruby.h" #include "ruby/util.h" #include "ruby/st.h" -#include "ruby/encoding.h" -#include "internal.h" -#include "probes.h" -#include "id.h" #ifndef ARRAY_DEBUG # define NDEBUG #endif #include <assert.h> -#define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) - VALUE rb_cArray; -static ID id_cmp, id_div, id_power; +static ID id_cmp; #define ARY_DEFAULT_SIZE 16 #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE)) @@ -50,11 +44,11 @@ memfill(register VALUE *mem, register long size, register VALUE val) } # define ARY_SHARED_P(ary) \ - (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ - FL_TEST((ary),ELTS_SHARED)!=0) + (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \ + FL_TEST(ary,ELTS_SHARED)!=0) # define ARY_EMBED_P(ary) \ - (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ - FL_TEST((ary), RARRAY_EMBED_FLAG)!=0) + (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \ + FL_TEST(ary, RARRAY_EMBED_FLAG)!=0) #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr) #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len) @@ -64,17 +58,18 @@ memfill(register VALUE *mem, register long size, register VALUE val) (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT))) -#define ARY_OWNS_HEAP_P(a) (!FL_TEST((a), ELTS_SHARED|RARRAY_EMBED_FLAG)) +#define ARY_OWNS_HEAP_P(a) (!FL_TEST(a, ELTS_SHARED|RARRAY_EMBED_FLAG)) #define FL_SET_EMBED(a) do { \ assert(!ARY_SHARED_P(a)); \ - FL_SET((a), RARRAY_EMBED_FLAG); \ + assert(!OBJ_FROZEN(a)); \ + FL_SET(a, RARRAY_EMBED_FLAG); \ } while (0) -#define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK) +#define FL_UNSET_EMBED(ary) FL_UNSET(ary, RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK) #define FL_SET_SHARED(ary) do { \ assert(!ARY_EMBED_P(ary)); \ - FL_SET((ary), ELTS_SHARED); \ + FL_SET(ary, ELTS_SHARED); \ } while (0) -#define FL_UNSET_SHARED(ary) FL_UNSET((ary), ELTS_SHARED) +#define FL_UNSET_SHARED(ary) FL_UNSET(ary, ELTS_SHARED) #define ARY_SET_PTR(ary, p) do { \ assert(!ARY_EMBED_P(ary)); \ @@ -82,7 +77,7 @@ memfill(register VALUE *mem, register long size, register VALUE val) RARRAY(ary)->as.heap.ptr = (p); \ } while (0) #define ARY_SET_EMBED_LEN(ary, n) do { \ - long tmp_n = (n); \ + long tmp_n = n; \ assert(ARY_EMBED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \ @@ -90,29 +85,29 @@ memfill(register VALUE *mem, register long size, register VALUE val) } while (0) #define ARY_SET_HEAP_LEN(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ - RARRAY(ary)->as.heap.len = (n); \ + RARRAY(ary)->as.heap.len = n; \ } while (0) #define ARY_SET_LEN(ary, n) do { \ if (ARY_EMBED_P(ary)) { \ - ARY_SET_EMBED_LEN((ary), (n)); \ + ARY_SET_EMBED_LEN(ary, n); \ } \ else { \ - ARY_SET_HEAP_LEN((ary), (n)); \ + ARY_SET_HEAP_LEN(ary, n); \ } \ - assert(RARRAY_LEN(ary) == (n)); \ + assert(RARRAY_LEN(ary) == n); \ } while (0) #define ARY_INCREASE_PTR(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ - RARRAY(ary)->as.heap.ptr += (n); \ + RARRAY(ary)->as.heap.ptr += n; \ } while (0) #define ARY_INCREASE_LEN(ary, n) do { \ assert(!OBJ_FROZEN(ary)); \ if (ARY_EMBED_P(ary)) { \ - ARY_SET_EMBED_LEN((ary), RARRAY_LEN(ary)+(n)); \ + ARY_SET_EMBED_LEN(ary, RARRAY_LEN(ary)+n); \ } \ else { \ - RARRAY(ary)->as.heap.len += (n); \ + RARRAY(ary)->as.heap.len += n; \ } \ } while (0) @@ -133,7 +128,7 @@ memfill(register VALUE *mem, register long size, register VALUE val) RARRAY(ary)->as.heap.aux.shared = (value); \ } while (0) #define RARRAY_SHARED_ROOT_FLAG FL_USER5 -#define ARY_SHARED_ROOT_P(ary) (FL_TEST((ary), RARRAY_SHARED_ROOT_FLAG)) +#define ARY_SHARED_ROOT_P(ary) (FL_TEST(ary, RARRAY_SHARED_ROOT_FLAG)) #define ARY_SHARED_NUM(ary) \ (assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa) #define ARY_SET_SHARED_NUM(ary, value) do { \ @@ -142,7 +137,7 @@ memfill(register VALUE *mem, register long size, register VALUE val) } while (0) #define FL_SET_SHARED_ROOT(ary) do { \ assert(!ARY_EMBED_P(ary)); \ - FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \ + FL_SET(ary, RARRAY_SHARED_ROOT_FLAG); \ } while (0) static void @@ -245,35 +240,26 @@ rb_ary_set_shared(VALUE ary, VALUE shared) static inline void rb_ary_modify_check(VALUE ary) { - rb_check_frozen(ary); + if (OBJ_FROZEN(ary)) rb_error_frozen("array"); if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } -void +static void rb_ary_modify(VALUE ary) { rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { long len = RARRAY_LEN(ary); - VALUE shared = ARY_SHARED(ary); if (len <= RARRAY_EMBED_LEN_MAX) { VALUE *ptr = ARY_HEAP_PTR(ary); + VALUE shared = ARY_SHARED(ary); FL_UNSET_SHARED(ary); FL_SET_EMBED(ary); MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len); rb_ary_decrement_share(shared); ARY_SET_EMBED_LEN(ary, len); } - else if (ARY_SHARED_NUM(shared) == 1 && len > (RARRAY_LEN(shared)>>1)) { - long shift = RARRAY_PTR(ary) - RARRAY_PTR(shared); - FL_UNSET_SHARED(ary); - ARY_SET_PTR(ary, RARRAY_PTR(shared)); - ARY_SET_CAPA(ary, RARRAY_LEN(shared)); - MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+shift, VALUE, len); - FL_SET_EMBED(shared); - rb_ary_decrement_share(shared); - } else { VALUE *ptr = ALLOC_N(VALUE, len); MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len); @@ -284,48 +270,6 @@ rb_ary_modify(VALUE ary) } } -static void -ary_ensure_room_for_push(VALUE ary, long add_len) -{ - long new_len = RARRAY_LEN(ary) + add_len; - long capa; - - if (ARY_SHARED_P(ary)) { - if (new_len > RARRAY_EMBED_LEN_MAX) { - VALUE shared = ARY_SHARED(ary); - if (ARY_SHARED_NUM(shared) == 1) { - if (RARRAY_PTR(ary) - RARRAY_PTR(shared) + new_len <= RARRAY_LEN(shared)) { - rb_ary_modify_check(ary); - } - else { - /* if array is shared, than it is likely it participate in push/shift pattern */ - rb_ary_modify(ary); - capa = ARY_CAPA(ary); - if (new_len > capa - (capa >> 6)) { - ary_double_capa(ary, new_len); - } - } - return; - } - } - } - rb_ary_modify(ary); - capa = ARY_CAPA(ary); - if (new_len > capa) { - ary_double_capa(ary, new_len); - } -} - -/* - * call-seq: - * ary.freeze -> ary - * - * Calls Object#freeze on +ary+ to prevent any further - * modification. A RuntimeError will be raised if a modification - * attempt is made. - * - */ - VALUE rb_ary_freeze(VALUE ary) { @@ -336,8 +280,8 @@ rb_ary_freeze(VALUE ary) * call-seq: * ary.frozen? -> true or false * - * Return +true+ if this array is frozen (or temporarily frozen - * while being sorted). See also Object#frozen? + * Return <code>true</code> if this array is frozen (or temporarily frozen + * while being sorted). */ static VALUE @@ -347,29 +291,11 @@ rb_ary_frozen_p(VALUE ary) return Qfalse; } -/* This can be used to take a snapshot of an array (with - e.g. rb_ary_replace) and check later whether the array has been - modified from the snapshot. The snapshot is cheap, though if - something does modify the array it will pay the cost of copying - it. If Array#pop or Array#shift has been called, the array will - be still shared with the snapshot, but the array length will - differ. */ -VALUE -rb_ary_shared_with_p(VALUE ary1, VALUE ary2) -{ - if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) && - !ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) && - RARRAY(ary1)->as.heap.aux.shared == RARRAY(ary2)->as.heap.aux.shared && - RARRAY(ary1)->as.heap.len == RARRAY(ary2)->as.heap.len) { - return Qtrue; - } - return Qfalse; -} - static VALUE ary_alloc(VALUE klass) { - NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY); + NEWOBJ(ary, struct RArray); + OBJSETUP(ary, klass, T_ARRAY); FL_SET_EMBED((VALUE)ary); ARY_SET_EMBED_LEN((VALUE)ary, 0); @@ -377,16 +303,6 @@ ary_alloc(VALUE klass) } static VALUE -empty_ary_alloc(VALUE klass) -{ - if (RUBY_DTRACE_ARRAY_CREATE_ENABLED()) { - RUBY_DTRACE_ARRAY_CREATE(0, rb_sourcefile(), rb_sourceline()); - } - - return ary_alloc(klass); -} - -static VALUE ary_new(VALUE klass, long capa) { VALUE ary; @@ -397,11 +313,6 @@ ary_new(VALUE klass, long capa) if (capa > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } - - if (RUBY_DTRACE_ARRAY_CREATE_ENABLED()) { - RUBY_DTRACE_ARRAY_CREATE(capa, rb_sourcefile(), rb_sourceline()); - } - ary = ary_alloc(klass); if (capa > RARRAY_EMBED_LEN_MAX) { FL_UNSET_EMBED(ary); @@ -475,7 +386,7 @@ rb_ary_free(VALUE ary) } } -RUBY_FUNC_EXPORTED size_t +size_t rb_ary_memsize(VALUE ary) { if (ARY_OWNS_HEAP_P(ary)) { @@ -511,12 +422,12 @@ ary_make_shared(VALUE ary) return ary; } else { - NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY); + NEWOBJ(shared, struct RArray); + OBJSETUP(shared, 0, T_ARRAY); FL_UNSET_EMBED(shared); - ARY_SET_LEN((VALUE)shared, ARY_CAPA(ary)); + ARY_SET_LEN((VALUE)shared, RARRAY_LEN(ary)); ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary)); - rb_mem_clear(RARRAY_PTR(shared) + RARRAY_LEN(ary), ARY_CAPA(ary) - RARRAY_LEN(ary)); FL_SET_SHARED_ROOT(shared); ARY_SET_SHARED_NUM((VALUE)shared, 1); FL_SET_SHARED(ary); @@ -563,9 +474,10 @@ rb_check_array_type(VALUE ary) * call-seq: * Array.try_convert(obj) -> array or nil * - * Tries to convert +obj+ into an array, using +to_ary+ method. Returns the - * converted array or +nil+ if +obj+ cannot be converted for any reason. - * This method can be used to check if an argument is an array. + * Try to convert <i>obj</i> into an array, using +to_ary+ method. + * Returns converted array or +nil+ if <i>obj</i> cannot be converted + * for any reason. This method can be used to check if an argument is an + * array. * * Array.try_convert([1]) #=> [1] * Array.try_convert("1") #=> nil @@ -590,54 +502,36 @@ rb_ary_s_try_convert(VALUE dummy, VALUE ary) * Array.new(array) * Array.new(size) {|index| block } * - * Returns a new array. - * - * In the first form, if no arguments are sent, the new array will be empty. - * When a +size+ and an optional +obj+ are sent, an array is created with - * +size+ copies of +obj+. Take notice that all elements will reference the - * same object +obj+. - * - * The second form creates a copy of the array passed as a parameter (the - * array is generated by calling to_ary on the parameter). - * - * first_array = ["Matz", "Guido"] - * - * second_array = Array.new(first_array) #=> ["Matz", "Guido"] - * - * first_array.equal? second_array #=> false - * - * In the last form, an array of the given size is created. Each element in - * this array is created by passing the element's index to the given block - * and storing the return value. - * - * Array.new(3){ |index| index ** 2 } - * # => [0, 1, 4] - * - * == Common gotchas - * - * When sending the second parameter, the same object will be used as the - * value for all the array elements: - * + * Returns a new array. In the first form, the new array is + * empty. In the second it is created with _size_ copies of _obj_ + * (that is, _size_ references to the same + * _obj_). The third form creates a copy of the array + * passed as a parameter (the array is generated by calling + * to_ary on the parameter). In the last form, an array + * of the given size is created. Each element in this array is + * calculated by passing the element's index to the given block and + * storing the return value. + * + * Array.new + * Array.new(2) + * Array.new(5, "A") + * + * # only one copy of the object is created * a = Array.new(2, Hash.new) - * # => [{}, {}] - * * a[0]['cat'] = 'feline' - * a # => [{"cat"=>"feline"}, {"cat"=>"feline"}] - * + * a * a[1]['cat'] = 'Felix' - * a # => [{"cat"=>"Felix"}, {"cat"=>"Felix"}] - * - * Since all the Array elements store the same hash, changes to one of them - * will affect them all. - * - * If multiple copies are what you want, you should use the block - * version which uses the result of that block each time an element - * of the array needs to be initialized: + * a * + * # here multiple copies are created * a = Array.new(2) { Hash.new } * a[0]['cat'] = 'feline' - * a # => [{"cat"=>"feline"}, {}] + * a * + * squares = Array.new(5) {|i| i*i} + * squares + * + * copy = Array.new(squares) */ static VALUE @@ -695,13 +589,14 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary) return ary; } + /* - * Returns a new array populated with the given objects. - * - * Array.[]( 1, 'a', /^A/ ) # => [1, "a", /^A/] - * Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/] - * [ 1, 'a', /^A/ ] # => [1, "a", /^A/] - */ +* Returns a new array populated with the given objects. +* +* Array.[]( 1, 'a', /^A/ ) +* Array[ 1, 'a', /^A/ ] +* [ 1, 'a', /^A/ ] +*/ static VALUE rb_ary_s_create(int argc, VALUE *argv, VALUE klass) @@ -805,6 +700,8 @@ ary_take_first_or_last(int argc, VALUE *argv, VALUE ary, enum ary_take_pos_flags return ary_make_partial(ary, rb_cArray, offset, n); } +static VALUE rb_ary_push_1(VALUE ary, VALUE item); + /* * call-seq: * ary << obj -> ary @@ -821,12 +718,8 @@ ary_take_first_or_last(int argc, VALUE *argv, VALUE ary, enum ary_take_pos_flags VALUE rb_ary_push(VALUE ary, VALUE item) { - long idx = RARRAY_LEN(ary); - - ary_ensure_room_for_push(ary, 1); - RARRAY_PTR(ary)[idx] = item; - ARY_SET_LEN(ary, idx + 1); - return ary; + rb_ary_modify(ary); + return rb_ary_push_1(ary, item); } static VALUE @@ -842,37 +735,27 @@ rb_ary_push_1(VALUE ary, VALUE item) return ary; } -VALUE -rb_ary_cat(VALUE ary, const VALUE *ptr, long len) -{ - long oldlen = RARRAY_LEN(ary); - - ary_ensure_room_for_push(ary, len); - MEMCPY(RARRAY_PTR(ary) + oldlen, ptr, VALUE, len); - ARY_SET_LEN(ary, oldlen + len); - return ary; -} - /* * call-seq: * ary.push(obj, ... ) -> ary * - * Append --- Pushes the given object(s) on to the end of this array. This + * Append---Pushes the given object(s) on to the end of this array. This * expression returns the array itself, so several appends - * may be chained together. See also Array#pop for the opposite - * effect. + * may be chained together. * * a = [ "a", "b", "c" ] * a.push("d", "e", "f") * #=> ["a", "b", "c", "d", "e", "f"] - * [1, 2, 3,].push(4).push(5) - * #=> [1, 2, 3, 4, 5] */ static VALUE rb_ary_push_m(int argc, VALUE *argv, VALUE ary) { - return rb_ary_cat(ary, argv, argc); + rb_ary_modify(ary); + while (argc--) { + rb_ary_push_1(ary, *argv++); + } + return ary; } VALUE @@ -898,11 +781,10 @@ rb_ary_pop(VALUE ary) * ary.pop(n) -> new_ary * * Removes the last element from +self+ and returns it, or - * +nil+ if the array is empty. + * <code>nil</code> if the array is empty. * - * If a number +n+ is given, returns an array of the last +n+ elements - * (or less) just like <code>array.slice!(-n, n)</code> does. See also - * Array#push for the opposite effect. + * If a number _n_ is given, returns an array of the last n elements + * (or less) just like <code>array.slice!(-n, n)</code> does. * * a = [ "a", "b", "c", "d" ] * a.pop #=> "d" @@ -958,14 +840,12 @@ rb_ary_shift(VALUE ary) * ary.shift -> obj or nil * ary.shift(n) -> new_ary * - * Removes the first element of +self+ and returns it (shifting all - * other elements down by one). Returns +nil+ if the array + * Returns the first element of +self+ and removes it (shifting all + * other elements down by one). Returns <code>nil</code> if the array * is empty. * - * If a number +n+ is given, returns an array of the first +n+ elements - * (or less) just like <code>array.slice!(0, n)</code> does. With +ary+ - * containing only the remainder elements, not including what was shifted to - * +new_ary+. See also Array#unshift for the opposite effect. + * If a number _n_ is given, returns an array of the first n elements + * (or less) just like <code>array.slice!(0, n)</code> does. * * args = [ "-m", "-q", "filename" ] * args.shift #=> "-m" @@ -1003,61 +883,12 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary) return result; } -static void -ary_ensure_room_for_unshift(VALUE ary, int argc) -{ - long len = RARRAY_LEN(ary); - long new_len = len + argc; - long capa; - VALUE *head, *sharedp; - - if (ARY_SHARED_P(ary)) { - VALUE shared = ARY_SHARED(ary); - capa = RARRAY_LEN(shared); - if (ARY_SHARED_NUM(shared) == 1 && capa > new_len) { - head = RARRAY_PTR(ary); - sharedp = RARRAY_PTR(shared); - goto makeroom_if_need; - } - } - - rb_ary_modify(ary); - capa = ARY_CAPA(ary); - if (capa - (capa >> 6) <= new_len) { - ary_double_capa(ary, new_len); - } - - /* use shared array for big "queues" */ - if (new_len > ARY_DEFAULT_SIZE * 4) { - /* make a room for unshifted items */ - capa = ARY_CAPA(ary); - ary_make_shared(ary); - - head = sharedp = RARRAY_PTR(ary); - goto makeroom; - makeroom_if_need: - if (head - sharedp < argc) { - long room; - makeroom: - room = capa - new_len; - room -= room >> 4; - MEMMOVE(sharedp + argc + room, head, VALUE, len); - head = sharedp + argc + room; - } - ARY_SET_PTR(ary, head - argc); - } - else { - /* sliding items */ - MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len); - } -} - /* * call-seq: * ary.unshift(obj, ...) -> ary * - * Prepends objects to the front of +self+, moving other elements upwards. - * See also Array#shift for the opposite effect. + * Prepends objects to the front of +self+, + * moving other elements upwards. * * a = [ "b", "c", "d" ] * a.unshift("a") #=> ["a", "b", "c", "d"] @@ -1067,16 +898,19 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) static VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary) { - long len = RARRAY_LEN(ary); + long len; - if (argc == 0) { - rb_ary_modify_check(ary); - return ary; + rb_ary_modify(ary); + if (argc == 0) return ary; + if (ARY_CAPA(ary) <= (len = RARRAY_LEN(ary)) + argc) { + ary_double_capa(ary, len + argc); } - ary_ensure_room_for_unshift(ary, argc); + /* sliding items */ + MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len); MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc); - ARY_SET_LEN(ary, len + argc); + ARY_INCREASE_LEN(ary, argc); + return ary; } @@ -1132,16 +966,13 @@ rb_ary_subseq(VALUE ary, long beg, long len) * ary.slice(start, length) -> new_ary or nil * ary.slice(range) -> new_ary or nil * - * Element Reference --- Returns the element at +index+, or returns a - * subarray starting at the +start+ index and continuing for +length+ - * elements, or returns a subarray specified by +range+ of indices. - * - * Negative indices count backward from the end of the array (-1 is the last - * element). For +start+ and +range+ cases the starting index is just before - * an element. Additionally, an empty array is returned when the starting - * index for an element range is at the end of the array. - * - * Returns +nil+ if the index (or starting index) are out of range. + * Element Reference---Returns the element at _index_, + * or returns a subarray starting at _start_ and + * continuing for _length_ elements, or returns a subarray + * specified by _range_. + * Negative indices count backward from the end of the + * array (-1 is the last element). Returns +nil+ if the index + * (or starting index) are out of range. * * a = [ "a", "b", "c", "d", "e" ] * a[2] + a[0] + a[1] #=> "cab" @@ -1153,7 +984,6 @@ rb_ary_subseq(VALUE ary, long beg, long len) * a[-3, 3] #=> [ "c", "d", "e" ] * # special cases * a[5] #=> nil - * a[6, 1] #=> nil * a[5, 1] #=> [] * a[5..10] #=> [] * @@ -1174,7 +1004,7 @@ rb_ary_aref(int argc, VALUE *argv, VALUE ary) return rb_ary_subseq(ary, beg, len); } if (argc != 1) { - rb_scan_args(argc, argv, "11", NULL, NULL); + rb_scan_args(argc, argv, "11", 0, 0); } arg = argv[0]; /* special case - speeding up */ @@ -1197,9 +1027,9 @@ rb_ary_aref(int argc, VALUE *argv, VALUE ary) * call-seq: * ary.at(index) -> obj or nil * - * Returns the element at +index+. A negative index counts from the end of - * +self+. Returns +nil+ if the index is out of range. See also - * Array#[]. + * Returns the element at _index_. A + * negative index counts from the end of +self+. Returns +nil+ + * if the index is out of range. See also <code>Array#[]</code>. * * a = [ "a", "b", "c", "d", "e" ] * a.at(0) #=> "a" @@ -1218,9 +1048,8 @@ rb_ary_at(VALUE ary, VALUE pos) * ary.first(n) -> new_ary * * Returns the first element, or the first +n+ elements, of the array. - * If the array is empty, the first form returns +nil+, and the - * second form returns an empty array. See also Array#last for - * the opposite effect. + * If the array is empty, the first form returns <code>nil</code>, and the + * second form returns an empty array. * * a = [ "q", "r", "s", "t" ] * a.first #=> "q" @@ -1245,9 +1074,7 @@ rb_ary_first(int argc, VALUE *argv, VALUE ary) * ary.last(n) -> new_ary * * Returns the last element(s) of +self+. If the array is empty, - * the first form returns +nil+. - * - * See also Array#first for the opposite effect. + * the first form returns <code>nil</code>. * * a = [ "w", "x", "y", "z" ] * a.last #=> "z" @@ -1269,24 +1096,21 @@ rb_ary_last(int argc, VALUE *argv, VALUE ary) /* * call-seq: * ary.fetch(index) -> obj - * ary.fetch(index, default) -> obj - * ary.fetch(index) { |index| block } -> obj + * ary.fetch(index, default ) -> obj + * ary.fetch(index) {|index| block } -> obj * - * Tries to return the element at position +index+, but throws an IndexError - * exception if the referenced +index+ lies outside of the array bounds. This - * error can be prevented by supplying a second argument, which will act as a - * +default+ value. - * - * Alternatively, if a block is given it will only be executed when an - * invalid +index+ is referenced. Negative values of +index+ count from the - * end of the array. + * Tries to return the element at position <i>index</i>. If the index + * lies outside the array, the first form throws an + * <code>IndexError</code> exception, the second form returns + * <i>default</i>, and the third form returns the value of invoking + * the block, passing in the index. Negative values of <i>index</i> + * count from the end of the array. * * a = [ 11, 22, 33, 44 ] * a.fetch(1) #=> 22 * a.fetch(-1) #=> 44 * a.fetch(4, 'cat') #=> "cat" - * a.fetch(100) { |i| puts "#{i} is out of bounds" } - * #=> "100 is out of bounds" + * a.fetch(4) { |i| i*i } #=> 16 */ static VALUE @@ -1319,27 +1143,24 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * ary.index(obj) -> int or nil - * ary.index { |item| block } -> int or nil - * ary.index -> Enumerator - * - * Returns the _index_ of the first object in +ary+ such that the object is - * <code>==</code> to +obj+. + * ary.index(obj) -> int or nil + * ary.index {|item| block} -> int or nil + * ary.index -> an_enumerator * - * If a block is given instead of an argument, returns the _index_ of the - * first object for which the block returns +true+. Returns +nil+ if no - * match is found. + * Returns the index of the first object in +self+ such that is + * <code>==</code> to <i>obj</i>. If a block is given instead of an + * argument, returns first object for which <em>block</em> is true. + * Returns <code>nil</code> if no match is found. + * See also <code>Array#rindex</code>. * - * See also Array#rindex. - * - * An Enumerator is returned if neither a block nor argument is given. + * If neither block nor argument is given, an enumerator is returned instead. * * a = [ "a", "b", "c" ] - * a.index("b") #=> 1 - * a.index("z") #=> nil - * a.index { |x| x == "b" } #=> 1 + * a.index("b") #=> 1 + * a.index("z") #=> nil + * a.index{|x|x=="b"} #=> 1 * - * This is an alias of Array#find_index. + * This is an alias of <code>#find_index</code>. */ static VALUE @@ -1369,26 +1190,23 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * ary.rindex(obj) -> int or nil - * ary.rindex { |item| block } -> int or nil - * ary.rindex -> Enumerator - * - * Returns the _index_ of the last object in +self+ <code>==</code> to +obj+. - * - * If a block is given instead of an argument, returns the _index_ of the - * first object for which the block returns +true+, starting from the last - * object. - * - * Returns +nil+ if no match is found. + * ary.rindex(obj) -> int or nil + * ary.rindex {|item| block} -> int or nil + * ary.rindex -> an_enumerator * - * See also Array#index. + * Returns the index of the last object in +self+ + * <code>==</code> to <i>obj</i>. If a block is given instead of an + * argument, returns first object for which <em>block</em> is + * true, starting from the last object. + * Returns <code>nil</code> if no match is found. + * See also <code>Array#index</code>. * - * If neither block nor argument is given, an Enumerator is returned instead. + * If neither block nor argument is given, an enumerator is returned instead. * * a = [ "a", "b", "b", "b", "c" ] - * a.rindex("b") #=> 3 - * a.rindex("z") #=> nil - * a.rindex { |x| x == "b" } #=> 3 + * a.rindex("b") #=> 3 + * a.rindex("z") #=> nil + * a.rindex{|x|x=="b"} #=> 3 */ static VALUE @@ -1454,12 +1272,15 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) rpl = rb_ary_to_ary(rpl); rlen = RARRAY_LEN(rpl); } + rb_ary_modify(ary); if (beg >= RARRAY_LEN(ary)) { if (beg > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", beg); } - ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */ len = beg + rlen; + if (len >= ARY_CAPA(ary)) { + ary_double_capa(ary, len); + } rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), beg - RARRAY_LEN(ary)); if (rlen > 0) { MEMCPY(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen); @@ -1469,7 +1290,6 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) else { long alen; - rb_ary_modify(ary); alen = RARRAY_LEN(ary) + rlen - len; if (alen >= ARY_CAPA(ary)) { ary_double_capa(ary, alen); @@ -1486,88 +1306,22 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) } } -void -rb_ary_set_len(VALUE ary, long len) -{ - long capa; - - rb_ary_modify_check(ary); - if (ARY_SHARED_P(ary)) { - rb_raise(rb_eRuntimeError, "can't set length of shared "); - } - if (len > (capa = (long)ARY_CAPA(ary))) { - rb_bug("probable buffer overflow: %ld for %ld", len, capa); - } - ARY_SET_LEN(ary, len); -} - -/*! - * expands or shrinks \a ary to \a len elements. - * expanded region will be filled with Qnil. - * \param ary an array - * \param len new size - * \return \a ary - * \post the size of \a ary is \a len. - */ -VALUE -rb_ary_resize(VALUE ary, long len) -{ - long olen; - - rb_ary_modify(ary); - olen = RARRAY_LEN(ary); - if (len == olen) return ary; - if (len > ARY_MAX_SIZE) { - rb_raise(rb_eIndexError, "index %ld too big", len); - } - if (len > olen) { - if (len >= ARY_CAPA(ary)) { - ary_double_capa(ary, len); - } - rb_mem_clear(RARRAY_PTR(ary) + olen, len - olen); - ARY_SET_LEN(ary, len); - } - else if (ARY_EMBED_P(ary)) { - ARY_SET_EMBED_LEN(ary, len); - } - else if (len <= RARRAY_EMBED_LEN_MAX) { - VALUE tmp[RARRAY_EMBED_LEN_MAX]; - MEMCPY(tmp, ARY_HEAP_PTR(ary), VALUE, len); - ary_discard(ary); - MEMCPY(ARY_EMBED_PTR(ary), tmp, VALUE, len); - ARY_SET_EMBED_LEN(ary, len); - } - else { - if (olen > len + ARY_DEFAULT_SIZE) { - REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, len); - ARY_SET_CAPA(ary, len); - } - ARY_SET_HEAP_LEN(ary, len); - } - return ary; -} - /* * call-seq: * ary[index] = obj -> obj * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil * ary[range] = obj or other_ary or nil -> obj or other_ary or nil * - * Element Assignment --- Sets the element at +index+, or replaces a subarray - * from the +start+ index for +length+ elements, or replaces a subarray - * specified by the +range+ of indices. - * - * If indices are greater than the current capacity of the array, the array - * grows automatically. Elements are inserted into the array at +start+ if - * +length+ is zero. - * - * Negative indices will count backward from the end of the array. For - * +start+ and +range+ cases the starting index is just before an element. - * - * An IndexError is raised if a negative index points past the beginning of - * the array. - * - * See also Array#push, and Array#unshift. + * Element Assignment---Sets the element at _index_, + * or replaces a subarray starting at _start_ and + * continuing for _length_ elements, or replaces a subarray + * specified by _range_. If indices are greater than + * the current capacity of the array, the array grows + * automatically. A negative indices will count backward + * from the end of the array. Inserts elements if _length_ is + * zero. An +IndexError+ is raised if a negative index points + * past the beginning of the array. See also + * <code>Array#push</code>, and <code>Array#unshift</code>. * * a = Array.new * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] @@ -1578,8 +1332,6 @@ rb_ary_resize(VALUE ary, long len) * a[-1] = "Z" #=> ["A", "Z"] * a[1..-1] = nil #=> ["A", nil] * a[1..-1] = [] #=> ["A"] - * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] - * a[3, 0] = "B" #=> [1, 2, "A", "B"] */ static VALUE @@ -1594,7 +1346,9 @@ rb_ary_aset(int argc, VALUE *argv, VALUE ary) rb_ary_splice(ary, beg, len, argv[2]); return argv[2]; } - rb_check_arity(argc, 2, 2); + if (argc != 2) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); + } rb_ary_modify_check(ary); if (FIXNUM_P(argv[0])) { offset = FIX2LONG(argv[0]); @@ -1616,10 +1370,8 @@ fixnum: * call-seq: * ary.insert(index, obj...) -> ary * - * Inserts the given values before the element with the given +index+. - * - * Negative indices count backwards from the end of the array, where +-1+ is - * the last element. + * Inserts the given values before the element with the given index + * (which may be negative). * * a = %w{ a b c d } * a.insert(2, 99) #=> ["a", "b", 99, "c", "d"] @@ -1631,7 +1383,9 @@ rb_ary_insert(int argc, VALUE *argv, VALUE ary) { long pos; - rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); + if (argc < 1) { + rb_raise(rb_eArgError, "wrong number of arguments (at least 1)"); + } rb_ary_modify_check(ary); if (argc == 1) return ary; pos = NUM2LONG(argv[0]); @@ -1645,18 +1399,15 @@ rb_ary_insert(int argc, VALUE *argv, VALUE ary) return ary; } -static VALUE -rb_ary_length(VALUE ary); - /* * call-seq: - * ary.each { |item| block } -> ary - * ary.each -> Enumerator + * ary.each {|item| block } -> ary + * ary.each -> an_enumerator * - * Calls the given block once for each element in +self+, passing that element - * as a parameter. + * Calls <i>block</i> once for each element in +self+, passing that + * element as a parameter. * - * An Enumerator is returned if no block is given. + * If no block is given, an enumerator is returned instead. * * a = [ "a", "b", "c" ] * a.each {|x| print x, " -- " } @@ -1667,12 +1418,11 @@ rb_ary_length(VALUE ary); */ VALUE -rb_ary_each(VALUE array) +rb_ary_each(VALUE ary) { long i; - volatile VALUE ary = array; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(RARRAY_PTR(ary)[i]); } @@ -1681,13 +1431,14 @@ rb_ary_each(VALUE array) /* * call-seq: - * ary.each_index { |index| block } -> ary - * ary.each_index -> Enumerator + * ary.each_index {|index| block } -> ary + * ary.each_index -> an_enumerator + * + * Same as <code>Array#each</code>, but passes the index of the element + * instead of the element itself. * - * Same as Array#each, but passes the +index+ of the element instead of the - * element itself. + * If no block is given, an enumerator is returned instead. * - * An Enumerator is returned if no block is given. * * a = [ "a", "b", "c" ] * a.each_index {|x| print x, " -- " } @@ -1701,7 +1452,7 @@ static VALUE rb_ary_each_index(VALUE ary) { long i; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(LONG2NUM(i)); @@ -1711,10 +1462,11 @@ rb_ary_each_index(VALUE ary) /* * call-seq: - * ary.reverse_each { |item| block } -> ary - * ary.reverse_each -> Enumerator + * ary.reverse_each {|item| block } -> ary + * ary.reverse_each -> an_enumerator * - * Same as Array#each, but traverses +self+ in reverse order. + * Same as <code>Array#each</code>, but traverses +self+ in reverse + * order. * * a = [ "a", "b", "c" ] * a.reverse_each {|x| print x, " " } @@ -1729,7 +1481,7 @@ rb_ary_reverse_each(VALUE ary) { long len; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); len = RARRAY_LEN(ary); while (len--) { rb_yield(RARRAY_PTR(ary)[len]); @@ -1747,7 +1499,6 @@ rb_ary_reverse_each(VALUE ary) * Returns the number of elements in +self+. May be zero. * * [ 1, 2, 3, 4, 5 ].length #=> 5 - * [].length #=> 0 */ static VALUE @@ -1761,7 +1512,7 @@ rb_ary_length(VALUE ary) * call-seq: * ary.empty? -> true or false * - * Returns +true+ if +self+ contains no elements. + * Returns <code>true</code> if +self+ contains no elements. * * [].empty? #=> true */ @@ -1774,12 +1525,22 @@ rb_ary_empty_p(VALUE ary) return Qfalse; } +static VALUE +rb_ary_dup_setup(VALUE ary) +{ + VALUE dup = rb_ary_new2(RARRAY_LEN(ary)); + int is_embed = ARY_EMBED_P(dup); + DUPSETUP(dup, ary); + if (is_embed) FL_SET_EMBED(dup); + ARY_SET_LEN(dup, RARRAY_LEN(ary)); + return dup; +} + VALUE rb_ary_dup(VALUE ary) { - VALUE dup = rb_ary_new2(RARRAY_LEN(ary)); + VALUE dup = rb_ary_dup_setup(ary); MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary)); - ARY_SET_LEN(dup, RARRAY_LEN(ary)); return dup; } @@ -1791,7 +1552,7 @@ rb_ary_resurrect(VALUE ary) extern VALUE rb_output_fs; -static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first); +static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result); static VALUE recursive_join(VALUE obj, VALUE argp, int recur) @@ -1800,13 +1561,12 @@ recursive_join(VALUE obj, VALUE argp, int recur) VALUE ary = arg[0]; VALUE sep = arg[1]; VALUE result = arg[2]; - int *first = (int *)arg[3]; if (recur) { rb_raise(rb_eArgError, "recursive array join"); } else { - ary_join_1(obj, ary, sep, 0, result, first); + ary_join_1(obj, ary, sep, 0, result); } return Qnil; } @@ -1817,7 +1577,6 @@ ary_join_0(VALUE ary, VALUE sep, long max, VALUE result) long i; VALUE val; - if (max > 0) rb_enc_copy(result, RARRAY_PTR(ary)[0]); for (i=0; i<max; i++) { val = RARRAY_PTR(ary)[i]; if (i > 0 && !NIL_P(sep)) @@ -1829,7 +1588,7 @@ ary_join_0(VALUE ary, VALUE sep, long max, VALUE result) } static void -ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first) +ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result) { VALUE val, tmp; @@ -1842,7 +1601,6 @@ ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first) case T_STRING: str_join: rb_str_buf_append(result, val); - *first = FALSE; break; case T_ARRAY: obj = val; @@ -1851,12 +1609,11 @@ ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first) rb_raise(rb_eArgError, "recursive array join"); } else { - VALUE args[4]; + VALUE args[3]; args[0] = val; args[1] = sep; args[2] = result; - args[3] = (VALUE)first; rb_exec_recursive(recursive_join, obj, (VALUE)args); } break; @@ -1873,10 +1630,6 @@ ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first) goto ary_join; } val = rb_obj_as_string(val); - if (*first) { - rb_enc_copy(result, val); - *first = FALSE; - } goto str_join; } } @@ -1891,8 +1644,8 @@ rb_ary_join(VALUE ary, VALUE sep) VALUE val, tmp, result; if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0); - if (OBJ_TAINTED(ary)) taint = TRUE; - if (OBJ_UNTRUSTED(ary)) untrust = TRUE; + if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = TRUE; + if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = TRUE; if (!NIL_P(sep)) { StringValue(sep); @@ -1903,14 +1656,11 @@ rb_ary_join(VALUE ary, VALUE sep) tmp = rb_check_string_type(val); if (NIL_P(tmp) || tmp != val) { - int first; result = rb_str_buf_new(len + (RARRAY_LEN(ary)-i)*10); - rb_enc_associate(result, rb_usascii_encoding()); if (taint) OBJ_TAINT(result); if (untrust) OBJ_UNTRUST(result); ary_join_0(ary, sep, i, result); - first = i == 0; - ary_join_1(ary, ary, sep, i, result, &first); + ary_join_1(ary, ary, sep, i, result); return result; } @@ -1927,12 +1677,10 @@ rb_ary_join(VALUE ary, VALUE sep) /* * call-seq: - * ary.join(separator=$,) -> str + * ary.join(sep=$,) -> str * * Returns a string created by converting each element of the array to - * a string, separated by the given +separator+. - * If the +separator+ is +nil+, it uses current $,. - * If both the +separator+ and $, are nil, it uses empty string. + * a string, separated by <i>sep</i>. * * [ "a", "b", "c" ].join #=> "abc" * [ "a", "b", "c" ].join("-") #=> "a-b-c" @@ -1957,14 +1705,13 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) long i; VALUE s, str; - if (recur) return rb_usascii_str_new_cstr("[...]"); + if (recur) return rb_tainted_str_new2("[...]"); str = rb_str_buf_new2("["); for (i=0; i<RARRAY_LEN(ary); i++) { s = rb_inspect(RARRAY_PTR(ary)[i]); if (OBJ_TAINTED(s)) tainted = TRUE; if (OBJ_UNTRUSTED(s)) untrust = TRUE; if (i > 0) rb_str_buf_cat2(str, ", "); - else rb_enc_copy(str, s); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); @@ -1975,12 +1722,10 @@ inspect_ary(VALUE ary, VALUE dummy, int recur) /* * call-seq: + * ary.to_s -> string * ary.inspect -> string - * ary.to_s -> string * * Creates a string representation of +self+. - * - * [ "a", "b", "c" ].to_s #=> "[\"a\", \"b\", \"c\"]" */ static VALUE @@ -2000,9 +1745,8 @@ rb_ary_to_s(VALUE ary) * call-seq: * ary.to_a -> ary * - * Returns +self+. - * - * If called on a subclass of Array, converts the receiver to an Array object. + * Returns +self+. If called on a subclass of Array, converts + * the receiver to an Array object. */ static VALUE @@ -2030,7 +1774,8 @@ rb_ary_to_ary_m(VALUE ary) } static void -ary_reverse(VALUE *p1, VALUE *p2) +ary_reverse(p1, p2) + VALUE *p1, *p2; { while (p1 < p2) { VALUE tmp = *p1; @@ -2072,7 +1817,7 @@ rb_ary_reverse_bang(VALUE ary) /* * call-seq: - * ary.reverse -> new_ary + * ary.reverse -> new_ary * * Returns a new array containing +self+'s elements in reverse order. * @@ -2083,15 +1828,14 @@ rb_ary_reverse_bang(VALUE ary) static VALUE rb_ary_reverse_m(VALUE ary) { + VALUE dup = rb_ary_dup_setup(ary); long len = RARRAY_LEN(ary); - VALUE dup = rb_ary_new2(len); if (len > 0) { VALUE *p1 = RARRAY_PTR(ary); VALUE *p2 = RARRAY_PTR(dup) + len - 1; do *p2-- = *p1++; while (--len > 0); } - ARY_SET_LEN(dup, RARRAY_LEN(ary)); return dup; } @@ -2124,13 +1868,11 @@ rb_ary_rotate(VALUE ary, long cnt) /* * call-seq: - * ary.rotate!(count=1) -> ary - * - * Rotates +self+ in place so that the element at +count+ comes first, and - * returns +self+. + * ary.rotate!(cnt=1) -> ary * - * If +count+ is negative then it rotates in the opposite direction, starting - * from the end of the array where +-1+ is the last element. + * Rotates +self+ in place so that the element at +cnt+ comes first, + * and returns +self+. If +cnt+ is negative then it rotates in + * counter direction. * * a = [ "a", "b", "c", "d" ] * a.rotate! #=> ["b", "c", "d", "a"] @@ -2155,13 +1897,11 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * ary.rotate(count=1) -> new_ary + * ary.rotate([n = 1]) -> new_ary * - * Returns a new array by rotating +self+ so that the element at +count+ is - * the first element of the new array. - * - * If +count+ is negative then it rotates in the opposite direction, starting - * from the end of +self+ where +-1+ is the last element. + * Returns new array by rotating +self+, whose first element is the + * element at +cnt+ in +self+. If +cnt+ is negative then it rotates + * in counter direction. * * a = [ "a", "b", "c", "d" ] * a.rotate #=> ["b", "c", "d", "a"] @@ -2183,7 +1923,7 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) } len = RARRAY_LEN(ary); - rotated = rb_ary_new2(len); + rotated = rb_ary_dup_setup(ary); if (len > 0) { cnt = rotate_count(cnt, len); ptr = RARRAY_PTR(ary); @@ -2192,7 +1932,6 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) MEMCPY(ptr2, ptr + cnt, VALUE, len); MEMCPY(ptr2 + len, ptr, VALUE, cnt); } - ARY_SET_LEN(rotated, RARRAY_LEN(ary)); return rotated; } @@ -2208,15 +1947,15 @@ enum { sort_optimizable_count }; -#define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString) +#define STRING_P(s) (TYPE(s) == T_STRING && CLASS_OF(s) == rb_cString) #define SORT_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(sort_opt_,type)) #define SORT_OPTIMIZABLE(data, type) \ - (((data)->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \ - ((data)->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \ - (((data)->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \ + ((data->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \ + (data->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \ + ((data->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \ rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \ - ((data)->opt_methods |= SORT_OPTIMIZABLE_BIT(type)))) + (data->opt_methods |= SORT_OPTIMIZABLE_BIT(type)))) static VALUE sort_reentered(VALUE ary) @@ -2268,22 +2007,17 @@ sort_2(const void *ap, const void *bp, void *dummy) /* * call-seq: * ary.sort! -> ary - * ary.sort! { |a, b| block } -> ary - * - * Sorts +self+ in place. + * ary.sort! {| a,b | block } -> ary * - * Comparisons for the sort will be done using the <code><=></code> operator - * or using an optional code block. - * - * The block must implement a comparison between +a+ and +b+, and return - * +-1+, when +a+ follows +b+, +0+ when +a+ and +b+ are equivalent, or ++1+ - * if +b+ follows +a+. - * - * See also Enumerable#sort_by. + * Sorts +self+. Comparisons for + * the sort will be done using the <code><=></code> operator or using + * an optional code block. The block implements a comparison between + * <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also + * <code>Enumerable#sort_by</code>. * * a = [ "d", "a", "e", "c", "b" ] - * a.sort! #=> ["a", "b", "c", "d", "e"] - * a.sort! { |x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] + * a.sort #=> ["a", "b", "c", "d", "e"] + * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE @@ -2294,13 +2028,12 @@ rb_ary_sort_bang(VALUE ary) if (RARRAY_LEN(ary) > 1) { VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */ struct ary_sort_data data; - long len = RARRAY_LEN(ary); RBASIC(tmp)->klass = 0; data.ary = tmp; data.opt_methods = 0; data.opt_inited = 0; - ruby_qsort(RARRAY_PTR(tmp), len, sizeof(VALUE), + ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE), rb_block_given_p()?sort_1:sort_2, &data); if (ARY_EMBED_P(tmp)) { @@ -2317,7 +2050,7 @@ rb_ary_sort_bang(VALUE ary) if (ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) { assert(!ARY_EMBED_P(ary)); FL_UNSET_SHARED(ary); - ARY_SET_CAPA(ary, RARRAY_LEN(tmp)); + ARY_SET_CAPA(ary, ARY_CAPA(tmp)); } else { assert(!ARY_SHARED_P(tmp)); @@ -2332,8 +2065,8 @@ rb_ary_sort_bang(VALUE ary) xfree(ARY_HEAP_PTR(ary)); } ARY_SET_PTR(ary, RARRAY_PTR(tmp)); - ARY_SET_HEAP_LEN(ary, len); - ARY_SET_CAPA(ary, RARRAY_LEN(tmp)); + ARY_SET_HEAP_LEN(ary, RARRAY_LEN(tmp)); + ARY_SET_CAPA(ary, ARY_CAPA(tmp)); } /* tmp was lost ownership for the ptr */ FL_UNSET(tmp, FL_FREEZE); @@ -2350,23 +2083,17 @@ rb_ary_sort_bang(VALUE ary) /* * call-seq: * ary.sort -> new_ary - * ary.sort { |a, b| block } -> new_ary + * ary.sort {| a,b | block } -> new_ary * - * Returns a new array created by sorting +self+. - * - * Comparisons for the sort will be done using the <code><=></code> operator - * or using an optional code block. - * - * The block must implement a comparison between +a+ and +b+, and return - * +-1+, when +a+ follows +b+, +0+ when +a+ and +b+ are equivalent, or ++1+ - * if +b+ follows +a+. - * - * - * See also Enumerable#sort_by. + * Returns a new array created by sorting +self+. Comparisons for + * the sort will be done using the <code><=></code> operator or using + * an optional code block. The block implements a comparison between + * <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also + * <code>Enumerable#sort_by</code>. * * a = [ "d", "a", "e", "c", "b" ] * a.sort #=> ["a", "b", "c", "d", "e"] - * a.sort { |x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] + * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE @@ -2377,106 +2104,6 @@ rb_ary_sort(VALUE ary) return ary; } -/* - * call-seq: - * ary.bsearch {|x| block } -> elem - * - * By using binary search, finds a value from this array which meets - * the given condition in O(log n) where n is the size of the array. - * - * You can use this method in two use cases: a find-minimum mode and - * a find-any mode. In either case, the elements of the array must be - * monotone (or sorted) with respect to the block. - * - * In find-minimum mode (this is a good choice for typical use case), - * the block must return true or false, and there must be an index i - * (0 <= i <= ary.size) so that: - * - * - the block returns false for any element whose index is less than - * i, and - * - the block returns true for any element whose index is greater - * than or equal to i. - * - * This method returns the i-th element. If i is equal to ary.size, - * it returns nil. - * - * ary = [0, 4, 7, 10, 12] - * ary.bsearch {|x| x >= 4 } #=> 4 - * ary.bsearch {|x| x >= 6 } #=> 7 - * ary.bsearch {|x| x >= -1 } #=> 0 - * ary.bsearch {|x| x >= 100 } #=> nil - * - * In find-any mode (this behaves like libc's bsearch(3)), the block - * must return a number, and there must be two indices i and j - * (0 <= i <= j <= ary.size) so that: - * - * - the block returns a positive number for ary[k] if 0 <= k < i, - * - the block returns zero for ary[k] if i <= k < j, and - * - the block returns a negative number for ary[k] if - * j <= k < ary.size. - * - * Under this condition, this method returns any element whose index - * is within i...j. If i is equal to j (i.e., there is no element - * that satisfies the block), this method returns nil. - * - * ary = [0, 4, 7, 10, 12] - * # try to find v such that 4 <= v < 8 - * ary.bsearch {|x| 1 - x / 4 } #=> 4 or 7 - * # try to find v such that 8 <= v < 10 - * ary.bsearch {|x| 4 - x / 2 } #=> nil - * - * You must not mix the two modes at a time; the block must always - * return either true/false, or always return a number. It is - * undefined which value is actually picked up at each iteration. - */ - -static VALUE -rb_ary_bsearch(VALUE ary) -{ - long low = 0, high = RARRAY_LEN(ary), mid; - int smaller = 0, satisfied = 0; - VALUE v, val; - - RETURN_ENUMERATOR(ary, 0, 0); - while (low < high) { - mid = low + ((high - low) / 2); - val = rb_ary_entry(ary, mid); - v = rb_yield(val); - if (FIXNUM_P(v)) { - if (FIX2INT(v) == 0) return val; - smaller = FIX2INT(v) < 0; - } - else if (v == Qtrue) { - satisfied = 1; - smaller = 1; - } - else if (v == Qfalse || v == Qnil) { - smaller = 0; - } - else if (rb_obj_is_kind_of(v, rb_cNumeric)) { - switch (rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0))) { - case 0: return val; - case 1: smaller = 1; break; - case -1: smaller = 0; - } - } - else { - rb_raise(rb_eTypeError, "wrong argument type %s" - " (must be numeric, true, false or nil)", - rb_obj_classname(v)); - } - if (smaller) { - high = mid; - } - else { - low = mid + 1; - } - } - if (low == RARRAY_LEN(ary)) return Qnil; - if (!satisfied) return Qnil; - return rb_ary_entry(ary, low); -} - static VALUE sort_by_i(VALUE i) @@ -2486,13 +2113,13 @@ sort_by_i(VALUE i) /* * call-seq: - * ary.sort_by! { |obj| block } -> ary - * ary.sort_by! -> Enumerator + * ary.sort_by! {| obj | block } -> ary + * ary.sort_by! -> an_enumerator * * Sorts +self+ in place using a set of keys generated by mapping the * values in +self+ through the given block. * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * */ @@ -2501,7 +2128,7 @@ rb_ary_sort_by_bang(VALUE ary) { VALUE sorted; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0); rb_ary_replace(ary, sorted); @@ -2511,22 +2138,20 @@ rb_ary_sort_by_bang(VALUE ary) /* * call-seq: - * ary.collect { |item| block } -> new_ary - * ary.map { |item| block } -> new_ary - * ary.collect -> Enumerator - * ary.map -> Enumerator - * - * Invokes the given block once for each element of +self+. + * ary.collect {|item| block } -> new_ary + * ary.map {|item| block } -> new_ary + * ary.collect -> an_enumerator + * ary.map -> an_enumerator * - * Creates a new array containing the values returned by the block. + * Invokes <i>block</i> once for each element of +self+. Creates a + * new array containing the values returned by the block. + * See also <code>Enumerable#collect</code>. * - * See also Enumerable#collect. - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * a = [ "a", "b", "c", "d" ] - * a.map { |x| x + "!" } #=> ["a!", "b!", "c!", "d!"] - * a #=> ["a", "b", "c", "d"] + * a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] + * a #=> ["a", "b", "c", "d"] */ static VALUE @@ -2535,7 +2160,7 @@ rb_ary_collect(VALUE ary) long i; VALUE collect; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); collect = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i])); @@ -2548,19 +2173,18 @@ rb_ary_collect(VALUE ary) * call-seq: * ary.collect! {|item| block } -> ary * ary.map! {|item| block } -> ary - * ary.collect! -> Enumerator - * ary.map! -> Enumerator + * ary.collect -> an_enumerator + * ary.map -> an_enumerator * - * Invokes the given block once for each element of +self+, replacing the - * element with the value returned by the block. + * Invokes the block once for each element of +self+, replacing the + * element with the value returned by _block_. + * See also <code>Enumerable#collect</code>. * - * See also Enumerable#collect. - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * a = [ "a", "b", "c", "d" ] - * a.map! {|x| x + "!" } - * a #=> [ "a!", "b!", "c!", "d!" ] + * a.collect! {|x| x + "!" } + * a #=> [ "a!", "b!", "c!", "d!" ] */ static VALUE @@ -2568,7 +2192,7 @@ rb_ary_collect_bang(VALUE ary) { long i; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i])); @@ -2588,13 +2212,15 @@ rb_get_values_at(VALUE obj, long olen, int argc, VALUE *argv, VALUE (*func) (VAL continue; } /* check if idx is Range */ - if (rb_range_beg_len(argv[i], &beg, &len, olen, 1)) { - long end = olen < beg+len ? olen : beg+len; - for (j = beg; j < end; j++) { - rb_ary_push(result, (*func)(obj, j)); + switch (rb_range_beg_len(argv[i], &beg, &len, olen, 0)) { + case Qfalse: + break; + case Qnil: + continue; + default: + for (j=0; j<len; j++) { + rb_ary_push(result, (*func)(obj, j+beg)); } - if (beg + len > j) - rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j); continue; } rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i]))); @@ -2604,20 +2230,18 @@ rb_get_values_at(VALUE obj, long olen, int argc, VALUE *argv, VALUE (*func) (VAL /* * call-seq: - * ary.values_at(selector, ...) -> new_ary - * - * Returns an array containing the elements in +self+ corresponding to the - * given +selector+(s). - * - * The selectors may be either integer indices or ranges. + * ary.values_at(selector,... ) -> new_ary * - * See also Array#select. + * Returns an array containing the elements in + * +self+ corresponding to the given selector(s). The selectors + * may be either integer indices or ranges. + * See also <code>Array#select</code>. * * a = %w{ a b c d e f } - * a.values_at(1, 3, 5) # => ["b", "d", "f"] - * a.values_at(1, 3, 5, 7) # => ["b", "d", "f", nil] - * a.values_at(-1, -2, -2, -7) # => ["f", "e", "e", nil] - * a.values_at(4..6, 3...6) # => ["e", "f", nil, "d", "e", "f"] + * a.values_at(1, 3, 5) + * a.values_at(1, 3, 5, 7) + * a.values_at(-1, -3, -5, -7) + * a.values_at(1..3, 2...5) */ static VALUE @@ -2629,20 +2253,17 @@ rb_ary_values_at(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * ary.select { |item| block } -> new_ary - * ary.select -> Enumerator + * ary.select {|item| block } -> new_ary + * ary.select -> an_enumerator * - * Returns a new array containing all elements of +ary+ - * for which the given +block+ returns a true value. + * Invokes the block passing in successive elements from +self+, + * returning an array containing those elements for which the block + * returns a true value (equivalent to <code>Enumerable#select</code>). * - * If no block is given, an Enumerator is returned instead. - * - * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4] + * If no block is given, an enumerator is returned instead. * * a = %w{ a b c d e f } - * a.select { |v| v =~ /[aeiou]/ } #=> ["a", "e"] - * - * See also Enumerable#select. + * a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"] */ static VALUE @@ -2651,7 +2272,7 @@ rb_ary_select(VALUE ary) VALUE result; long i; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) { @@ -2663,17 +2284,16 @@ rb_ary_select(VALUE ary) /* * call-seq: - * ary.select! {|item| block } -> ary or nil - * ary.select! -> Enumerator - * - * Invokes the given block passing in successive elements from +self+, - * deleting elements for which the block returns a +false+ value. + * ary.select! {|item| block } -> new_ary or nil + * ary.select! -> an_enumerator * - * If changes were made, it will return +self+, otherwise it returns +nil+. + * Invokes the block passing in successive elements from + * +self+, deleting elements for which the block returns a + * false value. It returns +self+ if changes were made, + * otherwise it returns <code>nil</code>. + * See also <code>Array#keep_if</code> * - * See also Array#keep_if - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * */ @@ -2682,7 +2302,7 @@ rb_ary_select_bang(VALUE ary) { long i1, i2; - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { VALUE v = RARRAY_PTR(ary)[i1]; @@ -2701,53 +2321,38 @@ rb_ary_select_bang(VALUE ary) /* * call-seq: - * ary.keep_if { |item| block } -> ary - * ary.keep_if -> Enumerator + * ary.keep_if {|item| block } -> ary + * ary.keep_if -> an_enumerator * - * Deletes every element of +self+ for which the given block evaluates to - * +false+. + * Deletes every element of +self+ for which <i>block</i> evaluates + * to false. + * See also <code>Array#select!</code> * - * See also Array#select! - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * a = %w{ a b c d e f } - * a.keep_if { |v| v =~ /[aeiou]/ } #=> ["a", "e"] + * a.keep_if {|v| v =~ /[aeiou]/} #=> ["a", "e"] */ static VALUE rb_ary_keep_if(VALUE ary) { - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); + RETURN_ENUMERATOR(ary, 0, 0); rb_ary_select_bang(ary); return ary; } -static void -ary_resize_smaller(VALUE ary, long len) -{ - rb_ary_modify(ary); - if (RARRAY_LEN(ary) > len) { - ARY_SET_LEN(ary, len); - if (len * 2 < ARY_CAPA(ary) && - ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { - ary_resize_capa(ary, len * 2); - } - } -} - /* * call-seq: - * ary.delete(obj) -> item or nil - * ary.delete(obj) { block } -> item or result of block - * - * Deletes all items from +self+ that are equal to +obj+. + * ary.delete(obj) -> obj or nil + * ary.delete(obj) { block } -> obj or nil * - * Returns the last deleted item, or +nil+ if no matching item is found. - * - * If the optional code block is given, the result of the block is returned if - * the item is not found. (To remove +nil+ elements and get an informative - * return value, use Array#compact!) + * Deletes items from +self+ that are equal to <i>obj</i>. + * If any items are found, returns <i>obj</i>. If + * the item is not found, returns <code>nil</code>. If the optional + * code block is given, returns the result of <i>block</i> if the item + * is not found. (To remove <code>nil</code> elements and + * get an informative return value, use #compact!) * * a = [ "a", "b", "b", "b", "c" ] * a.delete("b") #=> "b" @@ -2781,32 +2386,16 @@ rb_ary_delete(VALUE ary, VALUE item) return Qnil; } - ary_resize_smaller(ary, i2); - - return v; -} - -void -rb_ary_delete_same(VALUE ary, VALUE item) -{ - long i1, i2; - - for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { - VALUE e = RARRAY_PTR(ary)[i1]; - - if (e == item) { - continue; - } - if (i1 != i2) { - rb_ary_store(ary, i2, e); + rb_ary_modify(ary); + if (RARRAY_LEN(ary) > i2) { + ARY_SET_LEN(ary, i2); + if (i2 * 2 < ARY_CAPA(ary) && + ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { + ary_resize_capa(ary, i2*2); } - i2++; - } - if (RARRAY_LEN(ary) == i2) { - return; } - ary_resize_smaller(ary, i2); + return v; } VALUE @@ -2834,12 +2423,11 @@ rb_ary_delete_at(VALUE ary, long pos) * call-seq: * ary.delete_at(index) -> obj or nil * - * Deletes the element at the specified +index+, returning that element, or - * +nil+ if the +index+ is out of range. + * Deletes the element at the specified index, returning that element, + * or <code>nil</code> if the index is out of range. See also + * <code>Array#slice!</code>. * - * See also Array#slice! - * - * a = ["ant", "bat", "cat", "dog"] + * a = %w( ant bat cat dog ) * a.delete_at(2) #=> "cat" * a #=> ["ant", "bat", "dog"] * a.delete_at(99) #=> nil @@ -2857,11 +2445,9 @@ rb_ary_delete_at_m(VALUE ary, VALUE pos) * ary.slice!(start, length) -> new_ary or nil * ary.slice!(range) -> new_ary or nil * - * Deletes the element(s) given by an +index+ (optionally up to +length+ - * elements) or by a +range+. - * - * Returns the deleted object (or objects), or +nil+ if the +index+ is out of - * range. + * Deletes the element(s) given by an index (optionally with a length) + * or by a range. Returns the deleted object (or objects), or + * <code>nil</code> if the index is out of range. * * a = [ "a", "b", "c" ] * a.slice!(1) #=> "b" @@ -2923,100 +2509,74 @@ rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary) return rb_ary_delete_at(ary, NUM2LONG(arg1)); } -static VALUE -ary_reject(VALUE orig, VALUE result) -{ - long i; - - for (i = 0; i < RARRAY_LEN(orig); i++) { - VALUE v = RARRAY_PTR(orig)[i]; - if (!RTEST(rb_yield(v))) { - rb_ary_push_1(result, v); - } - } - return result; -} - -static VALUE -ary_reject_bang(VALUE ary) -{ - long i; - VALUE result = Qnil; - - rb_ary_modify_check(ary); - for (i = 0; i < RARRAY_LEN(ary); ) { - VALUE v = RARRAY_PTR(ary)[i]; - if (RTEST(rb_yield(v))) { - rb_ary_delete_at(ary, i); - result = ary; - } - else { - i++; - } - } - return result; -} - /* * call-seq: - * ary.reject! { |item| block } -> ary or nil - * ary.reject! -> Enumerator - * - * Equivalent to Array#delete_if, deleting elements from +self+ for which the - * block evaluates to +true+, but returns +nil+ if no changes were made. + * ary.reject! {|item| block } -> ary or nil + * ary.reject! -> an_enumerator * - * The array is changed instantly every time the block is called, not after - * the iteration is over. + * Equivalent to <code>Array#delete_if</code>, deleting elements from + * +self+ for which the block evaluates to true, but returns + * <code>nil</code> if no changes were made. + * See also <code>Enumerable#reject</code> and <code>Array#delete_if</code>. * - * See also Enumerable#reject and Array#delete_if. + * If no block is given, an enumerator is returned instead. * - * If no block is given, an Enumerator is returned instead. */ static VALUE rb_ary_reject_bang(VALUE ary) { - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); - return ary_reject_bang(ary); + long i1, i2; + + RETURN_ENUMERATOR(ary, 0, 0); + rb_ary_modify(ary); + for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { + VALUE v = RARRAY_PTR(ary)[i1]; + if (RTEST(rb_yield(v))) continue; + if (i1 != i2) { + rb_ary_store(ary, i2, v); + } + i2++; + } + + if (RARRAY_LEN(ary) == i2) return Qnil; + if (i2 < RARRAY_LEN(ary)) + ARY_SET_LEN(ary, i2); + return ary; } /* * call-seq: - * ary.reject {|item| block } -> new_ary - * ary.reject -> Enumerator + * ary.reject {|item| block } -> new_ary + * ary.reject -> an_enumerator * - * Returns a new array containing the items in +self+ for which the given - * block is not +true+. + * Returns a new array containing the items in +self+ + * for which the block is not true. + * See also <code>Array#delete_if</code> * - * See also Array#delete_if + * If no block is given, an enumerator is returned instead. * - * If no block is given, an Enumerator is returned instead. */ static VALUE rb_ary_reject(VALUE ary) { - VALUE rejected_ary; - - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); - rejected_ary = rb_ary_new(); - ary_reject(ary, rejected_ary); - return rejected_ary; + RETURN_ENUMERATOR(ary, 0, 0); + ary = rb_ary_dup(ary); + rb_ary_reject_bang(ary); + return ary; } /* * call-seq: - * ary.delete_if { |item| block } -> ary - * ary.delete_if -> Enumerator - * - * Deletes every element of +self+ for which block evaluates to +true+. + * ary.delete_if {|item| block } -> ary + * ary.delete_if -> an_enumerator * - * The array is changed instantly every time the block is called, not after - * the iteration is over. + * Deletes every element of +self+ for which <i>block</i> evaluates + * to true. + * See also <code>Array#reject!</code> * - * See also Array#reject! - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * a = [ "a", "b", "c" ] * a.delete_if {|x| x >= "b" } #=> ["a"] @@ -3025,8 +2585,8 @@ rb_ary_reject(VALUE ary) static VALUE rb_ary_delete_if(VALUE ary) { - RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length); - ary_reject_bang(ary); + RETURN_ENUMERATOR(ary, 0, 0); + rb_ary_reject_bang(ary); return ary; } @@ -3048,35 +2608,30 @@ take_items(VALUE obj, long n) if (!NIL_P(result)) return rb_ary_subseq(result, 0, n); result = rb_ary_new2(n); args[0] = result; args[1] = (VALUE)n; - if (rb_check_block_call(obj, idEach, 0, 0, take_i, (VALUE)args) == Qundef) - rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)", - rb_obj_classname(obj)); + rb_block_call(obj, rb_intern("each"), 0, 0, take_i, (VALUE)args); return result; } /* * call-seq: - * ary.zip(arg, ...) -> new_ary - * ary.zip(arg, ...) { |arr| block } -> nil - * - * Converts any arguments to arrays, then merges elements of +self+ with - * corresponding elements from each argument. - * - * This generates a sequence of <code>ary.size</code> _n_-element arrays, - * where _n_ is one more than the count of arguments. - * - * If the size of any argument is less than the size of the initial array, - * +nil+ values are supplied. - * - * If a block is given, it is invoked for each output +array+, otherwise an - * array of arrays is returned. + * ary.zip(arg, ...) -> new_ary + * ary.zip(arg, ...) {| arr | block } -> nil + * + * Converts any arguments to arrays, then merges elements of + * +self+ with corresponding elements from each argument. This + * generates a sequence of <code>self.size</code> <em>n</em>-element + * arrays, where <em>n</em> is one more that the count of arguments. If + * the size of any argument is less than <code>enumObj.size</code>, + * <code>nil</code> values are supplied. If a block is given, it is + * invoked for each output array, otherwise an array of arrays is + * returned. * * a = [ 4, 5, 6 ] * b = [ 7, 8, 9 ] - * [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] - * [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]] - * a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]] + * [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] + * [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]] + * a.zip([1,2],[8]) #=> [[4,1,8], [5,2,nil], [6,nil,nil]] */ static VALUE @@ -3115,13 +2670,11 @@ rb_ary_zip(int argc, VALUE *argv, VALUE ary) * call-seq: * ary.transpose -> new_ary * - * Assumes that +self+ is an array of arrays and transposes the rows and - * columns. + * Assumes that +self+ is an array of arrays and transposes the + * rows and columns. * * a = [[1,2], [3,4], [5,6]] * a.transpose #=> [[1, 3, 5], [2, 4, 6]] - * - * If the length of the subarrays don't match, an IndexError is raised. */ static VALUE @@ -3156,8 +2709,8 @@ rb_ary_transpose(VALUE ary) * call-seq: * ary.replace(other_ary) -> ary * - * Replaces the contents of +self+ with the contents of +other_ary+, - * truncating or expanding if necessary. + * Replaces the contents of +self+ with the contents of + * <i>other_ary</i>, truncating or expanding if necessary. * * a = [ "a", "b", "c", "d", "e" ] * a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"] @@ -3219,15 +2772,9 @@ rb_ary_replace(VALUE copy, VALUE orig) VALUE rb_ary_clear(VALUE ary) { - rb_ary_modify_check(ary); + rb_ary_modify(ary); ARY_SET_LEN(ary, 0); - if (ARY_SHARED_P(ary)) { - if (!ARY_EMBED_P(ary)) { - rb_ary_unshare(ary); - FL_SET_EMBED(ary); - } - } - else if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { + if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); } return ary; @@ -3235,32 +2782,27 @@ rb_ary_clear(VALUE ary) /* * call-seq: - * ary.fill(obj) -> ary - * ary.fill(obj, start [, length]) -> ary - * ary.fill(obj, range ) -> ary - * ary.fill { |index| block } -> ary - * ary.fill(start [, length] ) { |index| block } -> ary - * ary.fill(range) { |index| block } -> ary + * ary.fill(obj) -> ary + * ary.fill(obj, start [, length]) -> ary + * ary.fill(obj, range ) -> ary + * ary.fill {|index| block } -> ary + * ary.fill(start [, length] ) {|index| block } -> ary + * ary.fill(range) {|index| block } -> ary * * The first three forms set the selected elements of +self+ (which - * may be the entire array) to +obj+. - * - * A +start+ of +nil+ is equivalent to zero. - * - * A +length+ of +nil+ is equivalent to the length of the array. - * - * The last three forms fill the array with the value of the given block, - * which is passed the absolute index of each element to be filled. - * - * Negative values of +start+ count from the end of the array, where +-1+ is - * the last element. + * may be the entire array) to <i>obj</i>. A <i>start</i> of + * <code>nil</code> is equivalent to zero. A <i>length</i> of + * <code>nil</code> is equivalent to <i>self.length</i>. The last three + * forms fill the array with the value of the block. The block is + * passed the absolute index of each element to be filled. + * Negative values of <i>start</i> count from the end of the array. * * a = [ "a", "b", "c", "d" ] * a.fill("x") #=> ["x", "x", "x", "x"] * a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] * a.fill("y", 0..1) #=> ["y", "y", "z", "z"] - * a.fill { |i| i*i } #=> [0, 1, 4, 9] - * a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27] + * a.fill {|i| i*i} #=> [0, 1, 4, 9] + * a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27] */ static VALUE @@ -3338,15 +2880,10 @@ rb_ary_fill(int argc, VALUE *argv, VALUE ary) * call-seq: * ary + other_ary -> new_ary * - * Concatenation --- Returns a new array built by concatenating the + * Concatenation---Returns a new array built by concatenating the * two arrays together to produce a third array. * * [ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ] - * a = [ "a", "b", "c" ] - * a + [ "d", "e", "f" ] - * a #=> [ "a", "b", "c", "d", "e", "f" ] - * - * See also Array#concat. */ VALUE @@ -3368,16 +2905,12 @@ rb_ary_plus(VALUE x, VALUE y) * call-seq: * ary.concat(other_ary) -> ary * - * Appends the elements of +other_ary+ to +self+. + * Appends the elements of <i>other_ary</i> to +self+. * * [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ] - * a = [ 1, 2, 3 ] - * a.concat( [ 4, 5 ] ) - * a #=> [ 1, 2, 3, 4, 5 ] - * - * See also Array#+. */ + VALUE rb_ary_concat(VALUE x, VALUE y) { @@ -3395,11 +2928,9 @@ rb_ary_concat(VALUE x, VALUE y) * ary * int -> new_ary * ary * str -> new_string * - * Repetition --- With a String argument, equivalent to - * <code>ary.join(str)</code>. - * - * Otherwise, returns a new array built by concatenating the +int+ copies of - * +self+. + * Repetition---With a String argument, equivalent to + * self.join(str). Otherwise, returns a new array + * built by concatenating the _int_ copies of +self+. * * * [ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ] @@ -3411,7 +2942,7 @@ static VALUE rb_ary_times(VALUE ary, VALUE times) { VALUE ary2, tmp, *ptr, *ptr2; - long t, len; + long i, t, len; tmp = rb_check_string_type(times); if (!NIL_P(tmp)) { @@ -3437,15 +2968,8 @@ rb_ary_times(VALUE ary, VALUE times) ptr = RARRAY_PTR(ary); ptr2 = RARRAY_PTR(ary2); t = RARRAY_LEN(ary); - if (0 < t) { - MEMCPY(ptr2, ptr, VALUE, t); - while (t <= len/2) { - MEMCPY(ptr2+t, ptr2, VALUE, t); - t *= 2; - } - if (t < len) { - MEMCPY(ptr2+t, ptr2, VALUE, len-t); - } + for (i=0; i<len; i+=t) { + MEMCPY(ptr2+i, ptr, VALUE, t); } out: OBJ_INFECT(ary2, ary); @@ -3457,13 +2981,13 @@ rb_ary_times(VALUE ary, VALUE times) * call-seq: * ary.assoc(obj) -> new_ary or nil * - * Searches through an array whose elements are also arrays comparing +obj+ - * with the first element of each contained array using <code>obj.==</code>. - * - * Returns the first contained array that matches (that is, the first - * associated array), or +nil+ if no match is found. - * - * See also Array#rassoc + * Searches through an array whose elements are also arrays + * comparing _obj_ with the first element of each contained array + * using obj.==. + * Returns the first contained array that matches (that + * is, the first associated array), + * or +nil+ if no match is found. + * See also <code>Array#rassoc</code>. * * s1 = [ "colors", "red", "blue", "green" ] * s2 = [ "letters", "a", "b", "c" ] @@ -3492,14 +3016,10 @@ rb_ary_assoc(VALUE ary, VALUE key) * call-seq: * ary.rassoc(obj) -> new_ary or nil * - * Searches through the array whose elements are also arrays. - * - * Compares +obj+ with the second element of each contained array using - * <code>obj.==</code>. - * - * Returns the first contained array that matches +obj+. - * - * See also Array#assoc. + * Searches through the array whose elements are also arrays. Compares + * _obj_ with the second element of each contained array using + * <code>==</code>. Returns the first contained array that matches. See + * also <code>Array#assoc</code>. * * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ] * a.rassoc("two") #=> [2, "two"] @@ -3514,7 +3034,7 @@ rb_ary_rassoc(VALUE ary, VALUE value) for (i = 0; i < RARRAY_LEN(ary); ++i) { v = RARRAY_PTR(ary)[i]; - if (RB_TYPE_P(v, T_ARRAY) && + if (TYPE(v) == T_ARRAY && RARRAY_LEN(v) > 1 && rb_equal(RARRAY_PTR(v)[1], value)) return v; @@ -3525,32 +3045,12 @@ rb_ary_rassoc(VALUE ary, VALUE value) static VALUE recursive_equal(VALUE ary1, VALUE ary2, int recur) { - long i, len1; - VALUE *p1, *p2; + long i; if (recur) return Qtrue; /* Subtle! */ - - p1 = RARRAY_PTR(ary1); - p2 = RARRAY_PTR(ary2); - len1 = RARRAY_LEN(ary1); - - for (i = 0; i < len1; i++) { - if (*p1 != *p2) { - if (rb_equal(*p1, *p2)) { - len1 = RARRAY_LEN(ary1); - if (len1 != RARRAY_LEN(ary2)) - return Qfalse; - if (len1 < i) - return Qtrue; - p1 = RARRAY_PTR(ary1) + i; - p2 = RARRAY_PTR(ary2) + i; - } - else { - return Qfalse; - } - } - p1++; - p2++; + for (i=0; i<RARRAY_LEN(ary1); i++) { + if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i))) + return Qfalse; } return Qtrue; } @@ -3559,9 +3059,9 @@ recursive_equal(VALUE ary1, VALUE ary2, int recur) * call-seq: * ary == other_ary -> bool * - * Equality --- Two arrays are equal if they contain the same number of - * elements and if each element is equal to (according to Object#==) the - * corresponding element in +other_ary+. + * Equality---Two arrays are equal if they contain the same number + * of elements and if each element is equal to (according to + * Object.==) the corresponding element in the other array. * * [ "a", "c" ] == [ "a", "c", 7 ] #=> false * [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true @@ -3573,7 +3073,7 @@ static VALUE rb_ary_equal(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; - if (!RB_TYPE_P(ary2, T_ARRAY)) { + if (TYPE(ary2) != T_ARRAY) { if (!rb_respond_to(ary2, rb_intern("to_ary"))) { return Qfalse; } @@ -3600,15 +3100,15 @@ recursive_eql(VALUE ary1, VALUE ary2, int recur) * call-seq: * ary.eql?(other) -> true or false * - * Returns +true+ if +self+ and +other+ are the same object, - * or are both arrays with the same content (according to Object#eql?). + * Returns <code>true</code> if +self+ and _other_ are the same object, + * or are both arrays with the same content. */ static VALUE rb_ary_eql(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; - if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse; + if (TYPE(ary2) != T_ARRAY) return Qfalse; if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } @@ -3638,10 +3138,8 @@ recursive_hash(VALUE ary, VALUE dummy, int recur) * call-seq: * ary.hash -> fixnum * - * Compute a hash-code for this array. - * - * Two arrays with the same content will have the same hash code (and will - * compare using #eql?). + * Compute a hash-code for this array. Two arrays with the same content + * will have the same hash code (and will compare using <code>eql?</code>). */ static VALUE @@ -3652,10 +3150,11 @@ rb_ary_hash(VALUE ary) /* * call-seq: - * ary.include?(object) -> true or false + * ary.include?(obj) -> true or false * - * Returns +true+ if the given +object+ is present in +self+ (that is, if any - * element <code>==</code> +object+), otherwise returns +false+. + * Returns <code>true</code> if the given object is present in + * +self+ (that is, if any object <code>==</code> <i>anObject</i>), + * <code>false</code> otherwise. * * a = [ "a", "b", "c" ] * a.include?("b") #=> true @@ -3699,21 +3198,16 @@ recursive_cmp(VALUE ary1, VALUE ary2, int recur) * call-seq: * ary <=> other_ary -> -1, 0, +1 or nil * - * Comparison --- Returns an integer (+-1+, +0+, or <code>+1</code>) if this - * array is less than, equal to, or greater than +other_ary+. - * - * +nil+ is returned if the two values are incomparable. - * - * Each object in each array is compared (using the <=> operator). - * - * Arrays are compared in an "element-wise" manner; the first two elements - * that are not equal will determine the return value for the whole - * comparison. - * - * If all the values are equal, then the return is based on a comparison of - * the array lengths. Thus, two arrays are "equal" according to Array#<=> if, - * and only if, they have the same length and the value of each element is - * equal to the value of the corresponding element in the other array. + * Comparison---Returns an integer (-1, 0, + * or +1) if this array is less than, equal to, or greater than + * <i>other_ary</i>. Each object in each array is compared + * (using <=>). If any value isn't + * equal, then that inequality is the return value. If all the + * values found are equal, then the return is based on a + * comparison of the array lengths. Thus, two arrays are + * ``equal'' according to <code>Array#<=></code> if and only if they have + * the same length and the value of each element is equal to the + * value of the corresponding element in the other array. * * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 @@ -3799,17 +3293,12 @@ ary_recycle_hash(VALUE hash) * call-seq: * ary - other_ary -> new_ary * - * Array Difference - * - * Returns a new array that is a copy of the original array, removing any - * items that also appear in +other_ary+. The order is preserved from the - * original array. - * - * It compares elements using their #hash and #eql? methods for efficiency. + * Array Difference---Returns a new array that is a copy of + * the original array, removing any items that also appear in + * <i>other_ary</i>. (If you need set-like behavior, see the + * library class Set.) * * [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] - * - * If you need set-like behavior, see the library class Set. */ static VALUE @@ -3834,24 +3323,17 @@ rb_ary_diff(VALUE ary1, VALUE ary2) * call-seq: * ary & other_ary -> new_ary * - * Set Intersection --- Returns a new array containing elements common to the - * two arrays, excluding any duplicates. The order is preserved from the - * original array. - * - * It compares elements using their #hash and #eql? methods for efficiency. + * Set Intersection---Returns a new array + * containing elements common to the two arrays, with no duplicates. * - * [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ] - * [ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ] #=> [ 'a', 'b' ] - * - * See also Array#uniq. + * [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ] */ static VALUE rb_ary_and(VALUE ary1, VALUE ary2) { - VALUE hash, ary3, v; - st_data_t vv; + VALUE hash, ary3, v, vv; long i; ary2 = to_ary(ary2); @@ -3863,8 +3345,8 @@ rb_ary_and(VALUE ary1, VALUE ary2) return ary3; for (i=0; i<RARRAY_LEN(ary1); i++) { - vv = (st_data_t)(v = rb_ary_elt(ary1, i)); - if (st_delete(RHASH_TBL(hash), &vv, 0)) { + v = vv = rb_ary_elt(ary1, i); + if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } @@ -3877,21 +3359,18 @@ rb_ary_and(VALUE ary1, VALUE ary2) * call-seq: * ary | other_ary -> new_ary * - * Set Union --- Returns a new array by joining +ary+ with +other_ary+, - * excluding any duplicates and preserving the order from the original array. - * - * It compares elements using their #hash and #eql? methods for efficiency. + * Set Union---Returns a new array by joining this array with + * <i>other_ary</i>, removing duplicates. * - * [ "a", "b", "c" ] | [ "c", "d", "a" ] #=> [ "a", "b", "c", "d" ] - * - * See also Array#uniq. + * [ "a", "b", "c" ] | [ "c", "d", "a" ] + * #=> [ "a", "b", "c", "d" ] */ static VALUE rb_ary_or(VALUE ary1, VALUE ary2) { - VALUE hash, ary3, v; - st_data_t vv; + VALUE hash, ary3; + VALUE v, vv; long i; ary2 = to_ary(ary2); @@ -3899,14 +3378,14 @@ rb_ary_or(VALUE ary1, VALUE ary2) hash = ary_add_hash(ary_make_hash(ary1), ary2); for (i=0; i<RARRAY_LEN(ary1); i++) { - vv = (st_data_t)(v = rb_ary_elt(ary1, i)); - if (st_delete(RHASH_TBL(hash), &vv, 0)) { + v = vv = rb_ary_elt(ary1, i); + if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } for (i=0; i<RARRAY_LEN(ary2); i++) { - vv = (st_data_t)(v = rb_ary_elt(ary2, i)); - if (st_delete(RHASH_TBL(hash), &vv, 0)) { + v = vv = rb_ary_elt(ary2, i); + if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) { rb_ary_push(ary3, v); } } @@ -3923,27 +3402,18 @@ push_value(st_data_t key, st_data_t val, st_data_t ary) /* * call-seq: - * ary.uniq! -> ary or nil - * ary.uniq! { |item| ... } -> ary or nil + * ary.uniq! -> ary or nil * * Removes duplicate elements from +self+. - * - * If a block is given, it will use the return value of the block for - * comparison. - * - * It compares values using their #hash and #eql? methods for efficiency. - * - * Returns +nil+ if no changes are made (that is, no duplicates are found). + * Returns <code>nil</code> if no changes are made (that is, no + * duplicates are found). * * a = [ "a", "a", "b", "b", "c" ] - * a.uniq! # => ["a", "b", "c"] - * + * a.uniq! #=> ["a", "b", "c"] * b = [ "a", "b", "c" ] - * b.uniq! # => nil - * - * c = [["student","sam"], ["student","george"], ["teacher","matz"]] - * c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] - * + * b.uniq! #=> nil + * c = [ "a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl" ] + * c.uniq! {|s| s[/^\w+/]} #=> [ "a:def", "b:abc", "c:jkl" ] */ static VALUE @@ -3988,21 +3458,14 @@ rb_ary_uniq_bang(VALUE ary) /* * call-seq: - * ary.uniq -> new_ary - * ary.uniq { |item| ... } -> new_ary + * ary.uniq -> new_ary * * Returns a new array by removing duplicate values in +self+. * - * If a block is given, it will use the return value of the block for comparison. - * - * It compares values using their #hash and #eql? methods for efficiency. - * * a = [ "a", "a", "b", "b", "c" ] - * a.uniq # => ["a", "b", "c"] - * - * b = [["student","sam"], ["student","george"], ["teacher","matz"]] - * b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] - * + * a.uniq #=> ["a", "b", "c"] + * c = [ "a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl" ] + * c.uniq {|s| s[/^\w+/]} #=> [ "a:def", "b:abc", "c:jkl" ] */ static VALUE @@ -4038,8 +3501,8 @@ rb_ary_uniq(VALUE ary) * ary.compact! -> ary or nil * * Removes +nil+ elements from the array. - * - * Returns +nil+ if no changes were made, otherwise returns the array. + * Returns +nil+ if no changes were made, otherwise returns + * </i>ary</i>. * * [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ] * [ "a", "b", "c" ].compact! #=> nil @@ -4091,22 +3554,18 @@ rb_ary_compact(VALUE ary) /* * call-seq: - * ary.count -> int - * ary.count(obj) -> int + * ary.count -> int + * ary.count(obj) -> int * ary.count { |item| block } -> int * - * Returns the number of elements. - * - * If an argument is given, counts the number of elements which equal +obj+ - * using <code>===</code>. - * - * If a block is given, counts the number of elements for which the block - * returns a true value. + * Returns the number of elements. If an argument is given, counts + * the number of elements which equals to <i>obj</i>. If a block is + * given, counts the number of elements yielding a true value. * * ary = [1, 2, 4, 2] - * ary.count #=> 4 - * ary.count(2) #=> 2 - * ary.count { |x| x%2 == 0 } #=> 3 + * ary.count #=> 4 + * ary.count(2) #=> 2 + * ary.count{|x|x%2==0} #=> 3 * */ @@ -4197,14 +3656,12 @@ flatten(VALUE ary, int level, int *modified) /* * call-seq: * ary.flatten! -> ary or nil - * ary.flatten!(level) -> ary or nil + * ary.flatten!(level) -> array or nil * * Flattens +self+ in place. - * - * Returns +nil+ if no modifications were made (i.e., the array contains no - * subarrays.) - * - * The optional +level+ argument determines the level of recursion to flatten. + * Returns <code>nil</code> if no modifications were made (i.e., + * <i>ary</i> contains no subarrays.) If the optional <i>level</i> + * argument determines the level of recursion to flatten. * * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten! #=> [1, 2, 3, 4, 5] @@ -4242,14 +3699,10 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary) * ary.flatten -> new_ary * ary.flatten(level) -> new_ary * - * Returns a new array that is a one-dimensional flattening of +self+ - * (recursively). - * - * That is, for every element that is an array, extract its elements into - * the new array. - * - * The optional +level+ argument determines the level of recursion to - * flatten. + * Returns a new array that is a one-dimensional flattening of this + * array (recursively). That is, for every element that is an array, + * extract its elements into the new array. If the optional + * <i>level</i> argument determines the level of recursion to flatten. * * s = [ 1, 2, 3 ] #=> [1, 2, 3] * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] @@ -4275,44 +3728,25 @@ rb_ary_flatten(int argc, VALUE *argv, VALUE ary) return result; } -#define OPTHASH_GIVEN_P(opts) \ - (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1)) -static VALUE sym_random; - -#define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1) - /* * call-seq: - * ary.shuffle! -> ary - * ary.shuffle!(random: rng) -> ary + * ary.shuffle! -> ary * * Shuffles elements in +self+ in place. - * - * The optional +rng+ argument will be used as the random number generator. */ + static VALUE -rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary) +rb_ary_shuffle_bang(VALUE ary) { - VALUE *ptr, opts, *snap_ptr, randgen = rb_cRandom; - long i, snap_len; + VALUE *ptr; + long i = RARRAY_LEN(ary); - if (OPTHASH_GIVEN_P(opts)) { - randgen = rb_hash_lookup2(opts, sym_random, randgen); - } - rb_check_arity(argc, 0, 0); rb_ary_modify(ary); - i = RARRAY_LEN(ary); ptr = RARRAY_PTR(ary); - snap_len = i; - snap_ptr = ptr; while (i) { - long j = RAND_UPTO(i); - VALUE tmp; - if (snap_len != RARRAY_LEN(ary) || snap_ptr != RARRAY_PTR(ary)) { - rb_raise(rb_eRuntimeError, "modified during shuffle"); - } - tmp = ptr[--i]; + long j = (long)(rb_genrand_real()*i); + VALUE tmp = ptr[--i]; ptr[i] = ptr[j]; ptr[j] = tmp; } @@ -4322,49 +3756,34 @@ rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary) /* * call-seq: - * ary.shuffle -> new_ary - * ary.shuffle(random: rng) -> new_ary + * ary.shuffle -> new_ary * - * Returns a new array with elements of +self+ shuffled. + * Returns a new array with elements of this array shuffled. * * a = [ 1, 2, 3 ] #=> [1, 2, 3] * a.shuffle #=> [2, 3, 1] - * - * The optional +rng+ argument will be used as the random number generator. - * - * a.shuffle(random: Random.new(1)) #=> [1, 3, 2] */ static VALUE -rb_ary_shuffle(int argc, VALUE *argv, VALUE ary) +rb_ary_shuffle(VALUE ary) { ary = rb_ary_dup(ary); - rb_ary_shuffle_bang(argc, argv, ary); + rb_ary_shuffle_bang(ary); return ary; } /* * call-seq: - * ary.sample -> obj - * ary.sample(random: rng) -> obj - * ary.sample(n) -> new_ary - * ary.sample(n, random: rng) -> new_ary - * - * Choose a random element or +n+ random elements from the array. - * - * The elements are chosen by using random and unique indices into the array - * in order to ensure that an element doesn't repeat itself unless the array - * already contained duplicate elements. - * - * If the array is empty the first form returns +nil+ and the second form - * returns an empty array. + * ary.sample -> obj + * ary.sample(n) -> new_ary * - * The optional +rng+ argument will be used as the random number generator. + * Choose a random element or +n+ random elements from the array. The elements + * are chosen by using random and unique indices into the array in order to + * ensure that an element doesn't repeat itself unless the array already + * contained duplicate elements. If the array is empty the first form returns + * <code>nil</code> and the second form returns an empty array. * - * a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] - * a.sample #=> 7 - * a.sample(4) #=> [6, 4, 2, 5] */ @@ -4372,64 +3791,33 @@ static VALUE rb_ary_sample(int argc, VALUE *argv, VALUE ary) { VALUE nv, result, *ptr; - VALUE opts, randgen = rb_cRandom; long n, len, i, j, k, idx[10]; - long rnds[numberof(idx)]; - if (OPTHASH_GIVEN_P(opts)) { - randgen = rb_hash_lookup2(opts, sym_random, randgen); - } - ptr = RARRAY_PTR(ary); len = RARRAY_LEN(ary); if (argc == 0) { if (len == 0) return Qnil; - if (len == 1) { - i = 0; - } - else { - i = RAND_UPTO(len); - if ((len = RARRAY_LEN(ary)) <= i) return Qnil; - ptr = RARRAY_PTR(ary); - } - return ptr[i]; + i = len == 1 ? 0 : (long)(rb_genrand_real()*len); + return RARRAY_PTR(ary)[i]; } rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n < 0) rb_raise(rb_eArgError, "negative sample number"); - if (n > len) n = len; - if (n <= numberof(idx)) { - for (i = 0; i < n; ++i) { - rnds[i] = RAND_UPTO(len - i); - } - } - k = len; - len = RARRAY_LEN(ary); ptr = RARRAY_PTR(ary); - if (len < k) { - if (n <= numberof(idx)) { - for (i = 0; i < n; ++i) { - if (rnds[i] >= len) { - return rb_ary_new2(0); - } - } - } - } + len = RARRAY_LEN(ary); if (n > len) n = len; switch (n) { - case 0: - return rb_ary_new2(0); + case 0: return rb_ary_new2(0); case 1: - i = rnds[0]; - return rb_ary_new4(1, &ptr[i]); + return rb_ary_new4(1, &ptr[(long)(rb_genrand_real()*len)]); case 2: - i = rnds[0]; - j = rnds[1]; + i = (long)(rb_genrand_real()*len); + j = (long)(rb_genrand_real()*(len-1)); if (j >= i) j++; return rb_ary_new3(2, ptr[i], ptr[j]); case 3: - i = rnds[0]; - j = rnds[1]; - k = rnds[2]; + i = (long)(rb_genrand_real()*len); + j = (long)(rb_genrand_real()*(len-1)); + k = (long)(rb_genrand_real()*(len-2)); { long l = j, g = i; if (j >= i) l = i, g = ++j; @@ -4437,12 +3825,12 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) } return rb_ary_new3(3, ptr[i], ptr[j], ptr[k]); } - if (n <= numberof(idx)) { + if ((size_t)n < sizeof(idx)/sizeof(idx[0])) { VALUE *ptr_result; - long sorted[numberof(idx)]; - sorted[0] = idx[0] = rnds[0]; + long sorted[sizeof(idx)/sizeof(idx[0])]; + sorted[0] = idx[0] = (long)(rb_genrand_real()*len); for (i=1; i<n; i++) { - k = rnds[i]; + k = (long)(rb_genrand_real()*--len); for (j = 0; j < i; ++j) { if (k < sorted[j]) break; ++k; @@ -4459,54 +3847,37 @@ rb_ary_sample(int argc, VALUE *argv, VALUE ary) else { VALUE *ptr_result; result = rb_ary_new4(len, ptr); - RBASIC(result)->klass = 0; ptr_result = RARRAY_PTR(result); RB_GC_GUARD(ary); for (i=0; i<n; i++) { - j = RAND_UPTO(len-i) + i; + j = (long)(rb_genrand_real()*(len-i)) + i; nv = ptr_result[j]; ptr_result[j] = ptr_result[i]; ptr_result[i] = nv; } - RBASIC(result)->klass = rb_cArray; } ARY_SET_LEN(result, n); return result; } -static VALUE -rb_ary_cycle_size(VALUE self, VALUE args) -{ - long mul; - VALUE n = Qnil; - if (args && (RARRAY_LEN(args) > 0)) { - n = RARRAY_PTR(args)[0]; - } - if (RARRAY_LEN(self) == 0) return INT2FIX(0); - if (n == Qnil) return DBL2NUM(INFINITY); - mul = NUM2LONG(n); - if (mul <= 0) return INT2FIX(0); - return rb_funcall(rb_ary_length(self), '*', 1, LONG2FIX(mul)); -} /* * call-seq: - * ary.cycle(n=nil) { |obj| block } -> nil - * ary.cycle(n=nil) -> Enumerator + * ary.cycle(n=nil) {|obj| block } -> nil + * ary.cycle(n=nil) -> an_enumerator * - * Calls the given block for each element +n+ times or forever if +nil+ is - * given. + * Calls <i>block</i> for each element repeatedly _n_ times or + * forever if none or +nil+ is given. If a non-positive number is + * given or the array is empty, does nothing. Returns +nil+ if the + * loop has finished without getting interrupted. * - * Does nothing if a non-positive number is given or the array is empty. + * If no block is given, an enumerator is returned instead. * - * Returns +nil+ if the loop has finished without getting interrupted. - * - * If no block is given, an Enumerator is returned instead. * * a = ["a", "b", "c"] - * a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever. - * a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c. + * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. + * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c. * */ @@ -4518,7 +3889,7 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) rb_scan_args(argc, argv, "01", &nv); - RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size); + RETURN_ENUMERATOR(ary, argc, argv); if (NIL_P(nv)) { n = -1; } @@ -4541,9 +3912,7 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) #define tmpary_discard(a) (ary_discard(a), RBASIC(a)->klass = rb_cArray) /* - * Recursively compute permutations of +r+ elements of the set - * <code>[0..n-1]</code>. - * + * Recursively compute permutations of r elements of the set [0..n-1]. * When we have a complete permutation of array indexes, copy the values * at those indexes into a new array and yield that array. * @@ -4587,66 +3956,29 @@ permute0(long n, long r, long *p, long index, char *used, VALUE values) } /* - * Returns the product of from, from-1, ..., from - how_many + 1. - * http://en.wikipedia.org/wiki/Pochhammer_symbol - */ -static VALUE -descending_factorial(long from, long how_many) -{ - VALUE cnt = LONG2FIX(how_many >= 0); - while (how_many-- > 0) { - cnt = rb_funcall(cnt, '*', 1, LONG2FIX(from--)); - } - return cnt; -} - -static VALUE -binomial_coefficient(long comb, long size) -{ - if (comb > size-comb) { - comb = size-comb; - } - if (comb < 0) { - return LONG2FIX(0); - } - return rb_funcall(descending_factorial(size, comb), id_div, 1, descending_factorial(comb, comb)); -} - -static VALUE -rb_ary_permutation_size(VALUE ary, VALUE args) -{ - long n = RARRAY_LEN(ary); - long k = (args && (RARRAY_LEN(args) > 0)) ? NUM2LONG(RARRAY_PTR(args)[0]) : n; - - return descending_factorial(n, k); -} - -/* * call-seq: * ary.permutation { |p| block } -> ary - * ary.permutation -> Enumerator + * ary.permutation -> an_enumerator * ary.permutation(n) { |p| block } -> ary - * ary.permutation(n) -> Enumerator - * - * When invoked with a block, yield all permutations of length +n+ of the - * elements of the array, then return the array itself. - * - * If +n+ is not specified, yield all permutations of all elements. + * ary.permutation(n) -> an_enumerator * - * The implementation makes no guarantees about the order in which the - * permutations are yielded. + * When invoked with a block, yield all permutations of length <i>n</i> + * of the elements of <i>ary</i>, then return the array itself. + * If <i>n</i> is not specified, yield all permutations of all elements. + * The implementation makes no guarantees about the order in which + * the permutations are yielded. * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * Examples: * - * a = [1, 2, 3] - * a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] - * a.permutation(1).to_a #=> [[1],[2],[3]] - * a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] - * a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] - * a.permutation(0).to_a #=> [[]] # one permutation of length 0 - * a.permutation(4).to_a #=> [] # no permutations of length 4 + * a = [1, 2, 3] + * a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] + * a.permutation(1).to_a #=> [[1],[2],[3]] + * a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] + * a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] + * a.permutation(0).to_a #=> [[]] # one permutation of length 0 + * a.permutation(4).to_a #=> [] # no permutations of length 4 */ static VALUE @@ -4656,7 +3988,7 @@ rb_ary_permutation(int argc, VALUE *argv, VALUE ary) long r, n, i; n = RARRAY_LEN(ary); /* Array length */ - RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* Return enumerator if no block */ + RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */ rb_scan_args(argc, argv, "01", &num); r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */ @@ -4689,27 +4021,17 @@ rb_ary_permutation(int argc, VALUE *argv, VALUE ary) return ary; } -static VALUE -rb_ary_combination_size(VALUE ary, VALUE args) -{ - long n = RARRAY_LEN(ary); - long k = NUM2LONG(RARRAY_PTR(args)[0]); - - return binomial_coefficient(k, n); -} - /* * call-seq: * ary.combination(n) { |c| block } -> ary - * ary.combination(n) -> Enumerator - * - * When invoked with a block, yields all combinations of length +n+ of elements - * from the array and then returns the array itself. + * ary.combination(n) -> an_enumerator * - * The implementation makes no guarantees about the order in which the - * combinations are yielded. + * When invoked with a block, yields all combinations of length <i>n</i> + * of elements from <i>ary</i> and then returns <i>ary</i> itself. + * The implementation makes no guarantees about the order in which + * the combinations are yielded. * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * Examples: * @@ -4729,7 +4051,7 @@ rb_ary_combination(VALUE ary, VALUE num) long n, i, len; n = NUM2LONG(num); - RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size); + RETURN_ENUMERATOR(ary, 1, &num); len = RARRAY_LEN(ary); if (n < 0 || len < n) { /* yield nothing */ @@ -4773,9 +4095,8 @@ rb_ary_combination(VALUE ary, VALUE num) } /* - * Recursively compute repeated permutations of +r+ elements of the set - * <code>[0..n-1]</code>. - * + * Recursively compute repeated permutations of r elements of the set + * [0..n-1]. * When we have a complete repeated permutation of array indexes, copy the * values at those indexes into a new array and yield that array. * @@ -4812,31 +4133,17 @@ rpermute0(long n, long r, long *p, long index, VALUE values) } } -static VALUE -rb_ary_repeated_permutation_size(VALUE ary, VALUE args) -{ - long n = RARRAY_LEN(ary); - long k = NUM2LONG(RARRAY_PTR(args)[0]); - - if (k < 0) { - return LONG2FIX(0); - } - - return rb_funcall(LONG2NUM(n), id_power, 1, LONG2NUM(k)); -} - /* * call-seq: * ary.repeated_permutation(n) { |p| block } -> ary - * ary.repeated_permutation(n) -> Enumerator + * ary.repeated_permutation(n) -> an_enumerator * - * When invoked with a block, yield all repeated permutations of length +n+ of - * the elements of the array, then return the array itself. + * When invoked with a block, yield all repeated permutations of length + * <i>n</i> of the elements of <i>ary</i>, then return the array itself. + * The implementation makes no guarantees about the order in which + * the repeated permutations are yielded. * - * The implementation makes no guarantees about the order in which the repeated - * permutations are yielded. - * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * Examples: * @@ -4854,7 +4161,7 @@ rb_ary_repeated_permutation(VALUE ary, VALUE num) long r, n, i; n = RARRAY_LEN(ary); /* Array length */ - RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */ + RETURN_ENUMERATOR(ary, 1, &num); /* Return enumerator if no block */ r = NUM2LONG(num); /* Permutation size from argument */ if (r < 0) { @@ -4905,41 +4212,30 @@ rcombinate0(long n, long r, long *p, long index, long rest, VALUE values) } } -static VALUE -rb_ary_repeated_combination_size(VALUE ary, VALUE args) -{ - long n = RARRAY_LEN(ary); - long k = NUM2LONG(RARRAY_PTR(args)[0]); - if (k == 0) { - return LONG2FIX(1); - } - return binomial_coefficient(k, n + k - 1); -} - /* * call-seq: * ary.repeated_combination(n) { |c| block } -> ary - * ary.repeated_combination(n) -> Enumerator - * - * When invoked with a block, yields all repeated combinations of length +n+ of - * elements from the array and then returns the array itself. + * ary.repeated_combination(n) -> an_enumerator * - * The implementation makes no guarantees about the order in which the repeated - * combinations are yielded. + * When invoked with a block, yields all repeated combinations of + * length <i>n</i> of elements from <i>ary</i> and then returns + * <i>ary</i> itself. + * The implementation makes no guarantees about the order in which + * the repeated combinations are yielded. * - * If no block is given, an Enumerator is returned instead. + * If no block is given, an enumerator is returned instead. * * Examples: * - * a = [1, 2, 3] - * a.repeated_combination(1).to_a #=> [[1], [2], [3]] - * a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] - * a.repeated_combination(3).to_a #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], - * # [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]] - * a.repeated_combination(4).to_a #=> [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3], - * # [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3], - * # [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]] - * a.repeated_combination(0).to_a #=> [[]] # one combination of length 0 + * a = [1, 2, 3] + * a.repeated_combination(1).to_a #=> [[1], [2], [3]] + * a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] + * a.repeated_combination(3).to_a #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], + * # [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]] + * a.repeated_combination(4).to_a #=> [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3], + * # [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3], + * # [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]] + * a.repeated_combination(0).to_a #=> [[]] # one combination of length 0 * */ @@ -4949,7 +4245,7 @@ rb_ary_repeated_combination(VALUE ary, VALUE num) long n, i, len; n = NUM2LONG(num); /* Combination size from argument */ - RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */ + RETURN_ENUMERATOR(ary, 1, &num); /* Return enumerator if no block */ len = RARRAY_LEN(ary); if (n < 0) { /* yield nothing */ @@ -4983,13 +4279,12 @@ rb_ary_repeated_combination(VALUE ary, VALUE num) * ary.product(other_ary, ...) -> new_ary * ary.product(other_ary, ...) { |p| block } -> ary * - * Returns an array of all combinations of elements from all arrays. + * Returns an array of all combinations of elements from all arrays, + * The length of the returned array is the product of the length + * of +self+ and the argument arrays. + * If given a block, <i>product</i> will yield all combinations + * and return +self+ instead. * - * The length of the returned array is the product of the length of +self+ and - * the argument arrays. - * - * If given a block, #product will yield all combinations and return +self+ - * instead. * * [1,2,3].product([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]] * [1,2].product([1,2]) #=> [[1,1],[1,2],[2,1],[2,2]] @@ -5034,14 +4329,15 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) else { /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { - long k = RARRAY_LEN(arrays[i]); + long k = RARRAY_LEN(arrays[i]), l = resultlen; if (k == 0) { result = rb_ary_new2(0); goto done; } - if (MUL_OVERFLOW_LONG_P(resultlen, k)) - rb_raise(rb_eRangeError, "too big to product"); resultlen *= k; + if (resultlen < k || resultlen < l || resultlen / k != l) { + rb_raise(rb_eRangeError, "too big to product"); + } } result = rb_ary_new2(resultlen); } @@ -5054,7 +4350,7 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) } /* put it on the result array */ - if (NIL_P(result)) { + if(NIL_P(result)) { FL_SET(t0, FL_USER5); rb_yield(subarray); if (! FL_TEST(t0, FL_USER5)) { @@ -5076,7 +4372,7 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) counters[m]++; while (counters[m] == RARRAY_LEN(arrays[m])) { counters[m] = 0; - /* If the first counter overflows, we are done */ + /* If the first counter overlows, we are done */ if (--m < 0) goto done; counters[m]++; } @@ -5092,11 +4388,7 @@ done: * call-seq: * ary.take(n) -> new_ary * - * Returns first +n+ elements from the array. - * - * If a negative number is given, raises an ArgumentError. - * - * See also Array#drop + * Returns first n elements from <i>ary</i>. * * a = [1, 2, 3, 4, 5, 0] * a.take(3) #=> [1, 2, 3] @@ -5115,18 +4407,16 @@ rb_ary_take(VALUE obj, VALUE n) /* * call-seq: - * ary.take_while { |arr| block } -> new_ary - * ary.take_while -> Enumerator - * - * Passes elements to the block until the block returns +nil+ or +false+, then - * stops iterating and returns an array of all prior elements. + * ary.take_while {|arr| block } -> new_ary + * ary.take_while -> an_enumerator * - * If no block is given, an Enumerator is returned instead. + * Passes elements to the block until the block returns +nil+ or +false+, + * then stops iterating and returns an array of all prior elements. * - * See also Array#drop_while + * If no block is given, an enumerator is returned instead. * * a = [1, 2, 3, 4, 5, 0] - * a.take_while { |i| i < 3 } #=> [1, 2] + * a.take_while {|i| i < 3 } #=> [1, 2] * */ @@ -5146,12 +4436,8 @@ rb_ary_take_while(VALUE ary) * call-seq: * ary.drop(n) -> new_ary * - * Drops first +n+ elements from +ary+ and returns the rest of the elements in - * an array. - * - * If a negative number is given, raises an ArgumentError. - * - * See also Array#take + * Drops first n elements from <i>ary</i>, and returns rest elements + * in an array. * * a = [1, 2, 3, 4, 5, 0] * a.drop(3) #=> [4, 5, 0] @@ -5174,16 +4460,14 @@ rb_ary_drop(VALUE ary, VALUE n) /* * call-seq: - * ary.drop_while { |arr| block } -> new_ary - * ary.drop_while -> Enumerator + * ary.drop_while {|arr| block } -> new_ary + * ary.drop_while -> an_enumerator * - * Drops elements up to, but not including, the first element for which the - * block returns +nil+ or +false+ and returns an array containing the - * remaining elements. + * Drops elements up to, but not including, the first element for + * which the block returns +nil+ or +false+ and returns an array + * containing the remaining elements. * - * If no block is given, an Enumerator is returned instead. - * - * See also Array#take_while + * If no block is given, an enumerator is returned instead. * * a = [1, 2, 3, 4, 5, 0] * a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0] @@ -5202,238 +4486,13 @@ rb_ary_drop_while(VALUE ary) return rb_ary_drop(ary, LONG2FIX(i)); } -/* - * Arrays are ordered, integer-indexed collections of any object. - * - * Array indexing starts at 0, as in C or Java. A negative index is assumed - * to be relative to the end of the array---that is, an index of -1 indicates - * the last element of the array, -2 is the next to last element in the - * array, and so on. - * - * == Creating Arrays - * - * A new array can be created by using the literal constructor - * <code>[]</code>. Arrays can contain different types of objects. For - * example, the array below contains an Integer, a String and a Float: - * - * ary = [1, "two", 3.0] #=> [1, "two", 3.0] - * - * An array can also be created by explicitly calling Array.new with zero, one - * (the initial size of the Array) or two arguments (the initial size and a - * default object). - * - * ary = Array.new #=> [] - * Array.new(3) #=> [nil, nil, nil] - * Array.new(3, true) #=> [true, true, true] - * - * Note that the second argument populates the array with references to the - * same object. Therefore, it is only recommended in cases when you need to - * instantiate arrays with natively immutable objects such as Symbols, - * numbers, true or false. - * - * To create an array with separate objects a block can be passed instead. - * This method is safe to use with mutable objects such as hashes, strings or - * other arrays: - * - * Array.new(4) { Hash.new } #=> [{}, {}, {}, {}] - * - * This is also a quick way to build up multi-dimensional arrays: - * - * empty_table = Array.new(3) { Array.new(3) } - * #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]] - * - * An array can also be created by using the Array() method, provided by - * Kernel, which tries to call #to_ary, then #to_a on its argument. - * - * Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]] - * - * == 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 - * manipulating arrays. - * - * Some of the more common ones are illustrated below. - * - * == Accessing Elements - * - * Elements in an array can be retrieved using the Array#[] method. It can - * take a single integer argument (a numeric index), a pair of arguments - * (start and length) or a range. - * - * arr = [1, 2, 3, 4, 5, 6] - * arr[2] #=> 3 - * arr[100] #=> nil - * arr[-3] #=> 4 - * arr[2, 3] #=> [3, 4, 5] - * arr[1..4] #=> [2, 3, 4, 5] - * - * Another way to access a particular array element is by using the #at method - * - * arr.at(0) #=> 1 - * - * The #slice method works in an identical manner to Array#[]. - * - * To raise an error for indices outside of the array bounds or else to - * provide a default value when that happens, you can use #fetch. - * - * arr = ['a', 'b', 'c', 'd', 'e', 'f'] - * arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6 - * arr.fetch(100, "oops") #=> "oops" - * - * The special methods #first and #last will return the first and last - * elements of an array, respectively. - * - * arr.first #=> 1 - * arr.last #=> 6 - * - * To return the first +n+ elements of an array, use #take - * - * arr.take(3) #=> [1, 2, 3] - * - * #drop does the opposite of #take, by returning the elements after +n+ - * elements have been dropped: - * - * arr.drop(3) #=> [4, 5, 6] - * - * == Obtaining Information about an Array - * - * Arrays keep track of their 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'] - * browsers.length #=> 5 - * browsers.count #=> 5 - * - * To check whether an array contains any elements at all - * - * browsers.empty? #=> false - * - * To check whether a particular item is included in the array - * - * browsers.include?('Konqueror') #=> false - * - * == Adding Items to Arrays - * - * Items can be added to the end of an array by using either #push or #<< - * - * arr = [1, 2, 3, 4] - * arr.push(5) #=> [1, 2, 3, 4, 5] - * arr << 6 #=> [1, 2, 3, 4, 5, 6] - * - * #unshift will add a new item to the beginning of an array. - * - * arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6] - * - * With #insert you can add a new element to an array at any position. - * - * arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6] - * - * Using the #insert method, you can also insert multiple values at once: - * - * arr.insert(3, 'orange', 'pear', 'grapefruit') - * #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6] - * - * == Removing Items from an Array - * - * The method #pop removes the last element in an array and returns it: - * - * arr = [1, 2, 3, 4, 5, 6] - * arr.pop #=> 6 - * arr #=> [1, 2, 3, 4, 5] - * - * To retrieve and at the same time remove the first item, use #shift: - * - * arr.shift #=> 1 - * arr #=> [2, 3, 4, 5] - * - * To delete an element at a particular index: - * - * arr.delete_at(2) #=> 4 - * arr #=> [2, 3, 5] - * - * To delete a particular element anywhere in an array, use #delete: - * - * arr = [1, 2, 2, 3] - * arr.delete(2) #=> [1, 3] - * - * A useful method if you need to remove +nil+ values from an array is - * #compact: - * - * arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] - * arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] - * arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] - * arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] - * arr #=> ['foo', 0, 'bar', 7, 'baz'] - * - * Another common need is to remove duplicate elements from an array. - * - * It has the non-destructive #uniq, and destructive method #uniq! - * - * 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 - * - * Like all classes that include the Enumerable module, 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 - * the supplied block in sequence. - * - * Note that this operation leaves the array unchanged. - * - * arr = [1, 2, 3, 4, 5] - * arr.each { |a| print a -= 10, " " } - * # prints: -9 -8 -7 -6 -5 - * #=> [1, 2, 3, 4, 5] - * - * Another sometimes useful iterator is #reverse_each which will iterate over - * the elements in the array in reverse order. - * - * words = %w[rats live on no evil star] - * str = "" - * words.reverse_each { |word| str += "#{word.reverse} " } - * str #=> "rats live on no evil star " - * - * The #map method can be used to create a new array based on the original - * array, but with the values modified by the supplied block: - * - * arr.map { |a| 2*a } #=> [2, 4, 6, 8, 10] - * arr #=> [1, 2, 3, 4, 5] - * arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25] - * arr #=> [1, 4, 9, 16, 25] - * - * == 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 - * manner. While the destructive operations will modify the array they were - * called on, the non-destructive methods usually return a new array with the - * selected elements, but leave the original array unchanged. - * - * === Non-destructive Selection - * - * arr = [1, 2, 3, 4, 5, 6] - * arr.select { |a| a > 3 } #=> [4, 5, 6] - * arr.reject { |a| a < 3 } #=> [3, 4, 5, 6] - * arr.drop_while { |a| a < 4 } #=> [4, 5, 6] - * arr #=> [1, 2, 3, 4, 5, 6] - * - * === Destructive Selection - * - * #select! and #reject! are the corresponding destructive methods to #select - * and #reject - * - * Similar to #select vs. #reject, #delete_if and #keep_if have the exact - * opposite result when supplied with the same block: - * - * arr.delete_if { |a| a < 4 } #=> [4, 5, 6] - * arr #=> [4, 5, 6] - * - * arr = [1, 2, 3, 4, 5, 6] - * arr.keep_if { |a| a < 4 } #=> [1, 2, 3] - * arr #=> [1, 2, 3] - * + + +/* Arrays are ordered, integer-indexed collections of any object. + * Array indexing starts at 0, as in C or Java. A negative index is + * assumed to be relative to the end of the array---that is, an index of -1 + * indicates the last element of the array, -2 is the next to last + * element in the array, and so on. */ void @@ -5445,7 +4504,7 @@ Init_Array(void) rb_cArray = rb_define_class("Array", rb_cObject); rb_include_module(rb_cArray, rb_mEnumerable); - rb_define_alloc_func(rb_cArray, empty_ary_alloc); + rb_define_alloc_func(rb_cArray, ary_alloc); rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1); rb_define_singleton_method(rb_cArray, "try_convert", rb_ary_s_try_convert, 1); rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1); @@ -5532,8 +4591,8 @@ Init_Array(void) rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1); rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1); rb_define_method(rb_cArray, "count", rb_ary_count, -1); - rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, -1); - rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, -1); + rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0); + rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0); rb_define_method(rb_cArray, "sample", rb_ary_sample, -1); rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1); rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1); @@ -5546,10 +4605,6 @@ Init_Array(void) rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0); rb_define_method(rb_cArray, "drop", rb_ary_drop, 1); rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0); - rb_define_method(rb_cArray, "bsearch", rb_ary_bsearch, 0); id_cmp = rb_intern("<=>"); - sym_random = ID2SYM(rb_intern("random")); - id_div = rb_intern("div"); - id_power = rb_intern("**"); } |
