Ruby  2.0.0p594(2014-10-27revision48167)
array.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   array.c -
00004 
00005   $Author: usa $
00006   created at: Fri Aug  6 09:46:12 JST 1993
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "ruby/util.h"
00016 #include "ruby/st.h"
00017 #include "ruby/encoding.h"
00018 #include "internal.h"
00019 #include "probes.h"
00020 #include "id.h"
00021 
00022 #ifndef ARRAY_DEBUG
00023 # define NDEBUG
00024 #endif
00025 #include <assert.h>
00026 
00027 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00028 
00029 VALUE rb_cArray;
00030 
00031 static ID id_cmp, id_div, id_power;
00032 
00033 #define ARY_DEFAULT_SIZE 16
00034 #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE))
00035 
00036 void
00037 rb_mem_clear(register VALUE *mem, register long size)
00038 {
00039     while (size--) {
00040         *mem++ = Qnil;
00041     }
00042 }
00043 
00044 static inline void
00045 memfill(register VALUE *mem, register long size, register VALUE val)
00046 {
00047     while (size--) {
00048         *mem++ = val;
00049     }
00050 }
00051 
00052 # define ARY_SHARED_P(ary) \
00053     (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
00054      FL_TEST((ary),ELTS_SHARED)!=0)
00055 # define ARY_EMBED_P(ary) \
00056     (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
00057      FL_TEST((ary), RARRAY_EMBED_FLAG)!=0)
00058 
00059 #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
00060 #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
00061 #define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
00062 #define ARY_EMBED_LEN(a) \
00063     (assert(ARY_EMBED_P(a)), \
00064      (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
00065          (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
00066 
00067 #define ARY_OWNS_HEAP_P(a) (!FL_TEST((a), ELTS_SHARED|RARRAY_EMBED_FLAG))
00068 #define FL_SET_EMBED(a) do { \
00069     assert(!ARY_SHARED_P(a)); \
00070     FL_SET((a), RARRAY_EMBED_FLAG); \
00071 } while (0)
00072 #define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
00073 #define FL_SET_SHARED(ary) do { \
00074     assert(!ARY_EMBED_P(ary)); \
00075     FL_SET((ary), ELTS_SHARED); \
00076 } while (0)
00077 #define FL_UNSET_SHARED(ary) FL_UNSET((ary), ELTS_SHARED)
00078 
00079 #define ARY_SET_PTR(ary, p) do { \
00080     assert(!ARY_EMBED_P(ary)); \
00081     assert(!OBJ_FROZEN(ary)); \
00082     RARRAY(ary)->as.heap.ptr = (p); \
00083 } while (0)
00084 #define ARY_SET_EMBED_LEN(ary, n) do { \
00085     long tmp_n = (n); \
00086     assert(ARY_EMBED_P(ary)); \
00087     assert(!OBJ_FROZEN(ary)); \
00088     RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
00089     RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
00090 } while (0)
00091 #define ARY_SET_HEAP_LEN(ary, n) do { \
00092     assert(!ARY_EMBED_P(ary)); \
00093     RARRAY(ary)->as.heap.len = (n); \
00094 } while (0)
00095 #define ARY_SET_LEN(ary, n) do { \
00096     if (ARY_EMBED_P(ary)) { \
00097         ARY_SET_EMBED_LEN((ary), (n)); \
00098     } \
00099     else { \
00100         ARY_SET_HEAP_LEN((ary), (n)); \
00101     } \
00102     assert(RARRAY_LEN(ary) == (n)); \
00103 } while (0)
00104 #define ARY_INCREASE_PTR(ary, n) do  { \
00105     assert(!ARY_EMBED_P(ary)); \
00106     assert(!OBJ_FROZEN(ary)); \
00107     RARRAY(ary)->as.heap.ptr += (n); \
00108 } while (0)
00109 #define ARY_INCREASE_LEN(ary, n) do  { \
00110     assert(!OBJ_FROZEN(ary)); \
00111     if (ARY_EMBED_P(ary)) { \
00112         ARY_SET_EMBED_LEN((ary), RARRAY_LEN(ary)+(n)); \
00113     } \
00114     else { \
00115         RARRAY(ary)->as.heap.len += (n); \
00116     } \
00117 } while (0)
00118 
00119 #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \
00120                        ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa)
00121 #define ARY_SET_CAPA(ary, n) do { \
00122     assert(!ARY_EMBED_P(ary)); \
00123     assert(!ARY_SHARED_P(ary)); \
00124     assert(!OBJ_FROZEN(ary)); \
00125     RARRAY(ary)->as.heap.aux.capa = (n); \
00126 } while (0)
00127 
00128 #define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared)
00129 #define ARY_SET_SHARED(ary, value) do { \
00130     assert(!ARY_EMBED_P(ary)); \
00131     assert(ARY_SHARED_P(ary)); \
00132     assert(ARY_SHARED_ROOT_P(value)); \
00133     RARRAY(ary)->as.heap.aux.shared = (value); \
00134 } while (0)
00135 #define RARRAY_SHARED_ROOT_FLAG FL_USER5
00136 #define ARY_SHARED_ROOT_P(ary) (FL_TEST((ary), RARRAY_SHARED_ROOT_FLAG))
00137 #define ARY_SHARED_NUM(ary) \
00138     (assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa)
00139 #define ARY_SET_SHARED_NUM(ary, value) do { \
00140     assert(ARY_SHARED_ROOT_P(ary)); \
00141     RARRAY(ary)->as.heap.aux.capa = (value); \
00142 } while (0)
00143 #define FL_SET_SHARED_ROOT(ary) do { \
00144     assert(!ARY_EMBED_P(ary)); \
00145     FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
00146 } while (0)
00147 
00148 static void
00149 ary_resize_capa(VALUE ary, long capacity)
00150 {
00151     assert(RARRAY_LEN(ary) <= capacity);
00152     assert(!OBJ_FROZEN(ary));
00153     assert(!ARY_SHARED_P(ary));
00154     if (capacity > RARRAY_EMBED_LEN_MAX) {
00155         if (ARY_EMBED_P(ary)) {
00156             long len = ARY_EMBED_LEN(ary);
00157             VALUE *ptr = ALLOC_N(VALUE, (capacity));
00158             MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
00159             FL_UNSET_EMBED(ary);
00160             ARY_SET_PTR(ary, ptr);
00161             ARY_SET_HEAP_LEN(ary, len);
00162         }
00163         else {
00164             REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, (capacity));
00165         }
00166         ARY_SET_CAPA(ary, (capacity));
00167     }
00168     else {
00169         if (!ARY_EMBED_P(ary)) {
00170             long len = RARRAY_LEN(ary);
00171             VALUE *ptr = RARRAY_PTR(ary);
00172             if (len > capacity) len = capacity;
00173             MEMCPY(RARRAY(ary)->as.ary, ptr, VALUE, len);
00174             FL_SET_EMBED(ary);
00175             ARY_SET_LEN(ary, len);
00176             xfree(ptr);
00177         }
00178     }
00179 }
00180 
00181 static void
00182 ary_double_capa(VALUE ary, long min)
00183 {
00184     long new_capa = ARY_CAPA(ary) / 2;
00185 
00186     if (new_capa < ARY_DEFAULT_SIZE) {
00187         new_capa = ARY_DEFAULT_SIZE;
00188     }
00189     if (new_capa >= ARY_MAX_SIZE - min) {
00190         new_capa = (ARY_MAX_SIZE - min) / 2;
00191     }
00192     new_capa += min;
00193     ary_resize_capa(ary, new_capa);
00194 }
00195 
00196 static void
00197 rb_ary_decrement_share(VALUE shared)
00198 {
00199     if (shared) {
00200         long num = ARY_SHARED_NUM(shared) - 1;
00201         if (num == 0) {
00202             rb_ary_free(shared);
00203             rb_gc_force_recycle(shared);
00204         }
00205         else if (num > 0) {
00206             ARY_SET_SHARED_NUM(shared, num);
00207         }
00208     }
00209 }
00210 
00211 static void
00212 rb_ary_unshare(VALUE ary)
00213 {
00214     VALUE shared = RARRAY(ary)->as.heap.aux.shared;
00215     rb_ary_decrement_share(shared);
00216     FL_UNSET_SHARED(ary);
00217 }
00218 
00219 static inline void
00220 rb_ary_unshare_safe(VALUE ary)
00221 {
00222     if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
00223         rb_ary_unshare(ary);
00224     }
00225 }
00226 
00227 static VALUE
00228 rb_ary_increment_share(VALUE shared)
00229 {
00230     long num = ARY_SHARED_NUM(shared);
00231     if (num >= 0) {
00232         ARY_SET_SHARED_NUM(shared, num + 1);
00233     }
00234     return shared;
00235 }
00236 
00237 static void
00238 rb_ary_set_shared(VALUE ary, VALUE shared)
00239 {
00240     rb_ary_increment_share(shared);
00241     FL_SET_SHARED(ary);
00242     ARY_SET_SHARED(ary, shared);
00243 }
00244 
00245 static inline void
00246 rb_ary_modify_check(VALUE ary)
00247 {
00248     rb_check_frozen(ary);
00249     if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4)
00250         rb_raise(rb_eSecurityError, "Insecure: can't modify array");
00251 }
00252 
00253 void
00254 rb_ary_modify(VALUE ary)
00255 {
00256     rb_ary_modify_check(ary);
00257     if (ARY_SHARED_P(ary)) {
00258         long len = RARRAY_LEN(ary);
00259         VALUE shared = ARY_SHARED(ary);
00260         if (len <= RARRAY_EMBED_LEN_MAX) {
00261             VALUE *ptr = ARY_HEAP_PTR(ary);
00262             FL_UNSET_SHARED(ary);
00263             FL_SET_EMBED(ary);
00264             MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len);
00265             rb_ary_decrement_share(shared);
00266             ARY_SET_EMBED_LEN(ary, len);
00267         }
00268         else if (ARY_SHARED_NUM(shared) == 1 && len > (RARRAY_LEN(shared)>>1)) {
00269             long shift = RARRAY_PTR(ary) - RARRAY_PTR(shared);
00270             FL_UNSET_SHARED(ary);
00271             ARY_SET_PTR(ary, RARRAY_PTR(shared));
00272             ARY_SET_CAPA(ary, RARRAY_LEN(shared));
00273             MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+shift, VALUE, len);
00274             FL_SET_EMBED(shared);
00275             rb_ary_decrement_share(shared);
00276         }
00277         else {
00278             VALUE *ptr = ALLOC_N(VALUE, len);
00279             MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len);
00280             rb_ary_unshare(ary);
00281             ARY_SET_CAPA(ary, len);
00282             ARY_SET_PTR(ary, ptr);
00283         }
00284     }
00285 }
00286 
00287 static void
00288 ary_ensure_room_for_push(VALUE ary, long add_len)
00289 {
00290     long new_len = RARRAY_LEN(ary) + add_len;
00291     long capa;
00292 
00293     if (ARY_SHARED_P(ary)) {
00294         if (new_len > RARRAY_EMBED_LEN_MAX) {
00295             VALUE shared = ARY_SHARED(ary);
00296             if (ARY_SHARED_NUM(shared) == 1) {
00297                 if (RARRAY_PTR(ary) - RARRAY_PTR(shared) + new_len <= RARRAY_LEN(shared)) {
00298                     rb_ary_modify_check(ary);
00299                 }
00300                 else {
00301                     /* if array is shared, than it is likely it participate in push/shift pattern */
00302                     rb_ary_modify(ary);
00303                     capa = ARY_CAPA(ary);
00304                     if (new_len > capa - (capa >> 6)) {
00305                         ary_double_capa(ary, new_len);
00306                     }
00307                 }
00308                 return;
00309             }
00310         }
00311     }
00312     rb_ary_modify(ary);
00313     capa = ARY_CAPA(ary);
00314     if (new_len > capa) {
00315         ary_double_capa(ary, new_len);
00316     }
00317 }
00318 
00319 /*
00320  *  call-seq:
00321  *      ary.freeze -> ary
00322  *
00323  *  Calls Object#freeze on +ary+ to prevent any further
00324  *  modification. A RuntimeError will be raised if a modification
00325  *  attempt is made.
00326  *
00327  */
00328 
00329 VALUE
00330 rb_ary_freeze(VALUE ary)
00331 {
00332     return rb_obj_freeze(ary);
00333 }
00334 
00335 /*
00336  *  call-seq:
00337  *     ary.frozen?  -> true or false
00338  *
00339  *  Return +true+ if this array is frozen (or temporarily frozen
00340  *  while being sorted). See also Object#frozen?
00341  */
00342 
00343 static VALUE
00344 rb_ary_frozen_p(VALUE ary)
00345 {
00346     if (OBJ_FROZEN(ary)) return Qtrue;
00347     return Qfalse;
00348 }
00349 
00350 /* This can be used to take a snapshot of an array (with
00351    e.g. rb_ary_replace) and check later whether the array has been
00352    modified from the snapshot.  The snapshot is cheap, though if
00353    something does modify the array it will pay the cost of copying
00354    it.  If Array#pop or Array#shift has been called, the array will
00355    be still shared with the snapshot, but the array length will
00356    differ. */
00357 VALUE
00358 rb_ary_shared_with_p(VALUE ary1, VALUE ary2)
00359 {
00360     if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) &&
00361         !ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) &&
00362         RARRAY(ary1)->as.heap.aux.shared == RARRAY(ary2)->as.heap.aux.shared &&
00363         RARRAY(ary1)->as.heap.len == RARRAY(ary2)->as.heap.len) {
00364         return Qtrue;
00365     }
00366     return Qfalse;
00367 }
00368 
00369 static VALUE
00370 ary_alloc(VALUE klass)
00371 {
00372     NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY);
00373     FL_SET_EMBED((VALUE)ary);
00374     ARY_SET_EMBED_LEN((VALUE)ary, 0);
00375 
00376     return (VALUE)ary;
00377 }
00378 
00379 static VALUE
00380 empty_ary_alloc(VALUE klass)
00381 {
00382     if (RUBY_DTRACE_ARRAY_CREATE_ENABLED()) {
00383         RUBY_DTRACE_ARRAY_CREATE(0, rb_sourcefile(), rb_sourceline());
00384     }
00385 
00386     return ary_alloc(klass);
00387 }
00388 
00389 static VALUE
00390 ary_new(VALUE klass, long capa)
00391 {
00392     VALUE ary;
00393 
00394     if (capa < 0) {
00395         rb_raise(rb_eArgError, "negative array size (or size too big)");
00396     }
00397     if (capa > ARY_MAX_SIZE) {
00398         rb_raise(rb_eArgError, "array size too big");
00399     }
00400 
00401     if (RUBY_DTRACE_ARRAY_CREATE_ENABLED()) {
00402         RUBY_DTRACE_ARRAY_CREATE(capa, rb_sourcefile(), rb_sourceline());
00403     }
00404 
00405     ary = ary_alloc(klass);
00406     if (capa > RARRAY_EMBED_LEN_MAX) {
00407         FL_UNSET_EMBED(ary);
00408         ARY_SET_PTR(ary, ALLOC_N(VALUE, capa));
00409         ARY_SET_CAPA(ary, capa);
00410         ARY_SET_HEAP_LEN(ary, 0);
00411     }
00412 
00413     return ary;
00414 }
00415 
00416 VALUE
00417 rb_ary_new2(long capa)
00418 {
00419     return ary_new(rb_cArray, capa);
00420 }
00421 
00422 
00423 VALUE
00424 rb_ary_new(void)
00425 {
00426     return rb_ary_new2(RARRAY_EMBED_LEN_MAX);
00427 }
00428 
00429 #include <stdarg.h>
00430 
00431 VALUE
00432 rb_ary_new3(long n, ...)
00433 {
00434     va_list ar;
00435     VALUE ary;
00436     long i;
00437 
00438     ary = rb_ary_new2(n);
00439 
00440     va_start(ar, n);
00441     for (i=0; i<n; i++) {
00442         RARRAY_PTR(ary)[i] = va_arg(ar, VALUE);
00443     }
00444     va_end(ar);
00445 
00446     ARY_SET_LEN(ary, n);
00447     return ary;
00448 }
00449 
00450 VALUE
00451 rb_ary_new4(long n, const VALUE *elts)
00452 {
00453     VALUE ary;
00454 
00455     ary = rb_ary_new2(n);
00456     if (n > 0 && elts) {
00457         MEMCPY(RARRAY_PTR(ary), elts, VALUE, n);
00458         ARY_SET_LEN(ary, n);
00459     }
00460 
00461     return ary;
00462 }
00463 
00464 VALUE
00465 rb_ary_tmp_new(long capa)
00466 {
00467     return ary_new(0, capa);
00468 }
00469 
00470 void
00471 rb_ary_free(VALUE ary)
00472 {
00473     if (ARY_OWNS_HEAP_P(ary)) {
00474         xfree(ARY_HEAP_PTR(ary));
00475     }
00476 }
00477 
00478 RUBY_FUNC_EXPORTED size_t
00479 rb_ary_memsize(VALUE ary)
00480 {
00481     if (ARY_OWNS_HEAP_P(ary)) {
00482         return RARRAY(ary)->as.heap.aux.capa * sizeof(VALUE);
00483     }
00484     else {
00485         return 0;
00486     }
00487 }
00488 
00489 static inline void
00490 ary_discard(VALUE ary)
00491 {
00492     rb_ary_free(ary);
00493     RBASIC(ary)->flags |= RARRAY_EMBED_FLAG;
00494     RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK;
00495 }
00496 
00497 static VALUE
00498 ary_make_shared(VALUE ary)
00499 {
00500     assert(!ARY_EMBED_P(ary));
00501     if (ARY_SHARED_P(ary)) {
00502         return ARY_SHARED(ary);
00503     }
00504     else if (ARY_SHARED_ROOT_P(ary)) {
00505         return ary;
00506     }
00507     else if (OBJ_FROZEN(ary)) {
00508         ary_resize_capa(ary, ARY_HEAP_LEN(ary));
00509         FL_SET_SHARED_ROOT(ary);
00510         ARY_SET_SHARED_NUM(ary, 1);
00511         return ary;
00512     }
00513     else {
00514         NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY);
00515         FL_UNSET_EMBED(shared);
00516 
00517         ARY_SET_LEN((VALUE)shared, ARY_CAPA(ary));
00518         ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary));
00519         rb_mem_clear(RARRAY_PTR(shared) + RARRAY_LEN(ary), ARY_CAPA(ary) - RARRAY_LEN(ary));
00520         FL_SET_SHARED_ROOT(shared);
00521         ARY_SET_SHARED_NUM((VALUE)shared, 1);
00522         FL_SET_SHARED(ary);
00523         ARY_SET_SHARED(ary, (VALUE)shared);
00524         OBJ_FREEZE(shared);
00525         return (VALUE)shared;
00526     }
00527 }
00528 
00529 
00530 static VALUE
00531 ary_make_substitution(VALUE ary)
00532 {
00533     if (RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX) {
00534         VALUE subst = rb_ary_new2(RARRAY_LEN(ary));
00535         MEMCPY(ARY_EMBED_PTR(subst), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
00536         ARY_SET_EMBED_LEN(subst, RARRAY_LEN(ary));
00537         return subst;
00538     }
00539     else {
00540         return rb_ary_increment_share(ary_make_shared(ary));
00541     }
00542 }
00543 
00544 VALUE
00545 rb_assoc_new(VALUE car, VALUE cdr)
00546 {
00547     return rb_ary_new3(2, car, cdr);
00548 }
00549 
00550 static VALUE
00551 to_ary(VALUE ary)
00552 {
00553     return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
00554 }
00555 
00556 VALUE
00557 rb_check_array_type(VALUE ary)
00558 {
00559     return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
00560 }
00561 
00562 /*
00563  *  call-seq:
00564  *     Array.try_convert(obj) -> array or nil
00565  *
00566  *  Tries to convert +obj+ into an array, using +to_ary+ method.  Returns the
00567  *  converted array or +nil+ if +obj+ cannot be converted for any reason.
00568  *  This method can be used to check if an argument is an array.
00569  *
00570  *     Array.try_convert([1])   #=> [1]
00571  *     Array.try_convert("1")   #=> nil
00572  *
00573  *     if tmp = Array.try_convert(arg)
00574  *       # the argument is an array
00575  *     elsif tmp = String.try_convert(arg)
00576  *       # the argument is a string
00577  *     end
00578  *
00579  */
00580 
00581 static VALUE
00582 rb_ary_s_try_convert(VALUE dummy, VALUE ary)
00583 {
00584     return rb_check_array_type(ary);
00585 }
00586 
00587 /*
00588  *  call-seq:
00589  *     Array.new(size=0, obj=nil)
00590  *     Array.new(array)
00591  *     Array.new(size) {|index| block }
00592  *
00593  *  Returns a new array.
00594  *
00595  *  In the first form, if no arguments are sent, the new array will be empty.
00596  *  When a +size+ and an optional +obj+ are sent, an array is created with
00597  *  +size+ copies of +obj+.  Take notice that all elements will reference the
00598  *  same object +obj+.
00599  *
00600  *  The second form creates a copy of the array passed as a parameter (the
00601  *  array is generated by calling to_ary on the parameter).
00602  *
00603  *    first_array = ["Matz", "Guido"]
00604  *
00605  *    second_array = Array.new(first_array) #=> ["Matz", "Guido"]
00606  *
00607  *    first_array.equal? second_array       #=> false
00608  *
00609  *  In the last form, an array of the given size is created.  Each element in
00610  *  this array is created by passing the element's index to the given block
00611  *  and storing the return value.
00612  *
00613  *    Array.new(3){ |index| index ** 2 }
00614  *    # => [0, 1, 4]
00615  *
00616  *  == Common gotchas
00617  *
00618  *  When sending the second parameter, the same object will be used as the
00619  *  value for all the array elements:
00620  *
00621  *     a = Array.new(2, Hash.new)
00622  *     # => [{}, {}]
00623  *
00624  *     a[0]['cat'] = 'feline'
00625  *     a # => [{"cat"=>"feline"}, {"cat"=>"feline"}]
00626  *
00627  *     a[1]['cat'] = 'Felix'
00628  *     a # => [{"cat"=>"Felix"}, {"cat"=>"Felix"}]
00629  *
00630  *  Since all the Array elements store the same hash, changes to one of them
00631  *  will affect them all.
00632  *
00633  *  If multiple copies are what you want, you should use the block
00634  *  version which uses the result of that block each time an element
00635  *  of the array needs to be initialized:
00636  *
00637  *     a = Array.new(2) { Hash.new }
00638  *     a[0]['cat'] = 'feline'
00639  *     a # => [{"cat"=>"feline"}, {}]
00640  *
00641  */
00642 
00643 static VALUE
00644 rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
00645 {
00646     long len;
00647     VALUE size, val;
00648 
00649     rb_ary_modify(ary);
00650     if (argc == 0) {
00651         if (ARY_OWNS_HEAP_P(ary) && RARRAY_PTR(ary)) {
00652             xfree(RARRAY_PTR(ary));
00653         }
00654         rb_ary_unshare_safe(ary);
00655         FL_SET_EMBED(ary);
00656         ARY_SET_EMBED_LEN(ary, 0);
00657         if (rb_block_given_p()) {
00658             rb_warning("given block not used");
00659         }
00660         return ary;
00661     }
00662     rb_scan_args(argc, argv, "02", &size, &val);
00663     if (argc == 1 && !FIXNUM_P(size)) {
00664         val = rb_check_array_type(size);
00665         if (!NIL_P(val)) {
00666             rb_ary_replace(ary, val);
00667             return ary;
00668         }
00669     }
00670 
00671     len = NUM2LONG(size);
00672     if (len < 0) {
00673         rb_raise(rb_eArgError, "negative array size");
00674     }
00675     if (len > ARY_MAX_SIZE) {
00676         rb_raise(rb_eArgError, "array size too big");
00677     }
00678     rb_ary_modify(ary);
00679     ary_resize_capa(ary, len);
00680     if (rb_block_given_p()) {
00681         long i;
00682 
00683         if (argc == 2) {
00684             rb_warn("block supersedes default value argument");
00685         }
00686         for (i=0; i<len; i++) {
00687             rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
00688             ARY_SET_LEN(ary, i + 1);
00689         }
00690     }
00691     else {
00692         memfill(RARRAY_PTR(ary), len, val);
00693         ARY_SET_LEN(ary, len);
00694     }
00695     return ary;
00696 }
00697 
00698 /*
00699  * Returns a new array populated with the given objects.
00700  *
00701  *   Array.[]( 1, 'a', /^A/ ) # => [1, "a", /^A/]
00702  *   Array[ 1, 'a', /^A/ ]    # => [1, "a", /^A/]
00703  *   [ 1, 'a', /^A/ ]         # => [1, "a", /^A/]
00704  */
00705 
00706 static VALUE
00707 rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
00708 {
00709     VALUE ary = ary_new(klass, argc);
00710     if (argc > 0 && argv) {
00711         MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
00712         ARY_SET_LEN(ary, argc);
00713     }
00714 
00715     return ary;
00716 }
00717 
00718 void
00719 rb_ary_store(VALUE ary, long idx, VALUE val)
00720 {
00721     if (idx < 0) {
00722         idx += RARRAY_LEN(ary);
00723         if (idx < 0) {
00724             rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
00725                      idx - RARRAY_LEN(ary), -RARRAY_LEN(ary));
00726         }
00727     }
00728     else if (idx >= ARY_MAX_SIZE) {
00729         rb_raise(rb_eIndexError, "index %ld too big", idx);
00730     }
00731 
00732     rb_ary_modify(ary);
00733     if (idx >= ARY_CAPA(ary)) {
00734         ary_double_capa(ary, idx);
00735     }
00736     if (idx > RARRAY_LEN(ary)) {
00737         rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary),
00738                      idx-RARRAY_LEN(ary) + 1);
00739     }
00740 
00741     if (idx >= RARRAY_LEN(ary)) {
00742         ARY_SET_LEN(ary, idx + 1);
00743     }
00744     RARRAY_PTR(ary)[idx] = val;
00745 }
00746 
00747 static VALUE
00748 ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
00749 {
00750     assert(offset >= 0);
00751     assert(len >= 0);
00752     assert(offset+len <= RARRAY_LEN(ary));
00753 
00754     if (len <= RARRAY_EMBED_LEN_MAX) {
00755         VALUE result = ary_alloc(klass);
00756         MEMCPY(ARY_EMBED_PTR(result), RARRAY_PTR(ary) + offset, VALUE, len);
00757         ARY_SET_EMBED_LEN(result, len);
00758         return result;
00759     }
00760     else {
00761         VALUE shared, result = ary_alloc(klass);
00762         FL_UNSET_EMBED(result);
00763 
00764         shared = ary_make_shared(ary);
00765         ARY_SET_PTR(result, RARRAY_PTR(ary));
00766         ARY_SET_LEN(result, RARRAY_LEN(ary));
00767         rb_ary_set_shared(result, shared);
00768 
00769         ARY_INCREASE_PTR(result, offset);
00770         ARY_SET_LEN(result, len);
00771         return result;
00772     }
00773 }
00774 
00775 static VALUE
00776 ary_make_shared_copy(VALUE ary)
00777 {
00778     return ary_make_partial(ary, rb_obj_class(ary), 0, RARRAY_LEN(ary));
00779 }
00780 
00781 enum ary_take_pos_flags
00782 {
00783     ARY_TAKE_FIRST = 0,
00784     ARY_TAKE_LAST = 1
00785 };
00786 
00787 static VALUE
00788 ary_take_first_or_last(int argc, VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
00789 {
00790     VALUE nv;
00791     long n;
00792     long offset = 0;
00793 
00794     rb_scan_args(argc, argv, "1", &nv);
00795     n = NUM2LONG(nv);
00796     if (n > RARRAY_LEN(ary)) {
00797         n = RARRAY_LEN(ary);
00798     }
00799     else if (n < 0) {
00800         rb_raise(rb_eArgError, "negative array size");
00801     }
00802     if (last) {
00803         offset = RARRAY_LEN(ary) - n;
00804     }
00805     return ary_make_partial(ary, rb_cArray, offset, n);
00806 }
00807 
00808 /*
00809  *  call-seq:
00810  *     ary << obj            -> ary
00811  *
00812  *  Append---Pushes the given object on to the end of this array. This
00813  *  expression returns the array itself, so several appends
00814  *  may be chained together.
00815  *
00816  *     [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
00817  *             #=>  [ 1, 2, "c", "d", [ 3, 4 ] ]
00818  *
00819  */
00820 
00821 VALUE
00822 rb_ary_push(VALUE ary, VALUE item)
00823 {
00824     long idx = RARRAY_LEN(ary);
00825 
00826     ary_ensure_room_for_push(ary, 1);
00827     RARRAY_PTR(ary)[idx] = item;
00828     ARY_SET_LEN(ary, idx + 1);
00829     return ary;
00830 }
00831 
00832 VALUE
00833 rb_ary_cat(VALUE ary, const VALUE *ptr, long len)
00834 {
00835     long oldlen = RARRAY_LEN(ary);
00836 
00837     ary_ensure_room_for_push(ary, len);
00838     MEMCPY(RARRAY_PTR(ary) + oldlen, ptr, VALUE, len);
00839     ARY_SET_LEN(ary, oldlen + len);
00840     return ary;
00841 }
00842 
00843 /*
00844  *  call-seq:
00845  *     ary.push(obj, ... )   -> ary
00846  *
00847  *  Append --- Pushes the given object(s) on to the end of this array. This
00848  *  expression returns the array itself, so several appends
00849  *  may be chained together. See also Array#pop for the opposite
00850  *  effect.
00851  *
00852  *     a = [ "a", "b", "c" ]
00853  *     a.push("d", "e", "f")
00854  *             #=> ["a", "b", "c", "d", "e", "f"]
00855  *     [1, 2, 3,].push(4).push(5)
00856  *             #=> [1, 2, 3, 4, 5]
00857  */
00858 
00859 static VALUE
00860 rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
00861 {
00862     return rb_ary_cat(ary, argv, argc);
00863 }
00864 
00865 VALUE
00866 rb_ary_pop(VALUE ary)
00867 {
00868     long n;
00869     rb_ary_modify_check(ary);
00870     if (RARRAY_LEN(ary) == 0) return Qnil;
00871     if (ARY_OWNS_HEAP_P(ary) &&
00872         RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) &&
00873         ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
00874     {
00875         ary_resize_capa(ary, RARRAY_LEN(ary) * 2);
00876     }
00877     n = RARRAY_LEN(ary)-1;
00878     ARY_SET_LEN(ary, n);
00879     return RARRAY_PTR(ary)[n];
00880 }
00881 
00882 /*
00883  *  call-seq:
00884  *     ary.pop    -> obj or nil
00885  *     ary.pop(n) -> new_ary
00886  *
00887  *  Removes the last element from +self+ and returns it, or
00888  *  +nil+ if the array is empty.
00889  *
00890  *  If a number +n+ is given, returns an array of the last +n+ elements
00891  *  (or less) just like <code>array.slice!(-n, n)</code> does. See also
00892  *  Array#push for the opposite effect.
00893  *
00894  *     a = [ "a", "b", "c", "d" ]
00895  *     a.pop     #=> "d"
00896  *     a.pop(2)  #=> ["b", "c"]
00897  *     a         #=> ["a"]
00898  */
00899 
00900 static VALUE
00901 rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
00902 {
00903     VALUE result;
00904 
00905     if (argc == 0) {
00906         return rb_ary_pop(ary);
00907     }
00908 
00909     rb_ary_modify_check(ary);
00910     result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
00911     ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
00912     return result;
00913 }
00914 
00915 VALUE
00916 rb_ary_shift(VALUE ary)
00917 {
00918     VALUE top;
00919 
00920     rb_ary_modify_check(ary);
00921     if (RARRAY_LEN(ary) == 0) return Qnil;
00922     top = RARRAY_PTR(ary)[0];
00923     if (!ARY_SHARED_P(ary)) {
00924         if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
00925             MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
00926             ARY_INCREASE_LEN(ary, -1);
00927             return top;
00928         }
00929         assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */
00930 
00931         RARRAY_PTR(ary)[0] = Qnil;
00932         ary_make_shared(ary);
00933     }
00934     else if (ARY_SHARED_NUM(ARY_SHARED(ary)) == 1) {
00935         RARRAY_PTR(ary)[0] = Qnil;
00936     }
00937     ARY_INCREASE_PTR(ary, 1);           /* shift ptr */
00938     ARY_INCREASE_LEN(ary, -1);
00939 
00940     return top;
00941 }
00942 
00943 /*
00944  *  call-seq:
00945  *     ary.shift    -> obj or nil
00946  *     ary.shift(n) -> new_ary
00947  *
00948  *  Removes the first element of +self+ and returns it (shifting all
00949  *  other elements down by one). Returns +nil+ if the array
00950  *  is empty.
00951  *
00952  *  If a number +n+ is given, returns an array of the first +n+ elements
00953  *  (or less) just like <code>array.slice!(0, n)</code> does. With +ary+
00954  *  containing only the remainder elements, not including what was shifted to
00955  *  +new_ary+. See also Array#unshift for the opposite effect.
00956  *
00957  *     args = [ "-m", "-q", "filename" ]
00958  *     args.shift     #=> "-m"
00959  *     args           #=> ["-q", "filename"]
00960  *
00961  *     args = [ "-m", "-q", "filename" ]
00962  *     args.shift(2)  #=> ["-m", "-q"]
00963  *     args           #=> ["filename"]
00964  */
00965 
00966 static VALUE
00967 rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
00968 {
00969     VALUE result;
00970     long n;
00971 
00972     if (argc == 0) {
00973         return rb_ary_shift(ary);
00974     }
00975 
00976     rb_ary_modify_check(ary);
00977     result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
00978     n = RARRAY_LEN(result);
00979     if (ARY_SHARED_P(ary)) {
00980         if (ARY_SHARED_NUM(ARY_SHARED(ary)) == 1) {
00981             rb_mem_clear(RARRAY_PTR(ary), n);
00982         }
00983         ARY_INCREASE_PTR(ary, n);
00984     }
00985     else {
00986         MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
00987     }
00988     ARY_INCREASE_LEN(ary, -n);
00989 
00990     return result;
00991 }
00992 
00993 static void
00994 ary_ensure_room_for_unshift(VALUE ary, int argc)
00995 {
00996     long len = RARRAY_LEN(ary);
00997     long new_len = len + argc;
00998     long capa;
00999     VALUE *head, *sharedp;
01000 
01001     if (ARY_SHARED_P(ary)) {
01002         VALUE shared = ARY_SHARED(ary);
01003         capa = RARRAY_LEN(shared);
01004         if (ARY_SHARED_NUM(shared) == 1 && capa > new_len) {
01005             head = RARRAY_PTR(ary);
01006             sharedp = RARRAY_PTR(shared);
01007             goto makeroom_if_need;
01008         }
01009     }
01010 
01011     rb_ary_modify(ary);
01012     capa = ARY_CAPA(ary);
01013     if (capa - (capa >> 6) <= new_len) {
01014         ary_double_capa(ary, new_len);
01015     }
01016 
01017     /* use shared array for big "queues" */
01018     if (new_len > ARY_DEFAULT_SIZE * 4) {
01019         /* make a room for unshifted items */
01020         capa = ARY_CAPA(ary);
01021         ary_make_shared(ary);
01022 
01023         head = sharedp = RARRAY_PTR(ary);
01024         goto makeroom;
01025       makeroom_if_need:
01026         if (head - sharedp < argc) {
01027             long room;
01028           makeroom:
01029             room = capa - new_len;
01030             room -= room >> 4;
01031             MEMMOVE(sharedp + argc + room, head, VALUE, len);
01032             head = sharedp + argc + room;
01033         }
01034         ARY_SET_PTR(ary, head - argc);
01035     }
01036     else {
01037         /* sliding items */
01038         MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len);
01039     }
01040 }
01041 
01042 /*
01043  *  call-seq:
01044  *     ary.unshift(obj, ...)  -> ary
01045  *
01046  *  Prepends objects to the front of +self+, moving other elements upwards.
01047  *  See also Array#shift for the opposite effect.
01048  *
01049  *     a = [ "b", "c", "d" ]
01050  *     a.unshift("a")   #=> ["a", "b", "c", "d"]
01051  *     a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]
01052  */
01053 
01054 static VALUE
01055 rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
01056 {
01057     long len = RARRAY_LEN(ary);
01058 
01059     if (argc == 0) {
01060         rb_ary_modify_check(ary);
01061         return ary;
01062     }
01063 
01064     ary_ensure_room_for_unshift(ary, argc);
01065     MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
01066     ARY_SET_LEN(ary, len + argc);
01067     return ary;
01068 }
01069 
01070 VALUE
01071 rb_ary_unshift(VALUE ary, VALUE item)
01072 {
01073     return rb_ary_unshift_m(1,&item,ary);
01074 }
01075 
01076 /* faster version - use this if you don't need to treat negative offset */
01077 static inline VALUE
01078 rb_ary_elt(VALUE ary, long offset)
01079 {
01080     if (RARRAY_LEN(ary) == 0) return Qnil;
01081     if (offset < 0 || RARRAY_LEN(ary) <= offset) {
01082         return Qnil;
01083     }
01084     return RARRAY_PTR(ary)[offset];
01085 }
01086 
01087 VALUE
01088 rb_ary_entry(VALUE ary, long offset)
01089 {
01090     if (offset < 0) {
01091         offset += RARRAY_LEN(ary);
01092     }
01093     return rb_ary_elt(ary, offset);
01094 }
01095 
01096 VALUE
01097 rb_ary_subseq(VALUE ary, long beg, long len)
01098 {
01099     VALUE klass;
01100 
01101     if (beg > RARRAY_LEN(ary)) return Qnil;
01102     if (beg < 0 || len < 0) return Qnil;
01103 
01104     if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) {
01105         len = RARRAY_LEN(ary) - beg;
01106     }
01107     klass = rb_obj_class(ary);
01108     if (len == 0) return ary_new(klass, 0);
01109 
01110     return ary_make_partial(ary, klass, beg, len);
01111 }
01112 
01113 /*
01114  *  call-seq:
01115  *     ary[index]                -> obj     or nil
01116  *     ary[start, length]        -> new_ary or nil
01117  *     ary[range]                -> new_ary or nil
01118  *     ary.slice(index)          -> obj     or nil
01119  *     ary.slice(start, length)  -> new_ary or nil
01120  *     ary.slice(range)          -> new_ary or nil
01121  *
01122  *  Element Reference --- Returns the element at +index+, or returns a
01123  *  subarray starting at the +start+ index and continuing for +length+
01124  *  elements, or returns a subarray specified by +range+ of indices.
01125  *
01126  *  Negative indices count backward from the end of the array (-1 is the last
01127  *  element).  For +start+ and +range+ cases the starting index is just before
01128  *  an element.  Additionally, an empty array is returned when the starting
01129  *  index for an element range is at the end of the array.
01130  *
01131  *  Returns +nil+ if the index (or starting index) are out of range.
01132  *
01133  *     a = [ "a", "b", "c", "d", "e" ]
01134  *     a[2] +  a[0] + a[1]    #=> "cab"
01135  *     a[6]                   #=> nil
01136  *     a[1, 2]                #=> [ "b", "c" ]
01137  *     a[1..3]                #=> [ "b", "c", "d" ]
01138  *     a[4..7]                #=> [ "e" ]
01139  *     a[6..10]               #=> nil
01140  *     a[-3, 3]               #=> [ "c", "d", "e" ]
01141  *     # special cases
01142  *     a[5]                   #=> nil
01143  *     a[6, 1]                #=> nil
01144  *     a[5, 1]                #=> []
01145  *     a[5..10]               #=> []
01146  *
01147  */
01148 
01149 VALUE
01150 rb_ary_aref(int argc, VALUE *argv, VALUE ary)
01151 {
01152     VALUE arg;
01153     long beg, len;
01154 
01155     if (argc == 2) {
01156         beg = NUM2LONG(argv[0]);
01157         len = NUM2LONG(argv[1]);
01158         if (beg < 0) {
01159             beg += RARRAY_LEN(ary);
01160         }
01161         return rb_ary_subseq(ary, beg, len);
01162     }
01163     if (argc != 1) {
01164         rb_scan_args(argc, argv, "11", NULL, NULL);
01165     }
01166     arg = argv[0];
01167     /* special case - speeding up */
01168     if (FIXNUM_P(arg)) {
01169         return rb_ary_entry(ary, FIX2LONG(arg));
01170     }
01171     /* check if idx is Range */
01172     switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) {
01173       case Qfalse:
01174         break;
01175       case Qnil:
01176         return Qnil;
01177       default:
01178         return rb_ary_subseq(ary, beg, len);
01179     }
01180     return rb_ary_entry(ary, NUM2LONG(arg));
01181 }
01182 
01183 /*
01184  *  call-seq:
01185  *     ary.at(index)   ->   obj  or nil
01186  *
01187  *  Returns the element at +index+. A negative index counts from the end of
01188  *  +self+. Returns +nil+ if the index is out of range. See also
01189  *  Array#[].
01190  *
01191  *     a = [ "a", "b", "c", "d", "e" ]
01192  *     a.at(0)     #=> "a"
01193  *     a.at(-1)    #=> "e"
01194  */
01195 
01196 static VALUE
01197 rb_ary_at(VALUE ary, VALUE pos)
01198 {
01199     return rb_ary_entry(ary, NUM2LONG(pos));
01200 }
01201 
01202 /*
01203  *  call-seq:
01204  *     ary.first     ->   obj or nil
01205  *     ary.first(n)  ->   new_ary
01206  *
01207  *  Returns the first element, or the first +n+ elements, of the array.
01208  *  If the array is empty, the first form returns +nil+, and the
01209  *  second form returns an empty array. See also Array#last for
01210  *  the opposite effect.
01211  *
01212  *     a = [ "q", "r", "s", "t" ]
01213  *     a.first     #=> "q"
01214  *     a.first(2)  #=> ["q", "r"]
01215  */
01216 
01217 static VALUE
01218 rb_ary_first(int argc, VALUE *argv, VALUE ary)
01219 {
01220     if (argc == 0) {
01221         if (RARRAY_LEN(ary) == 0) return Qnil;
01222         return RARRAY_PTR(ary)[0];
01223     }
01224     else {
01225         return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
01226     }
01227 }
01228 
01229 /*
01230  *  call-seq:
01231  *     ary.last     ->  obj or nil
01232  *     ary.last(n)  ->  new_ary
01233  *
01234  *  Returns the last element(s) of +self+. If the array is empty,
01235  *  the first form returns +nil+.
01236  *
01237  *  See also Array#first for the opposite effect.
01238  *
01239  *     a = [ "w", "x", "y", "z" ]
01240  *     a.last     #=> "z"
01241  *     a.last(2)  #=> ["y", "z"]
01242  */
01243 
01244 VALUE
01245 rb_ary_last(int argc, VALUE *argv, VALUE ary)
01246 {
01247     if (argc == 0) {
01248         if (RARRAY_LEN(ary) == 0) return Qnil;
01249         return RARRAY_PTR(ary)[RARRAY_LEN(ary)-1];
01250     }
01251     else {
01252         return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
01253     }
01254 }
01255 
01256 /*
01257  *  call-seq:
01258  *     ary.fetch(index)                    -> obj
01259  *     ary.fetch(index, default)           -> obj
01260  *     ary.fetch(index) { |index| block }  -> obj
01261  *
01262  *  Tries to return the element at position +index+, but throws an IndexError
01263  *  exception if the referenced +index+ lies outside of the array bounds.  This
01264  *  error can be prevented by supplying a second argument, which will act as a
01265  *  +default+ value.
01266  *
01267  *  Alternatively, if a block is given it will only be executed when an
01268  *  invalid +index+ is referenced.  Negative values of +index+ count from the
01269  *  end of the array.
01270  *
01271  *     a = [ 11, 22, 33, 44 ]
01272  *     a.fetch(1)               #=> 22
01273  *     a.fetch(-1)              #=> 44
01274  *     a.fetch(4, 'cat')        #=> "cat"
01275  *     a.fetch(100) { |i| puts "#{i} is out of bounds" }
01276  *                              #=> "100 is out of bounds"
01277  */
01278 
01279 static VALUE
01280 rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
01281 {
01282     VALUE pos, ifnone;
01283     long block_given;
01284     long idx;
01285 
01286     rb_scan_args(argc, argv, "11", &pos, &ifnone);
01287     block_given = rb_block_given_p();
01288     if (block_given && argc == 2) {
01289         rb_warn("block supersedes default value argument");
01290     }
01291     idx = NUM2LONG(pos);
01292 
01293     if (idx < 0) {
01294         idx +=  RARRAY_LEN(ary);
01295     }
01296     if (idx < 0 || RARRAY_LEN(ary) <= idx) {
01297         if (block_given) return rb_yield(pos);
01298         if (argc == 1) {
01299             rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld",
01300                         idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary));
01301         }
01302         return ifnone;
01303     }
01304     return RARRAY_PTR(ary)[idx];
01305 }
01306 
01307 /*
01308  *  call-seq:
01309  *     ary.index(obj)             ->  int or nil
01310  *     ary.index { |item| block } ->  int or nil
01311  *     ary.index                  ->  Enumerator
01312  *
01313  *  Returns the _index_ of the first object in +ary+ such that the object is
01314  *  <code>==</code> to +obj+.
01315  *
01316  *  If a block is given instead of an argument, returns the _index_ of the
01317  *  first object for which the block returns +true+.  Returns +nil+ if no
01318  *  match is found.
01319  *
01320  *  See also Array#rindex.
01321  *
01322  *  An Enumerator is returned if neither a block nor argument is given.
01323  *
01324  *     a = [ "a", "b", "c" ]
01325  *     a.index("b")              #=> 1
01326  *     a.index("z")              #=> nil
01327  *     a.index { |x| x == "b" }  #=> 1
01328  *
01329  *  This is an alias of Array#find_index.
01330  */
01331 
01332 static VALUE
01333 rb_ary_index(int argc, VALUE *argv, VALUE ary)
01334 {
01335     VALUE val;
01336     long i;
01337 
01338     if (argc == 0) {
01339         RETURN_ENUMERATOR(ary, 0, 0);
01340         for (i=0; i<RARRAY_LEN(ary); i++) {
01341             if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
01342                 return LONG2NUM(i);
01343             }
01344         }
01345         return Qnil;
01346     }
01347     rb_scan_args(argc, argv, "1", &val);
01348     if (rb_block_given_p())
01349         rb_warn("given block not used");
01350     for (i=0; i<RARRAY_LEN(ary); i++) {
01351         if (rb_equal(RARRAY_PTR(ary)[i], val))
01352             return LONG2NUM(i);
01353     }
01354     return Qnil;
01355 }
01356 
01357 /*
01358  *  call-seq:
01359  *     ary.rindex(obj)             ->  int or nil
01360  *     ary.rindex { |item| block } ->  int or nil
01361  *     ary.rindex                  ->  Enumerator
01362  *
01363  *  Returns the _index_ of the last object in +self+ <code>==</code> to +obj+.
01364  *
01365  *  If a block is given instead of an argument, returns the _index_ of the
01366  *  first object for which the block returns +true+, starting from the last
01367  *  object.
01368  *
01369  *  Returns +nil+ if no match is found.
01370  *
01371  *  See also Array#index.
01372  *
01373  *  If neither block nor argument is given, an Enumerator is returned instead.
01374  *
01375  *     a = [ "a", "b", "b", "b", "c" ]
01376  *     a.rindex("b")             #=> 3
01377  *     a.rindex("z")             #=> nil
01378  *     a.rindex { |x| x == "b" } #=> 3
01379  */
01380 
01381 static VALUE
01382 rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
01383 {
01384     VALUE val;
01385     long i = RARRAY_LEN(ary);
01386 
01387     if (argc == 0) {
01388         RETURN_ENUMERATOR(ary, 0, 0);
01389         while (i--) {
01390             if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
01391                 return LONG2NUM(i);
01392             if (i > RARRAY_LEN(ary)) {
01393                 i = RARRAY_LEN(ary);
01394             }
01395         }
01396         return Qnil;
01397     }
01398     rb_scan_args(argc, argv, "1", &val);
01399     if (rb_block_given_p())
01400         rb_warn("given block not used");
01401     while (i--) {
01402         if (rb_equal(RARRAY_PTR(ary)[i], val))
01403             return LONG2NUM(i);
01404         if (i > RARRAY_LEN(ary)) {
01405             i = RARRAY_LEN(ary);
01406         }
01407     }
01408     return Qnil;
01409 }
01410 
01411 VALUE
01412 rb_ary_to_ary(VALUE obj)
01413 {
01414     VALUE tmp = rb_check_array_type(obj);
01415 
01416     if (!NIL_P(tmp)) return tmp;
01417     return rb_ary_new3(1, obj);
01418 }
01419 
01420 static void
01421 rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
01422 {
01423     long rlen;
01424 
01425     if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
01426     if (beg < 0) {
01427         beg += RARRAY_LEN(ary);
01428         if (beg < 0) {
01429             rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
01430                      beg - RARRAY_LEN(ary), -RARRAY_LEN(ary));
01431         }
01432     }
01433     if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) {
01434         len = RARRAY_LEN(ary) - beg;
01435     }
01436 
01437     if (rpl == Qundef) {
01438         rlen = 0;
01439     }
01440     else {
01441         rpl = rb_ary_to_ary(rpl);
01442         rlen = RARRAY_LEN(rpl);
01443     }
01444     if (beg >= RARRAY_LEN(ary)) {
01445         if (beg > ARY_MAX_SIZE - rlen) {
01446             rb_raise(rb_eIndexError, "index %ld too big", beg);
01447         }
01448         ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */
01449         len = beg + rlen;
01450         rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), beg - RARRAY_LEN(ary));
01451         if (rlen > 0) {
01452             MEMCPY(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
01453         }
01454         ARY_SET_LEN(ary, len);
01455     }
01456     else {
01457         long alen;
01458 
01459         rb_ary_modify(ary);
01460         alen = RARRAY_LEN(ary) + rlen - len;
01461         if (alen >= ARY_CAPA(ary)) {
01462             ary_double_capa(ary, alen);
01463         }
01464 
01465         if (len != rlen) {
01466             MEMMOVE(RARRAY_PTR(ary) + beg + rlen, RARRAY_PTR(ary) + beg + len,
01467                     VALUE, RARRAY_LEN(ary) - (beg + len));
01468             ARY_SET_LEN(ary, alen);
01469         }
01470         if (rlen > 0) {
01471             MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
01472         }
01473     }
01474     RB_GC_GUARD(rpl);
01475 }
01476 
01477 void
01478 rb_ary_set_len(VALUE ary, long len)
01479 {
01480     long capa;
01481 
01482     rb_ary_modify_check(ary);
01483     if (ARY_SHARED_P(ary)) {
01484         rb_raise(rb_eRuntimeError, "can't set length of shared ");
01485     }
01486     if (len > (capa = (long)ARY_CAPA(ary))) {
01487         rb_bug("probable buffer overflow: %ld for %ld", len, capa);
01488     }
01489     ARY_SET_LEN(ary, len);
01490 }
01491 
01500 VALUE
01501 rb_ary_resize(VALUE ary, long len)
01502 {
01503     long olen;
01504 
01505     rb_ary_modify(ary);
01506     olen = RARRAY_LEN(ary);
01507     if (len == olen) return ary;
01508     if (len > ARY_MAX_SIZE) {
01509         rb_raise(rb_eIndexError, "index %ld too big", len);
01510     }
01511     if (len > olen) {
01512         if (len >= ARY_CAPA(ary)) {
01513             ary_double_capa(ary, len);
01514         }
01515         rb_mem_clear(RARRAY_PTR(ary) + olen, len - olen);
01516         ARY_SET_LEN(ary, len);
01517     }
01518     else if (ARY_EMBED_P(ary)) {
01519         ARY_SET_EMBED_LEN(ary, len);
01520     }
01521     else if (len <= RARRAY_EMBED_LEN_MAX) {
01522         VALUE tmp[RARRAY_EMBED_LEN_MAX];
01523         MEMCPY(tmp, ARY_HEAP_PTR(ary), VALUE, len);
01524         ary_discard(ary);
01525         MEMCPY(ARY_EMBED_PTR(ary), tmp, VALUE, len);
01526         ARY_SET_EMBED_LEN(ary, len);
01527     }
01528     else {
01529         if (olen > len + ARY_DEFAULT_SIZE) {
01530             REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, len);
01531             ARY_SET_CAPA(ary, len);
01532         }
01533         ARY_SET_HEAP_LEN(ary, len);
01534     }
01535     return ary;
01536 }
01537 
01538 /*
01539  *  call-seq:
01540  *     ary[index]         = obj                      ->  obj
01541  *     ary[start, length] = obj or other_ary or nil  ->  obj or other_ary or nil
01542  *     ary[range]         = obj or other_ary or nil  ->  obj or other_ary or nil
01543  *
01544  *  Element Assignment --- Sets the element at +index+, or replaces a subarray
01545  *  from the +start+ index for +length+ elements, or replaces a subarray
01546  *  specified by the +range+ of indices.
01547  *
01548  *  If indices are greater than the current capacity of the array, the array
01549  *  grows automatically.  Elements are inserted into the array at +start+ if
01550  *  +length+ is zero.
01551  *
01552  *  Negative indices will count backward from the end of the array.  For
01553  *  +start+ and +range+ cases the starting index is just before an element.
01554  *
01555  *  An IndexError is raised if a negative index points past the beginning of
01556  *  the array.
01557  *
01558  *  See also Array#push, and Array#unshift.
01559  *
01560  *     a = Array.new
01561  *     a[4] = "4";                 #=> [nil, nil, nil, nil, "4"]
01562  *     a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
01563  *     a[1..2] = [ 1, 2 ]          #=> ["a", 1, 2, nil, "4"]
01564  *     a[0, 2] = "?"               #=> ["?", 2, nil, "4"]
01565  *     a[0..2] = "A"               #=> ["A", "4"]
01566  *     a[-1]   = "Z"               #=> ["A", "Z"]
01567  *     a[1..-1] = nil              #=> ["A", nil]
01568  *     a[1..-1] = []               #=> ["A"]
01569  *     a[0, 0] = [ 1, 2 ]          #=> [1, 2, "A"]
01570  *     a[3, 0] = "B"               #=> [1, 2, "A", "B"]
01571  */
01572 
01573 static VALUE
01574 rb_ary_aset(int argc, VALUE *argv, VALUE ary)
01575 {
01576     long offset, beg, len;
01577 
01578     if (argc == 3) {
01579         rb_ary_modify_check(ary);
01580         beg = NUM2LONG(argv[0]);
01581         len = NUM2LONG(argv[1]);
01582         rb_ary_splice(ary, beg, len, argv[2]);
01583         return argv[2];
01584     }
01585     rb_check_arity(argc, 2, 2);
01586     rb_ary_modify_check(ary);
01587     if (FIXNUM_P(argv[0])) {
01588         offset = FIX2LONG(argv[0]);
01589         goto fixnum;
01590     }
01591     if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
01592         /* check if idx is Range */
01593         rb_ary_splice(ary, beg, len, argv[1]);
01594         return argv[1];
01595     }
01596 
01597     offset = NUM2LONG(argv[0]);
01598 fixnum:
01599     rb_ary_store(ary, offset, argv[1]);
01600     return argv[1];
01601 }
01602 
01603 /*
01604  *  call-seq:
01605  *     ary.insert(index, obj...)  -> ary
01606  *
01607  *  Inserts the given values before the element with the given +index+.
01608  *
01609  *  Negative indices count backwards from the end of the array, where +-1+ is
01610  *  the last element.
01611  *
01612  *     a = %w{ a b c d }
01613  *     a.insert(2, 99)         #=> ["a", "b", 99, "c", "d"]
01614  *     a.insert(-2, 1, 2, 3)   #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
01615  */
01616 
01617 static VALUE
01618 rb_ary_insert(int argc, VALUE *argv, VALUE ary)
01619 {
01620     long pos;
01621 
01622     rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
01623     rb_ary_modify_check(ary);
01624     if (argc == 1) return ary;
01625     pos = NUM2LONG(argv[0]);
01626     if (pos == -1) {
01627         pos = RARRAY_LEN(ary);
01628     }
01629     if (pos < 0) {
01630         pos++;
01631     }
01632     rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1));
01633     return ary;
01634 }
01635 
01636 static VALUE
01637 rb_ary_length(VALUE ary);
01638 
01639 /*
01640  *  call-seq:
01641  *     ary.each { |item| block }  -> ary
01642  *     ary.each                   -> Enumerator
01643  *
01644  *  Calls the given block once for each element in +self+, passing that element
01645  *  as a parameter.
01646  *
01647  *  An Enumerator is returned if no block is given.
01648  *
01649  *     a = [ "a", "b", "c" ]
01650  *     a.each {|x| print x, " -- " }
01651  *
01652  *  produces:
01653  *
01654  *     a -- b -- c --
01655  */
01656 
01657 VALUE
01658 rb_ary_each(VALUE array)
01659 {
01660     long i;
01661     volatile VALUE ary = array;
01662 
01663     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
01664     for (i=0; i<RARRAY_LEN(ary); i++) {
01665         rb_yield(RARRAY_PTR(ary)[i]);
01666     }
01667     return ary;
01668 }
01669 
01670 /*
01671  *  call-seq:
01672  *     ary.each_index { |index| block }  -> ary
01673  *     ary.each_index                    -> Enumerator
01674  *
01675  *  Same as Array#each, but passes the +index+ of the element instead of the
01676  *  element itself.
01677  *
01678  *  An Enumerator is returned if no block is given.
01679  *
01680  *     a = [ "a", "b", "c" ]
01681  *     a.each_index {|x| print x, " -- " }
01682  *
01683  *  produces:
01684  *
01685  *     0 -- 1 -- 2 --
01686  */
01687 
01688 static VALUE
01689 rb_ary_each_index(VALUE ary)
01690 {
01691     long i;
01692     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
01693 
01694     for (i=0; i<RARRAY_LEN(ary); i++) {
01695         rb_yield(LONG2NUM(i));
01696     }
01697     return ary;
01698 }
01699 
01700 /*
01701  *  call-seq:
01702  *     ary.reverse_each { |item| block }  -> ary
01703  *     ary.reverse_each                   -> Enumerator
01704  *
01705  *  Same as Array#each, but traverses +self+ in reverse order.
01706  *
01707  *     a = [ "a", "b", "c" ]
01708  *     a.reverse_each {|x| print x, " " }
01709  *
01710  *  produces:
01711  *
01712  *     c b a
01713  */
01714 
01715 static VALUE
01716 rb_ary_reverse_each(VALUE ary)
01717 {
01718     long len;
01719 
01720     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
01721     len = RARRAY_LEN(ary);
01722     while (len--) {
01723         rb_yield(RARRAY_PTR(ary)[len]);
01724         if (RARRAY_LEN(ary) < len) {
01725             len = RARRAY_LEN(ary);
01726         }
01727     }
01728     return ary;
01729 }
01730 
01731 /*
01732  *  call-seq:
01733  *     ary.length -> int
01734  *
01735  *  Returns the number of elements in +self+. May be zero.
01736  *
01737  *     [ 1, 2, 3, 4, 5 ].length   #=> 5
01738  *     [].length                  #=> 0
01739  */
01740 
01741 static VALUE
01742 rb_ary_length(VALUE ary)
01743 {
01744     long len = RARRAY_LEN(ary);
01745     return LONG2NUM(len);
01746 }
01747 
01748 /*
01749  *  call-seq:
01750  *     ary.empty?   -> true or false
01751  *
01752  *  Returns +true+ if +self+ contains no elements.
01753  *
01754  *     [].empty?   #=> true
01755  */
01756 
01757 static VALUE
01758 rb_ary_empty_p(VALUE ary)
01759 {
01760     if (RARRAY_LEN(ary) == 0)
01761         return Qtrue;
01762     return Qfalse;
01763 }
01764 
01765 VALUE
01766 rb_ary_dup(VALUE ary)
01767 {
01768     VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
01769     MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
01770     ARY_SET_LEN(dup, RARRAY_LEN(ary));
01771     return dup;
01772 }
01773 
01774 VALUE
01775 rb_ary_resurrect(VALUE ary)
01776 {
01777     return rb_ary_new4(RARRAY_LEN(ary), RARRAY_PTR(ary));
01778 }
01779 
01780 extern VALUE rb_output_fs;
01781 
01782 static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first);
01783 
01784 static VALUE
01785 recursive_join(VALUE obj, VALUE argp, int recur)
01786 {
01787     VALUE *arg = (VALUE *)argp;
01788     VALUE ary = arg[0];
01789     VALUE sep = arg[1];
01790     VALUE result = arg[2];
01791     int *first = (int *)arg[3];
01792 
01793     if (recur) {
01794         rb_raise(rb_eArgError, "recursive array join");
01795     }
01796     else {
01797         ary_join_1(obj, ary, sep, 0, result, first);
01798     }
01799     return Qnil;
01800 }
01801 
01802 static void
01803 ary_join_0(VALUE ary, VALUE sep, long max, VALUE result)
01804 {
01805     long i;
01806     VALUE val;
01807 
01808     if (max > 0) rb_enc_copy(result, RARRAY_PTR(ary)[0]);
01809     for (i=0; i<max; i++) {
01810         val = RARRAY_PTR(ary)[i];
01811         if (i > 0 && !NIL_P(sep))
01812             rb_str_buf_append(result, sep);
01813         rb_str_buf_append(result, val);
01814         if (OBJ_TAINTED(val)) OBJ_TAINT(result);
01815         if (OBJ_UNTRUSTED(val)) OBJ_TAINT(result);
01816     }
01817 }
01818 
01819 static void
01820 ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first)
01821 {
01822     VALUE val, tmp;
01823 
01824     for (; i<RARRAY_LEN(ary); i++) {
01825         if (i > 0 && !NIL_P(sep))
01826             rb_str_buf_append(result, sep);
01827 
01828         val = RARRAY_PTR(ary)[i];
01829         switch (TYPE(val)) {
01830           case T_STRING:
01831           str_join:
01832             rb_str_buf_append(result, val);
01833             *first = FALSE;
01834             break;
01835           case T_ARRAY:
01836             obj = val;
01837           ary_join:
01838             if (val == ary) {
01839                 rb_raise(rb_eArgError, "recursive array join");
01840             }
01841             else {
01842                 VALUE args[4];
01843 
01844                 args[0] = val;
01845                 args[1] = sep;
01846                 args[2] = result;
01847                 args[3] = (VALUE)first;
01848                 rb_exec_recursive(recursive_join, obj, (VALUE)args);
01849             }
01850             break;
01851           default:
01852             tmp = rb_check_string_type(val);
01853             if (!NIL_P(tmp)) {
01854                 val = tmp;
01855                 goto str_join;
01856             }
01857             tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_ary");
01858             if (!NIL_P(tmp)) {
01859                 obj = val;
01860                 val = tmp;
01861                 goto ary_join;
01862             }
01863             val = rb_obj_as_string(val);
01864             if (*first) {
01865                 rb_enc_copy(result, val);
01866                 *first = FALSE;
01867             }
01868             goto str_join;
01869         }
01870     }
01871 }
01872 
01873 VALUE
01874 rb_ary_join(VALUE ary, VALUE sep)
01875 {
01876     long len = 1, i;
01877     int taint = FALSE;
01878     int untrust = FALSE;
01879     VALUE val, tmp, result;
01880 
01881     if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0);
01882     if (OBJ_TAINTED(ary)) taint = TRUE;
01883     if (OBJ_UNTRUSTED(ary)) untrust = TRUE;
01884 
01885     if (!NIL_P(sep)) {
01886         StringValue(sep);
01887         len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
01888     }
01889     for (i=0; i<RARRAY_LEN(ary); i++) {
01890         val = RARRAY_PTR(ary)[i];
01891         tmp = rb_check_string_type(val);
01892 
01893         if (NIL_P(tmp) || tmp != val) {
01894             int first;
01895             result = rb_str_buf_new(len + (RARRAY_LEN(ary)-i)*10);
01896             rb_enc_associate(result, rb_usascii_encoding());
01897             if (taint) OBJ_TAINT(result);
01898             if (untrust) OBJ_UNTRUST(result);
01899             ary_join_0(ary, sep, i, result);
01900             first = i == 0;
01901             ary_join_1(ary, ary, sep, i, result, &first);
01902             return result;
01903         }
01904 
01905         len += RSTRING_LEN(tmp);
01906     }
01907 
01908     result = rb_str_buf_new(len);
01909     if (taint) OBJ_TAINT(result);
01910     if (untrust) OBJ_UNTRUST(result);
01911     ary_join_0(ary, sep, RARRAY_LEN(ary), result);
01912 
01913     return result;
01914 }
01915 
01916 /*
01917  *  call-seq:
01918  *     ary.join(separator=$,)    -> str
01919  *
01920  *  Returns a string created by converting each element of the array to
01921  *  a string, separated by the given +separator+.
01922  *  If the +separator+ is +nil+, it uses current $,.
01923  *  If both the +separator+ and $, are nil, it uses empty string.
01924  *
01925  *     [ "a", "b", "c" ].join        #=> "abc"
01926  *     [ "a", "b", "c" ].join("-")   #=> "a-b-c"
01927  */
01928 
01929 static VALUE
01930 rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
01931 {
01932     VALUE sep;
01933 
01934     rb_scan_args(argc, argv, "01", &sep);
01935     if (NIL_P(sep)) sep = rb_output_fs;
01936 
01937     return rb_ary_join(ary, sep);
01938 }
01939 
01940 static VALUE
01941 inspect_ary(VALUE ary, VALUE dummy, int recur)
01942 {
01943     int tainted = OBJ_TAINTED(ary);
01944     int untrust = OBJ_UNTRUSTED(ary);
01945     long i;
01946     VALUE s, str;
01947 
01948     if (recur) return rb_usascii_str_new_cstr("[...]");
01949     str = rb_str_buf_new2("[");
01950     for (i=0; i<RARRAY_LEN(ary); i++) {
01951         s = rb_inspect(RARRAY_PTR(ary)[i]);
01952         if (OBJ_TAINTED(s)) tainted = TRUE;
01953         if (OBJ_UNTRUSTED(s)) untrust = TRUE;
01954         if (i > 0) rb_str_buf_cat2(str, ", ");
01955         else rb_enc_copy(str, s);
01956         rb_str_buf_append(str, s);
01957     }
01958     rb_str_buf_cat2(str, "]");
01959     if (tainted) OBJ_TAINT(str);
01960     if (untrust) OBJ_UNTRUST(str);
01961     return str;
01962 }
01963 
01964 /*
01965  *  call-seq:
01966  *     ary.inspect  -> string
01967  *     ary.to_s     -> string
01968  *
01969  *  Creates a string representation of +self+.
01970  *
01971  *     [ "a", "b", "c" ].to_s     #=> "[\"a\", \"b\", \"c\"]"
01972  */
01973 
01974 static VALUE
01975 rb_ary_inspect(VALUE ary)
01976 {
01977     if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
01978     return rb_exec_recursive(inspect_ary, ary, 0);
01979 }
01980 
01981 VALUE
01982 rb_ary_to_s(VALUE ary)
01983 {
01984     return rb_ary_inspect(ary);
01985 }
01986 
01987 /*
01988  *  call-seq:
01989  *     ary.to_a     -> ary
01990  *
01991  *  Returns +self+.
01992  *
01993  *  If called on a subclass of Array, converts the receiver to an Array object.
01994  */
01995 
01996 static VALUE
01997 rb_ary_to_a(VALUE ary)
01998 {
01999     if (rb_obj_class(ary) != rb_cArray) {
02000         VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
02001         rb_ary_replace(dup, ary);
02002         return dup;
02003     }
02004     return ary;
02005 }
02006 
02007 /*
02008  *  call-seq:
02009  *     ary.to_ary -> ary
02010  *
02011  *  Returns +self+.
02012  */
02013 
02014 static VALUE
02015 rb_ary_to_ary_m(VALUE ary)
02016 {
02017     return ary;
02018 }
02019 
02020 static void
02021 ary_reverse(VALUE *p1, VALUE *p2)
02022 {
02023     while (p1 < p2) {
02024         VALUE tmp = *p1;
02025         *p1++ = *p2;
02026         *p2-- = tmp;
02027     }
02028 }
02029 
02030 VALUE
02031 rb_ary_reverse(VALUE ary)
02032 {
02033     VALUE *p1, *p2;
02034 
02035     rb_ary_modify(ary);
02036     if (RARRAY_LEN(ary) > 1) {
02037         p1 = RARRAY_PTR(ary);
02038         p2 = p1 + RARRAY_LEN(ary) - 1;  /* points last item */
02039         ary_reverse(p1, p2);
02040     }
02041     return ary;
02042 }
02043 
02044 /*
02045  *  call-seq:
02046  *     ary.reverse!   -> ary
02047  *
02048  *  Reverses +self+ in place.
02049  *
02050  *     a = [ "a", "b", "c" ]
02051  *     a.reverse!       #=> ["c", "b", "a"]
02052  *     a                #=> ["c", "b", "a"]
02053  */
02054 
02055 static VALUE
02056 rb_ary_reverse_bang(VALUE ary)
02057 {
02058     return rb_ary_reverse(ary);
02059 }
02060 
02061 /*
02062  *  call-seq:
02063  *     ary.reverse    -> new_ary
02064  *
02065  *  Returns a new array containing +self+'s elements in reverse order.
02066  *
02067  *     [ "a", "b", "c" ].reverse   #=> ["c", "b", "a"]
02068  *     [ 1 ].reverse               #=> [1]
02069  */
02070 
02071 static VALUE
02072 rb_ary_reverse_m(VALUE ary)
02073 {
02074     long len = RARRAY_LEN(ary);
02075     VALUE dup = rb_ary_new2(len);
02076 
02077     if (len > 0) {
02078         VALUE *p1 = RARRAY_PTR(ary);
02079         VALUE *p2 = RARRAY_PTR(dup) + len - 1;
02080         do *p2-- = *p1++; while (--len > 0);
02081     }
02082     ARY_SET_LEN(dup, RARRAY_LEN(ary));
02083     return dup;
02084 }
02085 
02086 static inline long
02087 rotate_count(long cnt, long len)
02088 {
02089     return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len);
02090 }
02091 
02092 VALUE
02093 rb_ary_rotate(VALUE ary, long cnt)
02094 {
02095     rb_ary_modify(ary);
02096 
02097     if (cnt != 0) {
02098         VALUE *ptr = RARRAY_PTR(ary);
02099         long len = RARRAY_LEN(ary);
02100 
02101         if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) {
02102             --len;
02103             if (cnt < len) ary_reverse(ptr + cnt, ptr + len);
02104             if (--cnt > 0) ary_reverse(ptr, ptr + cnt);
02105             if (len > 0) ary_reverse(ptr, ptr + len);
02106             return ary;
02107         }
02108     }
02109 
02110     return Qnil;
02111 }
02112 
02113 /*
02114  *  call-seq:
02115  *     ary.rotate!(count=1)   -> ary
02116  *
02117  *  Rotates +self+ in place so that the element at +count+ comes first, and
02118  *  returns +self+.
02119  *
02120  *  If +count+ is negative then it rotates in the opposite direction, starting
02121  *  from the end of the array where +-1+ is the last element.
02122  *
02123  *     a = [ "a", "b", "c", "d" ]
02124  *     a.rotate!        #=> ["b", "c", "d", "a"]
02125  *     a                #=> ["b", "c", "d", "a"]
02126  *     a.rotate!(2)     #=> ["d", "a", "b", "c"]
02127  *     a.rotate!(-3)    #=> ["a", "b", "c", "d"]
02128  */
02129 
02130 static VALUE
02131 rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
02132 {
02133     long n = 1;
02134 
02135     switch (argc) {
02136       case 1: n = NUM2LONG(argv[0]);
02137       case 0: break;
02138       default: rb_scan_args(argc, argv, "01", NULL);
02139     }
02140     rb_ary_rotate(ary, n);
02141     return ary;
02142 }
02143 
02144 /*
02145  *  call-seq:
02146  *     ary.rotate(count=1)    -> new_ary
02147  *
02148  *  Returns a new array by rotating +self+ so that the element at +count+ is
02149  *  the first element of the new array.
02150  *
02151  *  If +count+ is negative then it rotates in the opposite direction, starting
02152  *  from the end of +self+ where +-1+ is the last element.
02153  *
02154  *     a = [ "a", "b", "c", "d" ]
02155  *     a.rotate         #=> ["b", "c", "d", "a"]
02156  *     a                #=> ["a", "b", "c", "d"]
02157  *     a.rotate(2)      #=> ["c", "d", "a", "b"]
02158  *     a.rotate(-3)     #=> ["b", "c", "d", "a"]
02159  */
02160 
02161 static VALUE
02162 rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
02163 {
02164     VALUE rotated, *ptr, *ptr2;
02165     long len, cnt = 1;
02166 
02167     switch (argc) {
02168       case 1: cnt = NUM2LONG(argv[0]);
02169       case 0: break;
02170       default: rb_scan_args(argc, argv, "01", NULL);
02171     }
02172 
02173     len = RARRAY_LEN(ary);
02174     rotated = rb_ary_new2(len);
02175     if (len > 0) {
02176         cnt = rotate_count(cnt, len);
02177         ptr = RARRAY_PTR(ary);
02178         ptr2 = RARRAY_PTR(rotated);
02179         len -= cnt;
02180         MEMCPY(ptr2, ptr + cnt, VALUE, len);
02181         MEMCPY(ptr2 + len, ptr, VALUE, cnt);
02182     }
02183     ARY_SET_LEN(rotated, RARRAY_LEN(ary));
02184     return rotated;
02185 }
02186 
02187 struct ary_sort_data {
02188     VALUE ary;
02189     int opt_methods;
02190     int opt_inited;
02191 };
02192 
02193 enum {
02194     sort_opt_Fixnum,
02195     sort_opt_String,
02196     sort_optimizable_count
02197 };
02198 
02199 #define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString)
02200 
02201 #define SORT_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(sort_opt_,type))
02202 #define SORT_OPTIMIZABLE(data, type) \
02203     (((data)->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \
02204      ((data)->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \
02205      (((data)->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \
02206       rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \
02207       ((data)->opt_methods |= SORT_OPTIMIZABLE_BIT(type))))
02208 
02209 static VALUE
02210 sort_reentered(VALUE ary)
02211 {
02212     if (RBASIC(ary)->klass) {
02213         rb_raise(rb_eRuntimeError, "sort reentered");
02214     }
02215     return Qnil;
02216 }
02217 
02218 static int
02219 sort_1(const void *ap, const void *bp, void *dummy)
02220 {
02221     struct ary_sort_data *data = dummy;
02222     VALUE retval = sort_reentered(data->ary);
02223     VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
02224     int n;
02225 
02226     retval = rb_yield_values(2, a, b);
02227     n = rb_cmpint(retval, a, b);
02228     sort_reentered(data->ary);
02229     return n;
02230 }
02231 
02232 static int
02233 sort_2(const void *ap, const void *bp, void *dummy)
02234 {
02235     struct ary_sort_data *data = dummy;
02236     VALUE retval = sort_reentered(data->ary);
02237     VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
02238     int n;
02239 
02240     if (FIXNUM_P(a) && FIXNUM_P(b) && SORT_OPTIMIZABLE(data, Fixnum)) {
02241         if ((long)a > (long)b) return 1;
02242         if ((long)a < (long)b) return -1;
02243         return 0;
02244     }
02245     if (STRING_P(a) && STRING_P(b) && SORT_OPTIMIZABLE(data, String)) {
02246         return rb_str_cmp(a, b);
02247     }
02248 
02249     retval = rb_funcall(a, id_cmp, 1, b);
02250     n = rb_cmpint(retval, a, b);
02251     sort_reentered(data->ary);
02252 
02253     return n;
02254 }
02255 
02256 /*
02257  *  call-seq:
02258  *     ary.sort!                   -> ary
02259  *     ary.sort! { |a, b| block }  -> ary
02260  *
02261  *  Sorts +self+ in place.
02262  *
02263  *  Comparisons for the sort will be done using the <code><=></code> operator
02264  *  or using an optional code block.
02265  *
02266  *  The block must implement a comparison between +a+ and +b+, and return
02267  *  +-1+, when +a+ follows +b+, +0+ when +a+ and +b+ are equivalent, or ++1+
02268  *  if +b+ follows +a+.
02269  *
02270  *  See also Enumerable#sort_by.
02271  *
02272  *     a = [ "d", "a", "e", "c", "b" ]
02273  *     a.sort!                    #=> ["a", "b", "c", "d", "e"]
02274  *     a.sort! { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]
02275  */
02276 
02277 VALUE
02278 rb_ary_sort_bang(VALUE ary)
02279 {
02280     rb_ary_modify(ary);
02281     assert(!ARY_SHARED_P(ary));
02282     if (RARRAY_LEN(ary) > 1) {
02283         VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
02284         struct ary_sort_data data;
02285         long len = RARRAY_LEN(ary);
02286 
02287         RBASIC(tmp)->klass = 0;
02288         data.ary = tmp;
02289         data.opt_methods = 0;
02290         data.opt_inited = 0;
02291         ruby_qsort(RARRAY_PTR(tmp), len, sizeof(VALUE),
02292                    rb_block_given_p()?sort_1:sort_2, &data);
02293 
02294         if (ARY_EMBED_P(tmp)) {
02295             assert(ARY_EMBED_P(tmp));
02296             if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
02297                 rb_ary_unshare(ary);
02298             }
02299             FL_SET_EMBED(ary);
02300             MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE, ARY_EMBED_LEN(tmp));
02301             ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
02302         }
02303         else {
02304             assert(!ARY_EMBED_P(tmp));
02305             if (ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
02306                 assert(!ARY_EMBED_P(ary));
02307                 FL_UNSET_SHARED(ary);
02308                 ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
02309             }
02310             else {
02311                 assert(!ARY_SHARED_P(tmp));
02312                 if (ARY_EMBED_P(ary)) {
02313                     FL_UNSET_EMBED(ary);
02314                 }
02315                 else if (ARY_SHARED_P(ary)) {
02316                     /* ary might be destructively operated in the given block */
02317                     rb_ary_unshare(ary);
02318                 }
02319                 else {
02320                     xfree(ARY_HEAP_PTR(ary));
02321                 }
02322                 ARY_SET_PTR(ary, RARRAY_PTR(tmp));
02323                 ARY_SET_HEAP_LEN(ary, len);
02324                 ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
02325             }
02326             /* tmp was lost ownership for the ptr */
02327             FL_UNSET(tmp, FL_FREEZE);
02328             FL_SET_EMBED(tmp);
02329             ARY_SET_EMBED_LEN(tmp, 0);
02330             FL_SET(tmp, FL_FREEZE);
02331         }
02332         /* tmp will be GC'ed. */
02333         RBASIC(tmp)->klass = rb_cArray;
02334     }
02335     return ary;
02336 }
02337 
02338 /*
02339  *  call-seq:
02340  *     ary.sort                   -> new_ary
02341  *     ary.sort { |a, b| block }  -> new_ary
02342  *
02343  *  Returns a new array created by sorting +self+.
02344  *
02345  *  Comparisons for the sort will be done using the <code><=></code> operator
02346  *  or using an optional code block.
02347  *
02348  *  The block must implement a comparison between +a+ and +b+, and return
02349  *  +-1+, when +a+ follows +b+, +0+ when +a+ and +b+ are equivalent, or ++1+
02350  *  if +b+ follows +a+.
02351  *
02352  *
02353  *  See also Enumerable#sort_by.
02354  *
02355  *     a = [ "d", "a", "e", "c", "b" ]
02356  *     a.sort                    #=> ["a", "b", "c", "d", "e"]
02357  *     a.sort { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]
02358  */
02359 
02360 VALUE
02361 rb_ary_sort(VALUE ary)
02362 {
02363     ary = rb_ary_dup(ary);
02364     rb_ary_sort_bang(ary);
02365     return ary;
02366 }
02367 
02368 /*
02369  *  call-seq:
02370  *     ary.bsearch {|x| block }  -> elem
02371  *
02372  *  By using binary search, finds a value from this array which meets
02373  *  the given condition in O(log n) where n is the size of the array.
02374  *
02375  *  You can use this method in two use cases: a find-minimum mode and
02376  *  a find-any mode.  In either case, the elements of the array must be
02377  *  monotone (or sorted) with respect to the block.
02378  *
02379  *  In find-minimum mode (this is a good choice for typical use case),
02380  *  the block must return true or false, and there must be an index i
02381  *  (0 <= i <= ary.size) so that:
02382  *
02383  *  - the block returns false for any element whose index is less than
02384  *    i, and
02385  *  - the block returns true for any element whose index is greater
02386  *    than or equal to i.
02387  *
02388  *  This method returns the i-th element.  If i is equal to ary.size,
02389  *  it returns nil.
02390  *
02391  *     ary = [0, 4, 7, 10, 12]
02392  *     ary.bsearch {|x| x >=   4 } #=> 4
02393  *     ary.bsearch {|x| x >=   6 } #=> 7
02394  *     ary.bsearch {|x| x >=  -1 } #=> 0
02395  *     ary.bsearch {|x| x >= 100 } #=> nil
02396  *
02397  *  In find-any mode (this behaves like libc's bsearch(3)), the block
02398  *  must return a number, and there must be two indices i and j
02399  *  (0 <= i <= j <= ary.size) so that:
02400  *
02401  *  - the block returns a positive number for ary[k] if 0 <= k < i,
02402  *  - the block returns zero for ary[k] if i <= k < j, and
02403  *  - the block returns a negative number for ary[k] if
02404  *    j <= k < ary.size.
02405  *
02406  *  Under this condition, this method returns any element whose index
02407  *  is within i...j.  If i is equal to j (i.e., there is no element
02408  *  that satisfies the block), this method returns nil.
02409  *
02410  *     ary = [0, 4, 7, 10, 12]
02411  *     # try to find v such that 4 <= v < 8
02412  *     ary.bsearch {|x| 1 - x / 4 } #=> 4 or 7
02413  *     # try to find v such that 8 <= v < 10
02414  *     ary.bsearch {|x| 4 - x / 2 } #=> nil
02415  *
02416  *  You must not mix the two modes at a time; the block must always
02417  *  return either true/false, or always return a number.  It is
02418  *  undefined which value is actually picked up at each iteration.
02419  */
02420 
02421 static VALUE
02422 rb_ary_bsearch(VALUE ary)
02423 {
02424     long low = 0, high = RARRAY_LEN(ary), mid;
02425     int smaller = 0, satisfied = 0;
02426     VALUE v, val;
02427 
02428     RETURN_ENUMERATOR(ary, 0, 0);
02429     while (low < high) {
02430         mid = low + ((high - low) / 2);
02431         val = rb_ary_entry(ary, mid);
02432         v = rb_yield(val);
02433         if (FIXNUM_P(v)) {
02434             if (FIX2INT(v) == 0) return val;
02435             smaller = FIX2INT(v) < 0;
02436         }
02437         else if (v == Qtrue) {
02438             satisfied = 1;
02439             smaller = 1;
02440         }
02441         else if (v == Qfalse || v == Qnil) {
02442             smaller = 0;
02443         }
02444         else if (rb_obj_is_kind_of(v, rb_cNumeric)) {
02445             switch (rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0))) {
02446                 case 0: return val;
02447                 case 1: smaller = 1; break;
02448                 case -1: smaller = 0;
02449             }
02450         }
02451         else {
02452             rb_raise(rb_eTypeError, "wrong argument type %s"
02453                 " (must be numeric, true, false or nil)",
02454                 rb_obj_classname(v));
02455         }
02456         if (smaller) {
02457             high = mid;
02458         }
02459         else {
02460             low = mid + 1;
02461         }
02462     }
02463     if (low == RARRAY_LEN(ary)) return Qnil;
02464     if (!satisfied) return Qnil;
02465     return rb_ary_entry(ary, low);
02466 }
02467 
02468 
02469 static VALUE
02470 sort_by_i(VALUE i)
02471 {
02472     return rb_yield(i);
02473 }
02474 
02475 /*
02476  *  call-seq:
02477  *     ary.sort_by! { |obj| block }    -> ary
02478  *     ary.sort_by!                    -> Enumerator
02479  *
02480  *  Sorts +self+ in place using a set of keys generated by mapping the
02481  *  values in +self+ through the given block.
02482  *
02483  *  If no block is given, an Enumerator is returned instead.
02484  *
02485  */
02486 
02487 static VALUE
02488 rb_ary_sort_by_bang(VALUE ary)
02489 {
02490     VALUE sorted;
02491 
02492     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02493     rb_ary_modify(ary);
02494     sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0);
02495     rb_ary_replace(ary, sorted);
02496     return ary;
02497 }
02498 
02499 
02500 /*
02501  *  call-seq:
02502  *     ary.collect { |item| block }  -> new_ary
02503  *     ary.map     { |item| block }  -> new_ary
02504  *     ary.collect                   -> Enumerator
02505  *     ary.map                       -> Enumerator
02506  *
02507  *  Invokes the given block once for each element of +self+.
02508  *
02509  *  Creates a new array containing the values returned by the block.
02510  *
02511  *  See also Enumerable#collect.
02512  *
02513  *  If no block is given, an Enumerator is returned instead.
02514  *
02515  *     a = [ "a", "b", "c", "d" ]
02516  *     a.map { |x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
02517  *     a                       #=> ["a", "b", "c", "d"]
02518  */
02519 
02520 static VALUE
02521 rb_ary_collect(VALUE ary)
02522 {
02523     long i;
02524     VALUE collect;
02525 
02526     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02527     collect = rb_ary_new2(RARRAY_LEN(ary));
02528     for (i = 0; i < RARRAY_LEN(ary); i++) {
02529         rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
02530     }
02531     return collect;
02532 }
02533 
02534 
02535 /*
02536  *  call-seq:
02537  *     ary.collect! {|item| block }   -> ary
02538  *     ary.map!     {|item| block }   -> ary
02539  *     ary.collect!                   -> Enumerator
02540  *     ary.map!                       -> Enumerator
02541  *
02542  *  Invokes the given block once for each element of +self+, replacing the
02543  *  element with the value returned by the block.
02544  *
02545  *  See also Enumerable#collect.
02546  *
02547  *  If no block is given, an Enumerator is returned instead.
02548  *
02549  *     a = [ "a", "b", "c", "d" ]
02550  *     a.map! {|x| x + "!" }
02551  *     a #=>  [ "a!", "b!", "c!", "d!" ]
02552  */
02553 
02554 static VALUE
02555 rb_ary_collect_bang(VALUE ary)
02556 {
02557     long i;
02558 
02559     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02560     rb_ary_modify(ary);
02561     for (i = 0; i < RARRAY_LEN(ary); i++) {
02562         rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
02563     }
02564     return ary;
02565 }
02566 
02567 VALUE
02568 rb_get_values_at(VALUE obj, long olen, int argc, VALUE *argv, VALUE (*func) (VALUE, long))
02569 {
02570     VALUE result = rb_ary_new2(argc);
02571     long beg, len, i, j;
02572 
02573     for (i=0; i<argc; i++) {
02574         if (FIXNUM_P(argv[i])) {
02575             rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
02576             continue;
02577         }
02578         /* check if idx is Range */
02579         if (rb_range_beg_len(argv[i], &beg, &len, olen, 1)) {
02580             long end = olen < beg+len ? olen : beg+len;
02581             for (j = beg; j < end; j++) {
02582                 rb_ary_push(result, (*func)(obj, j));
02583             }
02584             if (beg + len > j)
02585                 rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j);
02586             continue;
02587         }
02588         rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
02589     }
02590     return result;
02591 }
02592 
02593 /*
02594  *  call-seq:
02595  *     ary.values_at(selector, ...)  -> new_ary
02596  *
02597  *  Returns an array containing the elements in +self+ corresponding to the
02598  *  given +selector+(s).
02599  *
02600  *  The selectors may be either integer indices or ranges.
02601  *
02602  *  See also Array#select.
02603  *
02604  *     a = %w{ a b c d e f }
02605  *     a.values_at(1, 3, 5)          # => ["b", "d", "f"]
02606  *     a.values_at(1, 3, 5, 7)       # => ["b", "d", "f", nil]
02607  *     a.values_at(-1, -2, -2, -7)   # => ["f", "e", "e", nil]
02608  *     a.values_at(4..6, 3...6)      # => ["e", "f", nil, "d", "e", "f"]
02609  */
02610 
02611 static VALUE
02612 rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
02613 {
02614     return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry);
02615 }
02616 
02617 
02618 /*
02619  *  call-seq:
02620  *     ary.select { |item| block } -> new_ary
02621  *     ary.select                  -> Enumerator
02622  *
02623  *  Returns a new array containing all elements of +ary+
02624  *  for which the given +block+ returns a true value.
02625  *
02626  *  If no block is given, an Enumerator is returned instead.
02627  *
02628  *     [1,2,3,4,5].select { |num|  num.even?  }   #=> [2, 4]
02629  *
02630  *     a = %w{ a b c d e f }
02631  *     a.select { |v| v =~ /[aeiou]/ }  #=> ["a", "e"]
02632  *
02633  *  See also Enumerable#select.
02634  */
02635 
02636 static VALUE
02637 rb_ary_select(VALUE ary)
02638 {
02639     VALUE result;
02640     long i;
02641 
02642     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02643     result = rb_ary_new2(RARRAY_LEN(ary));
02644     for (i = 0; i < RARRAY_LEN(ary); i++) {
02645         if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
02646             rb_ary_push(result, rb_ary_elt(ary, i));
02647         }
02648     }
02649     return result;
02650 }
02651 
02652 /*
02653  *  call-seq:
02654  *     ary.select!  {|item| block } -> ary or nil
02655  *     ary.select!                  -> Enumerator
02656  *
02657  *  Invokes the given block passing in successive elements from +self+,
02658  *  deleting elements for which the block returns a +false+ value.
02659  *
02660  *  If changes were made, it will return +self+, otherwise it returns +nil+.
02661  *
02662  *  See also Array#keep_if
02663  *
02664  *  If no block is given, an Enumerator is returned instead.
02665  *
02666  */
02667 
02668 static VALUE
02669 rb_ary_select_bang(VALUE ary)
02670 {
02671     long i1, i2;
02672 
02673     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02674     rb_ary_modify(ary);
02675     for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
02676         VALUE v = RARRAY_PTR(ary)[i1];
02677         if (!RTEST(rb_yield(v))) continue;
02678         if (i1 != i2) {
02679             rb_ary_store(ary, i2, v);
02680         }
02681         i2++;
02682     }
02683 
02684     if (RARRAY_LEN(ary) == i2) return Qnil;
02685     if (i2 < RARRAY_LEN(ary))
02686         ARY_SET_LEN(ary, i2);
02687     return ary;
02688 }
02689 
02690 /*
02691  *  call-seq:
02692  *     ary.keep_if { |item| block } -> ary
02693  *     ary.keep_if                  -> Enumerator
02694  *
02695  *  Deletes every element of +self+ for which the given block evaluates to
02696  *  +false+.
02697  *
02698  *  See also Array#select!
02699  *
02700  *  If no block is given, an Enumerator is returned instead.
02701  *
02702  *     a = %w{ a b c d e f }
02703  *     a.keep_if { |v| v =~ /[aeiou]/ }  #=> ["a", "e"]
02704  */
02705 
02706 static VALUE
02707 rb_ary_keep_if(VALUE ary)
02708 {
02709     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02710     rb_ary_select_bang(ary);
02711     return ary;
02712 }
02713 
02714 static void
02715 ary_resize_smaller(VALUE ary, long len)
02716 {
02717     rb_ary_modify(ary);
02718     if (RARRAY_LEN(ary) > len) {
02719         ARY_SET_LEN(ary, len);
02720         if (len * 2 < ARY_CAPA(ary) &&
02721             ARY_CAPA(ary) > ARY_DEFAULT_SIZE) {
02722             ary_resize_capa(ary, len * 2);
02723         }
02724     }
02725 }
02726 
02727 /*
02728  *  call-seq:
02729  *     ary.delete(obj)            -> item or nil
02730  *     ary.delete(obj) { block }  -> item or result of block
02731  *
02732  *  Deletes all items from +self+ that are equal to +obj+.
02733  *
02734  *  Returns the last deleted item, or +nil+ if no matching item is found.
02735  *
02736  *  If the optional code block is given, the result of the block is returned if
02737  *  the item is not found.  (To remove +nil+ elements and get an informative
02738  *  return value, use Array#compact!)
02739  *
02740  *     a = [ "a", "b", "b", "b", "c" ]
02741  *     a.delete("b")                   #=> "b"
02742  *     a                               #=> ["a", "c"]
02743  *     a.delete("z")                   #=> nil
02744  *     a.delete("z") { "not found" }   #=> "not found"
02745  */
02746 
02747 VALUE
02748 rb_ary_delete(VALUE ary, VALUE item)
02749 {
02750     VALUE v = item;
02751     long i1, i2;
02752 
02753     for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
02754         VALUE e = RARRAY_PTR(ary)[i1];
02755 
02756         if (rb_equal(e, item)) {
02757             v = e;
02758             continue;
02759         }
02760         if (i1 != i2) {
02761             rb_ary_store(ary, i2, e);
02762         }
02763         i2++;
02764     }
02765     if (RARRAY_LEN(ary) == i2) {
02766         if (rb_block_given_p()) {
02767             return rb_yield(item);
02768         }
02769         return Qnil;
02770     }
02771 
02772     ary_resize_smaller(ary, i2);
02773 
02774     return v;
02775 }
02776 
02777 void
02778 rb_ary_delete_same(VALUE ary, VALUE item)
02779 {
02780     long i1, i2;
02781 
02782     for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
02783         VALUE e = RARRAY_PTR(ary)[i1];
02784 
02785         if (e == item) {
02786             continue;
02787         }
02788         if (i1 != i2) {
02789             rb_ary_store(ary, i2, e);
02790         }
02791         i2++;
02792     }
02793     if (RARRAY_LEN(ary) == i2) {
02794         return;
02795     }
02796 
02797     ary_resize_smaller(ary, i2);
02798 }
02799 
02800 VALUE
02801 rb_ary_delete_at(VALUE ary, long pos)
02802 {
02803     long len = RARRAY_LEN(ary);
02804     VALUE del;
02805 
02806     if (pos >= len) return Qnil;
02807     if (pos < 0) {
02808         pos += len;
02809         if (pos < 0) return Qnil;
02810     }
02811 
02812     rb_ary_modify(ary);
02813     del = RARRAY_PTR(ary)[pos];
02814     MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
02815             RARRAY_LEN(ary)-pos-1);
02816     ARY_INCREASE_LEN(ary, -1);
02817 
02818     return del;
02819 }
02820 
02821 /*
02822  *  call-seq:
02823  *     ary.delete_at(index)  -> obj or nil
02824  *
02825  *  Deletes the element at the specified +index+, returning that element, or
02826  *  +nil+ if the +index+ is out of range.
02827  *
02828  *  See also Array#slice!
02829  *
02830  *     a = ["ant", "bat", "cat", "dog"]
02831  *     a.delete_at(2)    #=> "cat"
02832  *     a                 #=> ["ant", "bat", "dog"]
02833  *     a.delete_at(99)   #=> nil
02834  */
02835 
02836 static VALUE
02837 rb_ary_delete_at_m(VALUE ary, VALUE pos)
02838 {
02839     return rb_ary_delete_at(ary, NUM2LONG(pos));
02840 }
02841 
02842 /*
02843  *  call-seq:
02844  *     ary.slice!(index)         -> obj or nil
02845  *     ary.slice!(start, length) -> new_ary or nil
02846  *     ary.slice!(range)         -> new_ary or nil
02847  *
02848  *  Deletes the element(s) given by an +index+ (optionally up to +length+
02849  *  elements) or by a +range+.
02850  *
02851  *  Returns the deleted object (or objects), or +nil+ if the +index+ is out of
02852  *  range.
02853  *
02854  *     a = [ "a", "b", "c" ]
02855  *     a.slice!(1)     #=> "b"
02856  *     a               #=> ["a", "c"]
02857  *     a.slice!(-1)    #=> "c"
02858  *     a               #=> ["a"]
02859  *     a.slice!(100)   #=> nil
02860  *     a               #=> ["a"]
02861  */
02862 
02863 static VALUE
02864 rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
02865 {
02866     VALUE arg1, arg2;
02867     long pos, len, orig_len;
02868 
02869     rb_ary_modify_check(ary);
02870     if (argc == 2) {
02871         pos = NUM2LONG(argv[0]);
02872         len = NUM2LONG(argv[1]);
02873       delete_pos_len:
02874         if (len < 0) return Qnil;
02875         orig_len = RARRAY_LEN(ary);
02876         if (pos < 0) {
02877             pos += orig_len;
02878             if (pos < 0) return Qnil;
02879         }
02880         else if (orig_len < pos) return Qnil;
02881         if (orig_len < pos + len) {
02882             len = orig_len - pos;
02883         }
02884         if (len == 0) return rb_ary_new2(0);
02885         arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos);
02886         RBASIC(arg2)->klass = rb_obj_class(ary);
02887         rb_ary_splice(ary, pos, len, Qundef);
02888         return arg2;
02889     }
02890 
02891     if (argc != 1) {
02892         /* error report */
02893         rb_scan_args(argc, argv, "11", NULL, NULL);
02894     }
02895     arg1 = argv[0];
02896 
02897     if (!FIXNUM_P(arg1)) {
02898         switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
02899           case Qtrue:
02900             /* valid range */
02901             goto delete_pos_len;
02902           case Qnil:
02903             /* invalid range */
02904             return Qnil;
02905           default:
02906             /* not a range */
02907             break;
02908         }
02909     }
02910 
02911     return rb_ary_delete_at(ary, NUM2LONG(arg1));
02912 }
02913 
02914 static VALUE
02915 ary_reject(VALUE orig, VALUE result)
02916 {
02917     long i;
02918 
02919     for (i = 0; i < RARRAY_LEN(orig); i++) {
02920         VALUE v = RARRAY_PTR(orig)[i];
02921         if (!RTEST(rb_yield(v))) {
02922             rb_ary_push(result, v);
02923         }
02924     }
02925     return result;
02926 }
02927 
02928 static VALUE
02929 ary_reject_bang(VALUE ary)
02930 {
02931     long i;
02932     VALUE result = Qnil;
02933 
02934     rb_ary_modify_check(ary);
02935     for (i = 0; i < RARRAY_LEN(ary); ) {
02936         VALUE v = RARRAY_PTR(ary)[i];
02937         if (RTEST(rb_yield(v))) {
02938             rb_ary_delete_at(ary, i);
02939             result = ary;
02940         }
02941         else {
02942             i++;
02943         }
02944     }
02945     return result;
02946 }
02947 
02948 /*
02949  *  call-seq:
02950  *     ary.reject! { |item| block }  -> ary or nil
02951  *     ary.reject!                   -> Enumerator
02952  *
02953  *  Equivalent to Array#delete_if, deleting elements from +self+ for which the
02954  *  block evaluates to +true+, but returns +nil+ if no changes were made.
02955  *
02956  *  The array is changed instantly every time the block is called, not after
02957  *  the iteration is over.
02958  *
02959  *  See also Enumerable#reject and Array#delete_if.
02960  *
02961  *  If no block is given, an Enumerator is returned instead.
02962  */
02963 
02964 static VALUE
02965 rb_ary_reject_bang(VALUE ary)
02966 {
02967     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02968     return ary_reject_bang(ary);
02969 }
02970 
02971 /*
02972  *  call-seq:
02973  *     ary.reject  {|item| block }  -> new_ary
02974  *     ary.reject                   -> Enumerator
02975  *
02976  *  Returns a new array containing the items in +self+ for which the given
02977  *  block is not +true+.
02978  *
02979  *  See also Array#delete_if
02980  *
02981  *  If no block is given, an Enumerator is returned instead.
02982  */
02983 
02984 static VALUE
02985 rb_ary_reject(VALUE ary)
02986 {
02987     VALUE rejected_ary;
02988 
02989     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
02990     rejected_ary = rb_ary_new();
02991     ary_reject(ary, rejected_ary);
02992     return rejected_ary;
02993 }
02994 
02995 /*
02996  *  call-seq:
02997  *     ary.delete_if { |item| block }  -> ary
02998  *     ary.delete_if                   -> Enumerator
02999  *
03000  *  Deletes every element of +self+ for which block evaluates to +true+.
03001  *
03002  *  The array is changed instantly every time the block is called, not after
03003  *  the iteration is over.
03004  *
03005  *  See also Array#reject!
03006  *
03007  *  If no block is given, an Enumerator is returned instead.
03008  *
03009  *     a = [ "a", "b", "c" ]
03010  *     a.delete_if {|x| x >= "b" }   #=> ["a"]
03011  */
03012 
03013 static VALUE
03014 rb_ary_delete_if(VALUE ary)
03015 {
03016     RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
03017     ary_reject_bang(ary);
03018     return ary;
03019 }
03020 
03021 static VALUE
03022 take_i(VALUE val, VALUE *args, int argc, VALUE *argv)
03023 {
03024     if (args[1]-- == 0) rb_iter_break();
03025     if (argc > 1) val = rb_ary_new4(argc, argv);
03026     rb_ary_push(args[0], val);
03027     return Qnil;
03028 }
03029 
03030 static VALUE
03031 take_items(VALUE obj, long n)
03032 {
03033     VALUE result = rb_check_array_type(obj);
03034     VALUE args[2];
03035 
03036     if (!NIL_P(result)) return rb_ary_subseq(result, 0, n);
03037     result = rb_ary_new2(n);
03038     args[0] = result; args[1] = (VALUE)n;
03039     if (rb_check_block_call(obj, idEach, 0, 0, take_i, (VALUE)args) == Qundef)
03040         rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
03041             rb_obj_classname(obj));
03042     return result;
03043 }
03044 
03045 
03046 /*
03047  *  call-seq:
03048  *     ary.zip(arg, ...)                  -> new_ary
03049  *     ary.zip(arg, ...) { |arr| block }  -> nil
03050  *
03051  *  Converts any arguments to arrays, then merges elements of +self+ with
03052  *  corresponding elements from each argument.
03053  *
03054  *  This generates a sequence of <code>ary.size</code> _n_-element arrays,
03055  *  where _n_ is one more than the count of arguments.
03056  *
03057  *  If the size of any argument is less than the size of the initial array,
03058  *  +nil+ values are supplied.
03059  *
03060  *  If a block is given, it is invoked for each output +array+, otherwise an
03061  *  array of arrays is returned.
03062  *
03063  *     a = [ 4, 5, 6 ]
03064  *     b = [ 7, 8, 9 ]
03065  *     [1, 2, 3].zip(a, b)   #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
03066  *     [1, 2].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8]]
03067  *     a.zip([1, 2], [8])    #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
03068  */
03069 
03070 static VALUE
03071 rb_ary_zip(int argc, VALUE *argv, VALUE ary)
03072 {
03073     int i, j;
03074     long len;
03075     VALUE result = Qnil;
03076 
03077     len = RARRAY_LEN(ary);
03078     for (i=0; i<argc; i++) {
03079         argv[i] = take_items(argv[i], len);
03080     }
03081     if (!rb_block_given_p()) {
03082         result = rb_ary_new2(len);
03083     }
03084 
03085     for (i=0; i<RARRAY_LEN(ary); i++) {
03086         VALUE tmp = rb_ary_new2(argc+1);
03087 
03088         rb_ary_push(tmp, rb_ary_elt(ary, i));
03089         for (j=0; j<argc; j++) {
03090             rb_ary_push(tmp, rb_ary_elt(argv[j], i));
03091         }
03092         if (NIL_P(result)) {
03093             rb_yield(tmp);
03094         }
03095         else {
03096             rb_ary_push(result, tmp);
03097         }
03098     }
03099     return result;
03100 }
03101 
03102 /*
03103  *  call-seq:
03104  *     ary.transpose -> new_ary
03105  *
03106  *  Assumes that +self+ is an array of arrays and transposes the rows and
03107  *  columns.
03108  *
03109  *     a = [[1,2], [3,4], [5,6]]
03110  *     a.transpose   #=> [[1, 3, 5], [2, 4, 6]]
03111  *
03112  *  If the length of the subarrays don't match, an IndexError is raised.
03113  */
03114 
03115 static VALUE
03116 rb_ary_transpose(VALUE ary)
03117 {
03118     long elen = -1, alen, i, j;
03119     VALUE tmp, result = 0;
03120 
03121     alen = RARRAY_LEN(ary);
03122     if (alen == 0) return rb_ary_dup(ary);
03123     for (i=0; i<alen; i++) {
03124         tmp = to_ary(rb_ary_elt(ary, i));
03125         if (elen < 0) {         /* first element */
03126             elen = RARRAY_LEN(tmp);
03127             result = rb_ary_new2(elen);
03128             for (j=0; j<elen; j++) {
03129                 rb_ary_store(result, j, rb_ary_new2(alen));
03130             }
03131         }
03132         else if (elen != RARRAY_LEN(tmp)) {
03133             rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
03134                      RARRAY_LEN(tmp), elen);
03135         }
03136         for (j=0; j<elen; j++) {
03137             rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
03138         }
03139     }
03140     return result;
03141 }
03142 
03143 /*
03144  *  call-seq:
03145  *     ary.replace(other_ary)  -> ary
03146  *
03147  *  Replaces the contents of +self+ with the contents of +other_ary+,
03148  *  truncating or expanding if necessary.
03149  *
03150  *     a = [ "a", "b", "c", "d", "e" ]
03151  *     a.replace([ "x", "y", "z" ])   #=> ["x", "y", "z"]
03152  *     a                              #=> ["x", "y", "z"]
03153  */
03154 
03155 VALUE
03156 rb_ary_replace(VALUE copy, VALUE orig)
03157 {
03158     rb_ary_modify_check(copy);
03159     orig = to_ary(orig);
03160     if (copy == orig) return copy;
03161 
03162     if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) {
03163         VALUE *ptr;
03164         VALUE shared = 0;
03165 
03166         if (ARY_OWNS_HEAP_P(copy)) {
03167             xfree(RARRAY_PTR(copy));
03168         }
03169         else if (ARY_SHARED_P(copy)) {
03170             shared = ARY_SHARED(copy);
03171             FL_UNSET_SHARED(copy);
03172         }
03173         FL_SET_EMBED(copy);
03174         ptr = RARRAY_PTR(orig);
03175         MEMCPY(RARRAY_PTR(copy), ptr, VALUE, RARRAY_LEN(orig));
03176         if (shared) {
03177             rb_ary_decrement_share(shared);
03178         }
03179         ARY_SET_LEN(copy, RARRAY_LEN(orig));
03180     }
03181     else {
03182         VALUE shared = ary_make_shared(orig);
03183         if (ARY_OWNS_HEAP_P(copy)) {
03184             xfree(RARRAY_PTR(copy));
03185         }
03186         else {
03187             rb_ary_unshare_safe(copy);
03188         }
03189         FL_UNSET_EMBED(copy);
03190         ARY_SET_PTR(copy, RARRAY_PTR(orig));
03191         ARY_SET_LEN(copy, RARRAY_LEN(orig));
03192         rb_ary_set_shared(copy, shared);
03193     }
03194     return copy;
03195 }
03196 
03197 /*
03198  *  call-seq:
03199  *     ary.clear    -> ary
03200  *
03201  *  Removes all elements from +self+.
03202  *
03203  *     a = [ "a", "b", "c", "d", "e" ]
03204  *     a.clear    #=> [ ]
03205  */
03206 
03207 VALUE
03208 rb_ary_clear(VALUE ary)
03209 {
03210     rb_ary_modify_check(ary);
03211     ARY_SET_LEN(ary, 0);
03212     if (ARY_SHARED_P(ary)) {
03213         if (!ARY_EMBED_P(ary)) {
03214             rb_ary_unshare(ary);
03215             FL_SET_EMBED(ary);
03216         }
03217     }
03218     else if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
03219         ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
03220     }
03221     return ary;
03222 }
03223 
03224 /*
03225  *  call-seq:
03226  *     ary.fill(obj)                                 -> ary
03227  *     ary.fill(obj, start [, length])               -> ary
03228  *     ary.fill(obj, range )                         -> ary
03229  *     ary.fill { |index| block }                    -> ary
03230  *     ary.fill(start [, length] ) { |index| block } -> ary
03231  *     ary.fill(range) { |index| block }             -> ary
03232  *
03233  *  The first three forms set the selected elements of +self+ (which
03234  *  may be the entire array) to +obj+.
03235  *
03236  *  A +start+ of +nil+ is equivalent to zero.
03237  *
03238  *  A +length+ of +nil+ is equivalent to the length of the array.
03239  *
03240  *  The last three forms fill the array with the value of the given block,
03241  *  which is passed the absolute index of each element to be filled.
03242  *
03243  *  Negative values of +start+ count from the end of the array, where +-1+ is
03244  *  the last element.
03245  *
03246  *     a = [ "a", "b", "c", "d" ]
03247  *     a.fill("x")              #=> ["x", "x", "x", "x"]
03248  *     a.fill("z", 2, 2)        #=> ["x", "x", "z", "z"]
03249  *     a.fill("y", 0..1)        #=> ["y", "y", "z", "z"]
03250  *     a.fill { |i| i*i }       #=> [0, 1, 4, 9]
03251  *     a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]
03252  */
03253 
03254 static VALUE
03255 rb_ary_fill(int argc, VALUE *argv, VALUE ary)
03256 {
03257     VALUE item, arg1, arg2;
03258     long beg = 0, end = 0, len = 0;
03259     VALUE *p, *pend;
03260     int block_p = FALSE;
03261 
03262     if (rb_block_given_p()) {
03263         block_p = TRUE;
03264         rb_scan_args(argc, argv, "02", &arg1, &arg2);
03265         argc += 1;              /* hackish */
03266     }
03267     else {
03268         rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
03269     }
03270     switch (argc) {
03271       case 1:
03272         beg = 0;
03273         len = RARRAY_LEN(ary);
03274         break;
03275       case 2:
03276         if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
03277             break;
03278         }
03279         /* fall through */
03280       case 3:
03281         beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
03282         if (beg < 0) {
03283             beg = RARRAY_LEN(ary) + beg;
03284             if (beg < 0) beg = 0;
03285         }
03286         len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
03287         break;
03288     }
03289     rb_ary_modify(ary);
03290     if (len < 0) {
03291         return ary;
03292     }
03293     if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
03294         rb_raise(rb_eArgError, "argument too big");
03295     }
03296     end = beg + len;
03297     if (RARRAY_LEN(ary) < end) {
03298         if (end >= ARY_CAPA(ary)) {
03299             ary_resize_capa(ary, end);
03300         }
03301         rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary));
03302         ARY_SET_LEN(ary, end);
03303     }
03304 
03305     if (block_p) {
03306         VALUE v;
03307         long i;
03308 
03309         for (i=beg; i<end; i++) {
03310             v = rb_yield(LONG2NUM(i));
03311             if (i>=RARRAY_LEN(ary)) break;
03312             RARRAY_PTR(ary)[i] = v;
03313         }
03314     }
03315     else {
03316         p = RARRAY_PTR(ary) + beg;
03317         pend = p + len;
03318         while (p < pend) {
03319             *p++ = item;
03320         }
03321     }
03322     return ary;
03323 }
03324 
03325 /*
03326  *  call-seq:
03327  *     ary + other_ary   -> new_ary
03328  *
03329  *  Concatenation --- Returns a new array built by concatenating the
03330  *  two arrays together to produce a third array.
03331  *
03332  *     [ 1, 2, 3 ] + [ 4, 5 ]    #=> [ 1, 2, 3, 4, 5 ]
03333  *     a = [ "a", "b", "c" ]
03334  *     a + [ "d", "e", "f" ]
03335  *     a                         #=> [ "a", "b", "c", "d", "e", "f" ]
03336  *
03337  *  See also Array#concat.
03338  */
03339 
03340 VALUE
03341 rb_ary_plus(VALUE x, VALUE y)
03342 {
03343     VALUE z;
03344     long len;
03345 
03346     y = to_ary(y);
03347     len = RARRAY_LEN(x) + RARRAY_LEN(y);
03348     z = rb_ary_new2(len);
03349     MEMCPY(RARRAY_PTR(z), RARRAY_PTR(x), VALUE, RARRAY_LEN(x));
03350     MEMCPY(RARRAY_PTR(z) + RARRAY_LEN(x), RARRAY_PTR(y), VALUE, RARRAY_LEN(y));
03351     ARY_SET_LEN(z, len);
03352     return z;
03353 }
03354 
03355 /*
03356  *  call-seq:
03357  *     ary.concat(other_ary)   -> ary
03358  *
03359  *  Appends the elements of +other_ary+ to +self+.
03360  *
03361  *     [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
03362  *     a = [ 1, 2, 3 ]
03363  *     a.concat( [ 4, 5 ] )
03364  *     a                                 #=> [ 1, 2, 3, 4, 5 ]
03365  *
03366  *  See also Array#+.
03367  */
03368 
03369 VALUE
03370 rb_ary_concat(VALUE x, VALUE y)
03371 {
03372     rb_ary_modify_check(x);
03373     y = to_ary(y);
03374     if (RARRAY_LEN(y) > 0) {
03375         rb_ary_splice(x, RARRAY_LEN(x), 0, y);
03376     }
03377     return x;
03378 }
03379 
03380 
03381 /*
03382  *  call-seq:
03383  *     ary * int     -> new_ary
03384  *     ary * str     -> new_string
03385  *
03386  *  Repetition --- With a String argument, equivalent to
03387  *  <code>ary.join(str)</code>.
03388  *
03389  *  Otherwise, returns a new array built by concatenating the +int+ copies of
03390  *  +self+.
03391  *
03392  *
03393  *     [ 1, 2, 3 ] * 3    #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ]
03394  *     [ 1, 2, 3 ] * ","  #=> "1,2,3"
03395  *
03396  */
03397 
03398 static VALUE
03399 rb_ary_times(VALUE ary, VALUE times)
03400 {
03401     VALUE ary2, tmp, *ptr, *ptr2;
03402     long t, len;
03403 
03404     tmp = rb_check_string_type(times);
03405     if (!NIL_P(tmp)) {
03406         return rb_ary_join(ary, tmp);
03407     }
03408 
03409     len = NUM2LONG(times);
03410     if (len == 0) {
03411         ary2 = ary_new(rb_obj_class(ary), 0);
03412         goto out;
03413     }
03414     if (len < 0) {
03415         rb_raise(rb_eArgError, "negative argument");
03416     }
03417     if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) {
03418         rb_raise(rb_eArgError, "argument too big");
03419     }
03420     len *= RARRAY_LEN(ary);
03421 
03422     ary2 = ary_new(rb_obj_class(ary), len);
03423     ARY_SET_LEN(ary2, len);
03424 
03425     ptr = RARRAY_PTR(ary);
03426     ptr2 = RARRAY_PTR(ary2);
03427     t = RARRAY_LEN(ary);
03428     if (0 < t) {
03429         MEMCPY(ptr2, ptr, VALUE, t);
03430         while (t <= len/2) {
03431             MEMCPY(ptr2+t, ptr2, VALUE, t);
03432             t *= 2;
03433         }
03434         if (t < len) {
03435             MEMCPY(ptr2+t, ptr2, VALUE, len-t);
03436         }
03437     }
03438   out:
03439     OBJ_INFECT(ary2, ary);
03440 
03441     return ary2;
03442 }
03443 
03444 /*
03445  *  call-seq:
03446  *     ary.assoc(obj)   -> new_ary  or  nil
03447  *
03448  *  Searches through an array whose elements are also arrays comparing +obj+
03449  *  with the first element of each contained array using <code>obj.==</code>.
03450  *
03451  *  Returns the first contained array that matches (that is, the first
03452  *  associated array), or +nil+ if no match is found.
03453  *
03454  *  See also Array#rassoc
03455  *
03456  *     s1 = [ "colors", "red", "blue", "green" ]
03457  *     s2 = [ "letters", "a", "b", "c" ]
03458  *     s3 = "foo"
03459  *     a  = [ s1, s2, s3 ]
03460  *     a.assoc("letters")  #=> [ "letters", "a", "b", "c" ]
03461  *     a.assoc("foo")      #=> nil
03462  */
03463 
03464 VALUE
03465 rb_ary_assoc(VALUE ary, VALUE key)
03466 {
03467     long i;
03468     VALUE v;
03469 
03470     for (i = 0; i < RARRAY_LEN(ary); ++i) {
03471         v = rb_check_array_type(RARRAY_PTR(ary)[i]);
03472         if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
03473             rb_equal(RARRAY_PTR(v)[0], key))
03474             return v;
03475     }
03476     return Qnil;
03477 }
03478 
03479 /*
03480  *  call-seq:
03481  *     ary.rassoc(obj) -> new_ary or nil
03482  *
03483  *  Searches through the array whose elements are also arrays.
03484  *
03485  *  Compares +obj+ with the second element of each contained array using
03486  *  <code>obj.==</code>.
03487  *
03488  *  Returns the first contained array that matches +obj+.
03489  *
03490  *  See also Array#assoc.
03491  *
03492  *     a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
03493  *     a.rassoc("two")    #=> [2, "two"]
03494  *     a.rassoc("four")   #=> nil
03495  */
03496 
03497 VALUE
03498 rb_ary_rassoc(VALUE ary, VALUE value)
03499 {
03500     long i;
03501     VALUE v;
03502 
03503     for (i = 0; i < RARRAY_LEN(ary); ++i) {
03504         v = RARRAY_PTR(ary)[i];
03505         if (RB_TYPE_P(v, T_ARRAY) &&
03506             RARRAY_LEN(v) > 1 &&
03507             rb_equal(RARRAY_PTR(v)[1], value))
03508             return v;
03509     }
03510     return Qnil;
03511 }
03512 
03513 static VALUE
03514 recursive_equal(VALUE ary1, VALUE ary2, int recur)
03515 {
03516     long i, len1;
03517     VALUE *p1, *p2;
03518 
03519     if (recur) return Qtrue; /* Subtle! */
03520 
03521     p1 = RARRAY_PTR(ary1);
03522     p2 = RARRAY_PTR(ary2);
03523     len1 = RARRAY_LEN(ary1);
03524 
03525     for (i = 0; i < len1; i++) {
03526         if (*p1 != *p2) {
03527             if (rb_equal(*p1, *p2)) {
03528                 len1 = RARRAY_LEN(ary1);
03529                 if (len1 != RARRAY_LEN(ary2))
03530                     return Qfalse;
03531                 if (len1 < i)
03532                     return Qtrue;
03533                 p1 = RARRAY_PTR(ary1) + i;
03534                 p2 = RARRAY_PTR(ary2) + i;
03535             }
03536             else {
03537                 return Qfalse;
03538             }
03539         }
03540         p1++;
03541         p2++;
03542     }
03543     return Qtrue;
03544 }
03545 
03546 /*
03547  *  call-seq:
03548  *     ary == other_ary   ->   bool
03549  *
03550  *  Equality --- Two arrays are equal if they contain the same number of
03551  *  elements and if each element is equal to (according to Object#==) the
03552  *  corresponding element in +other_ary+.
03553  *
03554  *     [ "a", "c" ]    == [ "a", "c", 7 ]     #=> false
03555  *     [ "a", "c", 7 ] == [ "a", "c", 7 ]     #=> true
03556  *     [ "a", "c", 7 ] == [ "a", "d", "f" ]   #=> false
03557  *
03558  */
03559 
03560 static VALUE
03561 rb_ary_equal(VALUE ary1, VALUE ary2)
03562 {
03563     if (ary1 == ary2) return Qtrue;
03564     if (!RB_TYPE_P(ary2, T_ARRAY)) {
03565         if (!rb_respond_to(ary2, rb_intern("to_ary"))) {
03566             return Qfalse;
03567         }
03568         return rb_equal(ary2, ary1);
03569     }
03570     if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
03571     return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
03572 }
03573 
03574 static VALUE
03575 recursive_eql(VALUE ary1, VALUE ary2, int recur)
03576 {
03577     long i;
03578 
03579     if (recur) return Qtrue; /* Subtle! */
03580     for (i=0; i<RARRAY_LEN(ary1); i++) {
03581         if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
03582             return Qfalse;
03583     }
03584     return Qtrue;
03585 }
03586 
03587 /*
03588  *  call-seq:
03589  *     ary.eql?(other)  -> true or false
03590  *
03591  *  Returns +true+ if +self+ and +other+ are the same object,
03592  *  or are both arrays with the same content (according to Object#eql?).
03593  */
03594 
03595 static VALUE
03596 rb_ary_eql(VALUE ary1, VALUE ary2)
03597 {
03598     if (ary1 == ary2) return Qtrue;
03599     if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
03600     if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
03601     return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
03602 }
03603 
03604 static VALUE
03605 recursive_hash(VALUE ary, VALUE dummy, int recur)
03606 {
03607     long i;
03608     st_index_t h;
03609     VALUE n;
03610 
03611     h = rb_hash_start(RARRAY_LEN(ary));
03612     if (recur) {
03613         h = rb_hash_uint(h, NUM2LONG(rb_hash(rb_cArray)));
03614     }
03615     else {
03616         for (i=0; i<RARRAY_LEN(ary); i++) {
03617             n = rb_hash(RARRAY_PTR(ary)[i]);
03618             h = rb_hash_uint(h, NUM2LONG(n));
03619         }
03620     }
03621     h = rb_hash_end(h);
03622     return LONG2FIX(h);
03623 }
03624 
03625 /*
03626  *  call-seq:
03627  *     ary.hash   -> fixnum
03628  *
03629  *  Compute a hash-code for this array.
03630  *
03631  *  Two arrays with the same content will have the same hash code (and will
03632  *  compare using #eql?).
03633  */
03634 
03635 static VALUE
03636 rb_ary_hash(VALUE ary)
03637 {
03638     return rb_exec_recursive_outer(recursive_hash, ary, 0);
03639 }
03640 
03641 /*
03642  *  call-seq:
03643  *     ary.include?(object)   -> true or false
03644  *
03645  *  Returns +true+ if the given +object+ is present in +self+ (that is, if any
03646  *  element <code>==</code> +object+), otherwise returns +false+.
03647  *
03648  *     a = [ "a", "b", "c" ]
03649  *     a.include?("b")   #=> true
03650  *     a.include?("z")   #=> false
03651  */
03652 
03653 VALUE
03654 rb_ary_includes(VALUE ary, VALUE item)
03655 {
03656     long i;
03657 
03658     for (i=0; i<RARRAY_LEN(ary); i++) {
03659         if (rb_equal(RARRAY_PTR(ary)[i], item)) {
03660             return Qtrue;
03661         }
03662     }
03663     return Qfalse;
03664 }
03665 
03666 
03667 static VALUE
03668 recursive_cmp(VALUE ary1, VALUE ary2, int recur)
03669 {
03670     long i, len;
03671 
03672     if (recur) return Qundef;   /* Subtle! */
03673     len = RARRAY_LEN(ary1);
03674     if (len > RARRAY_LEN(ary2)) {
03675         len = RARRAY_LEN(ary2);
03676     }
03677     for (i=0; i<len; i++) {
03678         VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
03679         if (v != INT2FIX(0)) {
03680             return v;
03681         }
03682     }
03683     return Qundef;
03684 }
03685 
03686 /*
03687  *  call-seq:
03688  *     ary <=> other_ary   ->  -1, 0, +1 or nil
03689  *
03690  *  Comparison --- Returns an integer (+-1+, +0+, or <code>+1</code>) if this
03691  *  array is less than, equal to, or greater than +other_ary+.
03692  *
03693  *  +nil+ is returned if the two values are incomparable.
03694  *
03695  *  Each object in each array is compared (using the <=> operator).
03696  *
03697  *  Arrays are compared in an "element-wise" manner; the first two elements
03698  *  that are not equal will determine the return value for the whole
03699  *  comparison.
03700  *
03701  *  If all the values are equal, then the return is based on a comparison of
03702  *  the array lengths. Thus, two arrays are "equal" according to Array#<=> if,
03703  *  and only if, they have the same length and the value of each element is
03704  *  equal to the value of the corresponding element in the other array.
03705  *
03706  *     [ "a", "a", "c" ]    <=> [ "a", "b", "c" ]   #=> -1
03707  *     [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ]            #=> +1
03708  *
03709  */
03710 
03711 VALUE
03712 rb_ary_cmp(VALUE ary1, VALUE ary2)
03713 {
03714     long len;
03715     VALUE v;
03716 
03717     ary2 = rb_check_array_type(ary2);
03718     if (NIL_P(ary2)) return Qnil;
03719     if (ary1 == ary2) return INT2FIX(0);
03720     v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
03721     if (v != Qundef) return v;
03722     len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
03723     if (len == 0) return INT2FIX(0);
03724     if (len > 0) return INT2FIX(1);
03725     return INT2FIX(-1);
03726 }
03727 
03728 static VALUE
03729 ary_add_hash(VALUE hash, VALUE ary)
03730 {
03731     long i;
03732 
03733     for (i=0; i<RARRAY_LEN(ary); i++) {
03734         rb_hash_aset(hash, RARRAY_PTR(ary)[i], Qtrue);
03735     }
03736     return hash;
03737 }
03738 
03739 static inline VALUE
03740 ary_tmp_hash_new(void)
03741 {
03742     VALUE hash = rb_hash_new();
03743 
03744     RBASIC(hash)->klass = 0;
03745     return hash;
03746 }
03747 
03748 static VALUE
03749 ary_make_hash(VALUE ary)
03750 {
03751     VALUE hash = ary_tmp_hash_new();
03752     return ary_add_hash(hash, ary);
03753 }
03754 
03755 static VALUE
03756 ary_add_hash_by(VALUE hash, VALUE ary)
03757 {
03758     long i;
03759 
03760     for (i = 0; i < RARRAY_LEN(ary); ++i) {
03761         VALUE v = rb_ary_elt(ary, i), k = rb_yield(v);
03762         if (rb_hash_lookup2(hash, k, Qundef) == Qundef) {
03763             rb_hash_aset(hash, k, v);
03764         }
03765     }
03766     return hash;
03767 }
03768 
03769 static VALUE
03770 ary_make_hash_by(VALUE ary)
03771 {
03772     VALUE hash = ary_tmp_hash_new();
03773     return ary_add_hash_by(hash, ary);
03774 }
03775 
03776 static inline void
03777 ary_recycle_hash(VALUE hash)
03778 {
03779     if (RHASH(hash)->ntbl) {
03780         st_table *tbl = RHASH(hash)->ntbl;
03781         RHASH(hash)->ntbl = 0;
03782         st_free_table(tbl);
03783     }
03784     RB_GC_GUARD(hash);
03785 }
03786 
03787 /*
03788  *  call-seq:
03789  *     ary - other_ary    -> new_ary
03790  *
03791  *  Array Difference
03792  *
03793  *  Returns a new array that is a copy of the original array, removing any
03794  *  items that also appear in +other_ary+. The order is preserved from the
03795  *  original array.
03796  *
03797  *  It compares elements using their #hash and #eql? methods for efficiency.
03798  *
03799  *     [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]
03800  *
03801  *  If you need set-like behavior, see the library class Set.
03802  */
03803 
03804 static VALUE
03805 rb_ary_diff(VALUE ary1, VALUE ary2)
03806 {
03807     VALUE ary3;
03808     VALUE hash;
03809     long i;
03810 
03811     hash = ary_make_hash(to_ary(ary2));
03812     ary3 = rb_ary_new();
03813 
03814     for (i=0; i<RARRAY_LEN(ary1); i++) {
03815         if (st_lookup(RHASH_TBL(hash), RARRAY_PTR(ary1)[i], 0)) continue;
03816         rb_ary_push(ary3, rb_ary_elt(ary1, i));
03817     }
03818     ary_recycle_hash(hash);
03819     return ary3;
03820 }
03821 
03822 /*
03823  *  call-seq:
03824  *     ary & other_ary      -> new_ary
03825  *
03826  *  Set Intersection --- Returns a new array containing elements common to the
03827  *  two arrays, excluding any duplicates. The order is preserved from the
03828  *  original array.
03829  *
03830  *  It compares elements using their #hash and #eql? methods for efficiency.
03831  *
03832  *     [ 1, 1, 3, 5 ] & [ 1, 2, 3 ]                 #=> [ 1, 3 ]
03833  *     [ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ]   #=> [ 'a', 'b' ]
03834  *
03835  *  See also Array#uniq.
03836  */
03837 
03838 
03839 static VALUE
03840 rb_ary_and(VALUE ary1, VALUE ary2)
03841 {
03842     VALUE hash, ary3, v;
03843     st_data_t vv;
03844     long i;
03845 
03846     ary2 = to_ary(ary2);
03847     ary3 = rb_ary_new2(RARRAY_LEN(ary1) < RARRAY_LEN(ary2) ?
03848             RARRAY_LEN(ary1) : RARRAY_LEN(ary2));
03849     hash = ary_make_hash(ary2);
03850 
03851     if (RHASH_EMPTY_P(hash))
03852         return ary3;
03853 
03854     for (i=0; i<RARRAY_LEN(ary1); i++) {
03855         vv = (st_data_t)(v = rb_ary_elt(ary1, i));
03856         if (st_delete(RHASH_TBL(hash), &vv, 0)) {
03857             rb_ary_push(ary3, v);
03858         }
03859     }
03860     ary_recycle_hash(hash);
03861 
03862     return ary3;
03863 }
03864 
03865 /*
03866  *  call-seq:
03867  *     ary | other_ary     -> new_ary
03868  *
03869  *  Set Union --- Returns a new array by joining +ary+ with +other_ary+,
03870  *  excluding any duplicates and preserving the order from the original array.
03871  *
03872  *  It compares elements using their #hash and #eql? methods for efficiency.
03873  *
03874  *     [ "a", "b", "c" ] | [ "c", "d", "a" ]    #=> [ "a", "b", "c", "d" ]
03875  *
03876  *  See also Array#uniq.
03877  */
03878 
03879 static VALUE
03880 rb_ary_or(VALUE ary1, VALUE ary2)
03881 {
03882     VALUE hash, ary3, v;
03883     st_data_t vv;
03884     long i;
03885 
03886     ary2 = to_ary(ary2);
03887     ary3 = rb_ary_new2(RARRAY_LEN(ary1)+RARRAY_LEN(ary2));
03888     hash = ary_add_hash(ary_make_hash(ary1), ary2);
03889 
03890     for (i=0; i<RARRAY_LEN(ary1); i++) {
03891         vv = (st_data_t)(v = rb_ary_elt(ary1, i));
03892         if (st_delete(RHASH_TBL(hash), &vv, 0)) {
03893             rb_ary_push(ary3, v);
03894         }
03895     }
03896     for (i=0; i<RARRAY_LEN(ary2); i++) {
03897         vv = (st_data_t)(v = rb_ary_elt(ary2, i));
03898         if (st_delete(RHASH_TBL(hash), &vv, 0)) {
03899             rb_ary_push(ary3, v);
03900         }
03901     }
03902     ary_recycle_hash(hash);
03903     return ary3;
03904 }
03905 
03906 static int
03907 push_value(st_data_t key, st_data_t val, st_data_t ary)
03908 {
03909     rb_ary_push((VALUE)ary, (VALUE)val);
03910     return ST_CONTINUE;
03911 }
03912 
03913 /*
03914  *  call-seq:
03915  *     ary.uniq!                -> ary or nil
03916  *     ary.uniq! { |item| ... } -> ary or nil
03917  *
03918  *  Removes duplicate elements from +self+.
03919  *
03920  *  If a block is given, it will use the return value of the block for
03921  *  comparison.
03922  *
03923  *  It compares values using their #hash and #eql? methods for efficiency.
03924  *
03925  *  Returns +nil+ if no changes are made (that is, no duplicates are found).
03926  *
03927  *     a = [ "a", "a", "b", "b", "c" ]
03928  *     a.uniq!   # => ["a", "b", "c"]
03929  *
03930  *     b = [ "a", "b", "c" ]
03931  *     b.uniq!   # => nil
03932  *
03933  *     c = [["student","sam"], ["student","george"], ["teacher","matz"]]
03934  *     c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]]
03935  *
03936  */
03937 
03938 static VALUE
03939 rb_ary_uniq_bang(VALUE ary)
03940 {
03941     VALUE hash, v;
03942     long i, j;
03943 
03944     rb_ary_modify_check(ary);
03945     if (RARRAY_LEN(ary) <= 1)
03946         return Qnil;
03947     if (rb_block_given_p()) {
03948         hash = ary_make_hash_by(ary);
03949         if (RARRAY_LEN(ary) == (i = RHASH_SIZE(hash))) {
03950             return Qnil;
03951         }
03952         ARY_SET_LEN(ary, 0);
03953         if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
03954             rb_ary_unshare(ary);
03955             FL_SET_EMBED(ary);
03956         }
03957         ary_resize_capa(ary, i);
03958         st_foreach(RHASH_TBL(hash), push_value, ary);
03959     }
03960     else {
03961         hash = ary_make_hash(ary);
03962         if (RARRAY_LEN(ary) == (long)RHASH_SIZE(hash)) {
03963             return Qnil;
03964         }
03965         for (i=j=0; i<RARRAY_LEN(ary); i++) {
03966             st_data_t vv = (st_data_t)(v = rb_ary_elt(ary, i));
03967             if (st_delete(RHASH_TBL(hash), &vv, 0)) {
03968                 rb_ary_store(ary, j++, v);
03969             }
03970         }
03971         ARY_SET_LEN(ary, j);
03972     }
03973     ary_recycle_hash(hash);
03974 
03975     return ary;
03976 }
03977 
03978 /*
03979  *  call-seq:
03980  *     ary.uniq                -> new_ary
03981  *     ary.uniq { |item| ... } -> new_ary
03982  *
03983  *  Returns a new array by removing duplicate values in +self+.
03984  *
03985  *  If a block is given, it will use the return value of the block for comparison.
03986  *
03987  *  It compares values using their #hash and #eql? methods for efficiency.
03988  *
03989  *     a = [ "a", "a", "b", "b", "c" ]
03990  *     a.uniq   # => ["a", "b", "c"]
03991  *
03992  *     b = [["student","sam"], ["student","george"], ["teacher","matz"]]
03993  *     b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]]
03994  *
03995  */
03996 
03997 static VALUE
03998 rb_ary_uniq(VALUE ary)
03999 {
04000     VALUE hash, uniq, v;
04001     long i;
04002 
04003     if (RARRAY_LEN(ary) <= 1)
04004         return rb_ary_dup(ary);
04005     if (rb_block_given_p()) {
04006         hash = ary_make_hash_by(ary);
04007         uniq = ary_new(rb_obj_class(ary), RHASH_SIZE(hash));
04008         st_foreach(RHASH_TBL(hash), push_value, uniq);
04009     }
04010     else {
04011         hash = ary_make_hash(ary);
04012         uniq = ary_new(rb_obj_class(ary), RHASH_SIZE(hash));
04013         for (i=0; i<RARRAY_LEN(ary); i++) {
04014             st_data_t vv = (st_data_t)(v = rb_ary_elt(ary, i));
04015             if (st_delete(RHASH_TBL(hash), &vv, 0)) {
04016                 rb_ary_push(uniq, v);
04017             }
04018         }
04019     }
04020     ary_recycle_hash(hash);
04021 
04022     return uniq;
04023 }
04024 
04025 /*
04026  *  call-seq:
04027  *     ary.compact!    -> ary  or  nil
04028  *
04029  *  Removes +nil+ elements from the array.
04030  *
04031  *  Returns +nil+ if no changes were made, otherwise returns the array.
04032  *
04033  *     [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
04034  *     [ "a", "b", "c" ].compact!           #=> nil
04035  */
04036 
04037 static VALUE
04038 rb_ary_compact_bang(VALUE ary)
04039 {
04040     VALUE *p, *t, *end;
04041     long n;
04042 
04043     rb_ary_modify(ary);
04044     p = t = RARRAY_PTR(ary);
04045     end = p + RARRAY_LEN(ary);
04046 
04047     while (t < end) {
04048         if (NIL_P(*t)) t++;
04049         else *p++ = *t++;
04050     }
04051     n = p - RARRAY_PTR(ary);
04052     if (RARRAY_LEN(ary) == n) {
04053         return Qnil;
04054     }
04055     ARY_SET_LEN(ary, n);
04056     if (n * 2 < ARY_CAPA(ary) && ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
04057         ary_resize_capa(ary, n * 2);
04058     }
04059 
04060     return ary;
04061 }
04062 
04063 /*
04064  *  call-seq:
04065  *     ary.compact     -> new_ary
04066  *
04067  *  Returns a copy of +self+ with all +nil+ elements removed.
04068  *
04069  *     [ "a", nil, "b", nil, "c", nil ].compact
04070  *                       #=> [ "a", "b", "c" ]
04071  */
04072 
04073 static VALUE
04074 rb_ary_compact(VALUE ary)
04075 {
04076     ary = rb_ary_dup(ary);
04077     rb_ary_compact_bang(ary);
04078     return ary;
04079 }
04080 
04081 /*
04082  *  call-seq:
04083  *     ary.count                   -> int
04084  *     ary.count(obj)              -> int
04085  *     ary.count { |item| block }  -> int
04086  *
04087  *  Returns the number of elements.
04088  *
04089  *  If an argument is given, counts the number of elements which equal +obj+
04090  *  using <code>===</code>.
04091  *
04092  *  If a block is given, counts the number of elements for which the block
04093  *  returns a true value.
04094  *
04095  *     ary = [1, 2, 4, 2]
04096  *     ary.count                  #=> 4
04097  *     ary.count(2)               #=> 2
04098  *     ary.count { |x| x%2 == 0 } #=> 3
04099  *
04100  */
04101 
04102 static VALUE
04103 rb_ary_count(int argc, VALUE *argv, VALUE ary)
04104 {
04105     long i, n = 0;
04106 
04107     if (argc == 0) {
04108         VALUE v;
04109 
04110         if (!rb_block_given_p())
04111             return LONG2NUM(RARRAY_LEN(ary));
04112 
04113         for (i = 0; i < RARRAY_LEN(ary); i++) {
04114             v = RARRAY_PTR(ary)[i];
04115             if (RTEST(rb_yield(v))) n++;
04116         }
04117     }
04118     else {
04119         VALUE obj;
04120 
04121         rb_scan_args(argc, argv, "1", &obj);
04122         if (rb_block_given_p()) {
04123             rb_warn("given block not used");
04124         }
04125         for (i = 0; i < RARRAY_LEN(ary); i++) {
04126             if (rb_equal(RARRAY_PTR(ary)[i], obj)) n++;
04127         }
04128     }
04129 
04130     return LONG2NUM(n);
04131 }
04132 
04133 static VALUE
04134 flatten(VALUE ary, int level, int *modified)
04135 {
04136     long i = 0;
04137     VALUE stack, result, tmp, elt;
04138     st_table *memo;
04139     st_data_t id;
04140 
04141     stack = ary_new(0, ARY_DEFAULT_SIZE);
04142     result = ary_new(0, RARRAY_LEN(ary));
04143     memo = st_init_numtable();
04144     st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
04145     *modified = 0;
04146 
04147     while (1) {
04148         while (i < RARRAY_LEN(ary)) {
04149             elt = RARRAY_PTR(ary)[i++];
04150             tmp = rb_check_array_type(elt);
04151             if (RBASIC(result)->klass) {
04152                 rb_raise(rb_eRuntimeError, "flatten reentered");
04153             }
04154             if (NIL_P(tmp) || (level >= 0 && RARRAY_LEN(stack) / 2 >= level)) {
04155                 rb_ary_push(result, elt);
04156             }
04157             else {
04158                 *modified = 1;
04159                 id = (st_data_t)tmp;
04160                 if (st_lookup(memo, id, 0)) {
04161                     st_free_table(memo);
04162                     rb_raise(rb_eArgError, "tried to flatten recursive array");
04163                 }
04164                 st_insert(memo, id, (st_data_t)Qtrue);
04165                 rb_ary_push(stack, ary);
04166                 rb_ary_push(stack, LONG2NUM(i));
04167                 ary = tmp;
04168                 i = 0;
04169             }
04170         }
04171         if (RARRAY_LEN(stack) == 0) {
04172             break;
04173         }
04174         id = (st_data_t)ary;
04175         st_delete(memo, &id, 0);
04176         tmp = rb_ary_pop(stack);
04177         i = NUM2LONG(tmp);
04178         ary = rb_ary_pop(stack);
04179     }
04180 
04181     st_free_table(memo);
04182 
04183     RBASIC(result)->klass = rb_class_of(ary);
04184     return result;
04185 }
04186 
04187 /*
04188  *  call-seq:
04189  *     ary.flatten!        -> ary or nil
04190  *     ary.flatten!(level) -> ary or nil
04191  *
04192  *  Flattens +self+ in place.
04193  *
04194  *  Returns +nil+ if no modifications were made (i.e., the array contains no
04195  *  subarrays.)
04196  *
04197  *  The optional +level+ argument determines the level of recursion to flatten.
04198  *
04199  *     a = [ 1, 2, [3, [4, 5] ] ]
04200  *     a.flatten!   #=> [1, 2, 3, 4, 5]
04201  *     a.flatten!   #=> nil
04202  *     a            #=> [1, 2, 3, 4, 5]
04203  *     a = [ 1, 2, [3, [4, 5] ] ]
04204  *     a.flatten!(1) #=> [1, 2, 3, [4, 5]]
04205  */
04206 
04207 static VALUE
04208 rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
04209 {
04210     int mod = 0, level = -1;
04211     VALUE result, lv;
04212 
04213     rb_scan_args(argc, argv, "01", &lv);
04214     rb_ary_modify_check(ary);
04215     if (!NIL_P(lv)) level = NUM2INT(lv);
04216     if (level == 0) return Qnil;
04217 
04218     result = flatten(ary, level, &mod);
04219     if (mod == 0) {
04220         ary_discard(result);
04221         return Qnil;
04222     }
04223     if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result);
04224     rb_ary_replace(ary, result);
04225     if (mod) ARY_SET_EMBED_LEN(result, 0);
04226 
04227     return ary;
04228 }
04229 
04230 /*
04231  *  call-seq:
04232  *     ary.flatten -> new_ary
04233  *     ary.flatten(level) -> new_ary
04234  *
04235  *  Returns a new array that is a one-dimensional flattening of +self+
04236  *  (recursively).
04237  *
04238  *  That is, for every element that is an array, extract its elements into
04239  *  the new array.
04240  *
04241  *  The optional +level+ argument determines the level of recursion to
04242  *  flatten.
04243  *
04244  *     s = [ 1, 2, 3 ]           #=> [1, 2, 3]
04245  *     t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
04246  *     a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
04247  *     a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
04248  *     a = [ 1, 2, [3, [4, 5] ] ]
04249  *     a.flatten(1)              #=> [1, 2, 3, [4, 5]]
04250  */
04251 
04252 static VALUE
04253 rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
04254 {
04255     int mod = 0, level = -1;
04256     VALUE result, lv;
04257 
04258     rb_scan_args(argc, argv, "01", &lv);
04259     if (!NIL_P(lv)) level = NUM2INT(lv);
04260     if (level == 0) return ary_make_shared_copy(ary);
04261 
04262     result = flatten(ary, level, &mod);
04263     OBJ_INFECT(result, ary);
04264 
04265     return result;
04266 }
04267 
04268 #define OPTHASH_GIVEN_P(opts) \
04269     (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
04270 static VALUE sym_random;
04271 
04272 #define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)
04273 
04274 /*
04275  *  call-seq:
04276  *     ary.shuffle!              -> ary
04277  *     ary.shuffle!(random: rng) -> ary
04278  *
04279  *  Shuffles elements in +self+ in place.
04280  *
04281  *  The optional +rng+ argument will be used as the random number generator.
04282  */
04283 
04284 static VALUE
04285 rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary)
04286 {
04287     VALUE *ptr, opts, *snap_ptr, randgen = rb_cRandom;
04288     long i, snap_len;
04289 
04290     if (OPTHASH_GIVEN_P(opts)) {
04291         randgen = rb_hash_lookup2(opts, sym_random, randgen);
04292     }
04293     rb_check_arity(argc, 0, 0);
04294     rb_ary_modify(ary);
04295     i = RARRAY_LEN(ary);
04296     ptr = RARRAY_PTR(ary);
04297     snap_len = i;
04298     snap_ptr = ptr;
04299     while (i) {
04300         long j = RAND_UPTO(i);
04301         VALUE tmp;
04302         if (snap_len != RARRAY_LEN(ary) || snap_ptr != RARRAY_PTR(ary)) {
04303             rb_raise(rb_eRuntimeError, "modified during shuffle");
04304         }
04305         tmp = ptr[--i];
04306         ptr[i] = ptr[j];
04307         ptr[j] = tmp;
04308     }
04309     return ary;
04310 }
04311 
04312 
04313 /*
04314  *  call-seq:
04315  *     ary.shuffle              -> new_ary
04316  *     ary.shuffle(random: rng) -> new_ary
04317  *
04318  *  Returns a new array with elements of +self+ shuffled.
04319  *
04320  *     a = [ 1, 2, 3 ]           #=> [1, 2, 3]
04321  *     a.shuffle                 #=> [2, 3, 1]
04322  *
04323  *  The optional +rng+ argument will be used as the random number generator.
04324  *
04325  *     a.shuffle(random: Random.new(1))  #=> [1, 3, 2]
04326  */
04327 
04328 static VALUE
04329 rb_ary_shuffle(int argc, VALUE *argv, VALUE ary)
04330 {
04331     ary = rb_ary_dup(ary);
04332     rb_ary_shuffle_bang(argc, argv, ary);
04333     return ary;
04334 }
04335 
04336 
04337 /*
04338  *  call-seq:
04339  *     ary.sample                  -> obj
04340  *     ary.sample(random: rng)     -> obj
04341  *     ary.sample(n)               -> new_ary
04342  *     ary.sample(n, random: rng)  -> new_ary
04343  *
04344  *  Choose a random element or +n+ random elements from the array.
04345  *
04346  *  The elements are chosen by using random and unique indices into the array
04347  *  in order to ensure that an element doesn't repeat itself unless the array
04348  *  already contained duplicate elements.
04349  *
04350  *  If the array is empty the first form returns +nil+ and the second form
04351  *  returns an empty array.
04352  *
04353  *  The optional +rng+ argument will be used as the random number generator.
04354  *
04355  *     a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
04356  *     a.sample         #=> 7
04357  *     a.sample(4)      #=> [6, 4, 2, 5]
04358  */
04359 
04360 
04361 static VALUE
04362 rb_ary_sample(int argc, VALUE *argv, VALUE ary)
04363 {
04364     VALUE nv, result, *ptr;
04365     VALUE opts, randgen = rb_cRandom;
04366     long n, len, i, j, k, idx[10];
04367     long rnds[numberof(idx)];
04368 
04369     if (OPTHASH_GIVEN_P(opts)) {
04370         randgen = rb_hash_lookup2(opts, sym_random, randgen);
04371     }
04372     ptr = RARRAY_PTR(ary);
04373     len = RARRAY_LEN(ary);
04374     if (argc == 0) {
04375         if (len == 0) return Qnil;
04376         if (len == 1) {
04377             i = 0;
04378         }
04379         else {
04380             i = RAND_UPTO(len);
04381             if ((len = RARRAY_LEN(ary)) <= i) return Qnil;
04382             ptr = RARRAY_PTR(ary);
04383         }
04384         return ptr[i];
04385     }
04386     rb_scan_args(argc, argv, "1", &nv);
04387     n = NUM2LONG(nv);
04388     if (n < 0) rb_raise(rb_eArgError, "negative sample number");
04389     if (n > len) n = len;
04390     if (n <= numberof(idx)) {
04391         for (i = 0; i < n; ++i) {
04392             rnds[i] = RAND_UPTO(len - i);
04393         }
04394     }
04395     k = len;
04396     len = RARRAY_LEN(ary);
04397     ptr = RARRAY_PTR(ary);
04398     if (len < k) {
04399         if (n <= numberof(idx)) {
04400             for (i = 0; i < n; ++i) {
04401                 if (rnds[i] >= len) {
04402                     return rb_ary_new2(0);
04403                 }
04404             }
04405         }
04406     }
04407     if (n > len) n = len;
04408     switch (n) {
04409       case 0:
04410         return rb_ary_new2(0);
04411       case 1:
04412         i = rnds[0];
04413         return rb_ary_new4(1, &ptr[i]);
04414       case 2:
04415         i = rnds[0];
04416         j = rnds[1];
04417         if (j >= i) j++;
04418         return rb_ary_new3(2, ptr[i], ptr[j]);
04419       case 3:
04420         i = rnds[0];
04421         j = rnds[1];
04422         k = rnds[2];
04423         {
04424             long l = j, g = i;
04425             if (j >= i) l = i, g = ++j;
04426             if (k >= l && (++k >= g)) ++k;
04427         }
04428         return rb_ary_new3(3, ptr[i], ptr[j], ptr[k]);
04429     }
04430     if (n <= numberof(idx)) {
04431         VALUE *ptr_result;
04432         long sorted[numberof(idx)];
04433         sorted[0] = idx[0] = rnds[0];
04434         for (i=1; i<n; i++) {
04435             k = rnds[i];
04436             for (j = 0; j < i; ++j) {
04437                 if (k < sorted[j]) break;
04438                 ++k;
04439             }
04440             memmove(&sorted[j+1], &sorted[j], sizeof(sorted[0])*(i-j));
04441             sorted[j] = idx[i] = k;
04442         }
04443         result = rb_ary_new2(n);
04444         ptr_result = RARRAY_PTR(result);
04445         for (i=0; i<n; i++) {
04446             ptr_result[i] = ptr[idx[i]];
04447         }
04448     }
04449     else {
04450         VALUE *ptr_result;
04451         result = rb_ary_new4(len, ptr);
04452         RBASIC(result)->klass = 0;
04453         ptr_result = RARRAY_PTR(result);
04454         RB_GC_GUARD(ary);
04455         for (i=0; i<n; i++) {
04456             j = RAND_UPTO(len-i) + i;
04457             nv = ptr_result[j];
04458             ptr_result[j] = ptr_result[i];
04459             ptr_result[i] = nv;
04460         }
04461         RBASIC(result)->klass = rb_cArray;
04462     }
04463     ARY_SET_LEN(result, n);
04464 
04465     return result;
04466 }
04467 
04468 static VALUE
04469 rb_ary_cycle_size(VALUE self, VALUE args)
04470 {
04471     long mul;
04472     VALUE n = Qnil;
04473     if (args && (RARRAY_LEN(args) > 0)) {
04474         n = RARRAY_PTR(args)[0];
04475     }
04476     if (RARRAY_LEN(self) == 0) return INT2FIX(0);
04477     if (n == Qnil) return DBL2NUM(INFINITY);
04478     mul = NUM2LONG(n);
04479     if (mul <= 0) return INT2FIX(0);
04480     return rb_funcall(rb_ary_length(self), '*', 1, LONG2FIX(mul));
04481 }
04482 
04483 /*
04484  *  call-seq:
04485  *     ary.cycle(n=nil) { |obj| block }  -> nil
04486  *     ary.cycle(n=nil)                  -> Enumerator
04487  *
04488  *  Calls the given block for each element +n+ times or forever if +nil+ is
04489  *  given.
04490  *
04491  *  Does nothing if a non-positive number is given or the array is empty.
04492  *
04493  *  Returns +nil+ if the loop has finished without getting interrupted.
04494  *
04495  *  If no block is given, an Enumerator is returned instead.
04496  *
04497  *     a = ["a", "b", "c"]
04498  *     a.cycle { |x| puts x }     # print, a, b, c, a, b, c,.. forever.
04499  *     a.cycle(2) { |x| puts x }  # print, a, b, c, a, b, c.
04500  *
04501  */
04502 
04503 static VALUE
04504 rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
04505 {
04506     long n, i;
04507     VALUE nv = Qnil;
04508 
04509     rb_scan_args(argc, argv, "01", &nv);
04510 
04511     RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size);
04512     if (NIL_P(nv)) {
04513         n = -1;
04514     }
04515     else {
04516         n = NUM2LONG(nv);
04517         if (n <= 0) return Qnil;
04518     }
04519 
04520     while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) {
04521         for (i=0; i<RARRAY_LEN(ary); i++) {
04522             rb_yield(RARRAY_PTR(ary)[i]);
04523         }
04524     }
04525     return Qnil;
04526 }
04527 
04528 #define tmpbuf(n, size) rb_str_tmp_new((n)*(size))
04529 #define tmpbuf_discard(s) (rb_str_resize((s), 0L), RBASIC(s)->klass = rb_cString)
04530 #define tmpary(n) rb_ary_tmp_new(n)
04531 #define tmpary_discard(a) (ary_discard(a), RBASIC(a)->klass = rb_cArray)
04532 
04533 /*
04534  * Build a ruby array of the corresponding values and yield it to the
04535  * associated block.
04536  * Return the class of +values+ for reentry check.
04537  */
04538 static int
04539 yield_indexed_values(const VALUE values, const long r, const long *const p)
04540 {
04541     const VALUE result = rb_ary_new2(r);
04542     VALUE *const result_array = RARRAY_PTR(result);
04543     const VALUE *const values_array = RARRAY_PTR(values);
04544     long i;
04545 
04546     for (i = 0; i < r; i++) result_array[i] = values_array[p[i]];
04547     ARY_SET_LEN(result, r);
04548     rb_yield(result);
04549     return !RBASIC(values)->klass;
04550 }
04551 
04552 /*
04553  * Recursively compute permutations of +r+ elements of the set
04554  * <code>[0..n-1]</code>.
04555  *
04556  * When we have a complete permutation of array indexes, copy the values
04557  * at those indexes into a new array and yield that array.
04558  *
04559  * n: the size of the set
04560  * r: the number of elements in each permutation
04561  * p: the array (of size r) that we're filling in
04562  * index: what index we're filling in now
04563  * used: an array of booleans: whether a given index is already used
04564  * values: the Ruby array that holds the actual values to permute
04565  */
04566 static void
04567 permute0(long n, long r, long *p, long index, char *used, VALUE values)
04568 {
04569     long i;
04570     for (i = 0; i < n; i++) {
04571         if (used[i] == 0) {
04572             p[index] = i;
04573             if (index < r-1) {             /* if not done yet */
04574                 used[i] = 1;               /* mark index used */
04575                 permute0(n, r, p, index+1, /* recurse */
04576                          used, values);
04577                 used[i] = 0;               /* index unused */
04578             }
04579             else {
04580                 if (!yield_indexed_values(values, r, p)) {
04581                     rb_raise(rb_eRuntimeError, "permute reentered");
04582                 }
04583             }
04584         }
04585     }
04586 }
04587 
04588 /*
04589  * Returns the product of from, from-1, ..., from - how_many + 1.
04590  * http://en.wikipedia.org/wiki/Pochhammer_symbol
04591  */
04592 static VALUE
04593 descending_factorial(long from, long how_many)
04594 {
04595     VALUE cnt = LONG2FIX(how_many >= 0);
04596     while (how_many-- > 0) {
04597         cnt = rb_funcall(cnt, '*', 1, LONG2FIX(from--));
04598     }
04599     return cnt;
04600 }
04601 
04602 static VALUE
04603 binomial_coefficient(long comb, long size)
04604 {
04605     if (comb > size-comb) {
04606         comb = size-comb;
04607     }
04608     if (comb < 0) {
04609         return LONG2FIX(0);
04610     }
04611     return rb_funcall(descending_factorial(size, comb), id_div, 1, descending_factorial(comb, comb));
04612 }
04613 
04614 static VALUE
04615 rb_ary_permutation_size(VALUE ary, VALUE args)
04616 {
04617     long n = RARRAY_LEN(ary);
04618     long k = (args && (RARRAY_LEN(args) > 0)) ? NUM2LONG(RARRAY_PTR(args)[0]) : n;
04619 
04620     return descending_factorial(n, k);
04621 }
04622 
04623 /*
04624  *  call-seq:
04625  *     ary.permutation { |p| block }          -> ary
04626  *     ary.permutation                        -> Enumerator
04627  *     ary.permutation(n) { |p| block }       -> ary
04628  *     ary.permutation(n)                     -> Enumerator
04629  *
04630  * When invoked with a block, yield all permutations of length +n+ of the
04631  * elements of the array, then return the array itself.
04632  *
04633  * If +n+ is not specified, yield all permutations of all elements.
04634  *
04635  * The implementation makes no guarantees about the order in which the
04636  * permutations are yielded.
04637  *
04638  * If no block is given, an Enumerator is returned instead.
04639  *
04640  * Examples:
04641  *
04642  *   a = [1, 2, 3]
04643  *   a.permutation.to_a    #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
04644  *   a.permutation(1).to_a #=> [[1],[2],[3]]
04645  *   a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
04646  *   a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
04647  *   a.permutation(0).to_a #=> [[]] # one permutation of length 0
04648  *   a.permutation(4).to_a #=> []   # no permutations of length 4
04649  */
04650 
04651 static VALUE
04652 rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
04653 {
04654     VALUE num;
04655     long r, n, i;
04656 
04657     n = RARRAY_LEN(ary);                  /* Array length */
04658     RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size);   /* Return enumerator if no block */
04659     rb_scan_args(argc, argv, "01", &num);
04660     r = NIL_P(num) ? n : NUM2LONG(num);   /* Permutation size from argument */
04661 
04662     if (r < 0 || n < r) {
04663         /* no permutations: yield nothing */
04664     }
04665     else if (r == 0) { /* exactly one permutation: the zero-length array */
04666         rb_yield(rb_ary_new2(0));
04667     }
04668     else if (r == 1) { /* this is a special, easy case */
04669         for (i = 0; i < RARRAY_LEN(ary); i++) {
04670             rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
04671         }
04672     }
04673     else {             /* this is the general case */
04674         volatile VALUE t0 = tmpbuf(r,sizeof(long));
04675         long *p = (long*)RSTRING_PTR(t0);
04676         volatile VALUE t1 = tmpbuf(n,sizeof(char));
04677         char *used = (char*)RSTRING_PTR(t1);
04678         VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
04679         RBASIC(ary0)->klass = 0;
04680 
04681         MEMZERO(used, char, n); /* initialize array */
04682 
04683         permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */
04684         tmpbuf_discard(t0);
04685         tmpbuf_discard(t1);
04686         RBASIC(ary0)->klass = rb_cArray;
04687     }
04688     return ary;
04689 }
04690 
04691 static VALUE
04692 rb_ary_combination_size(VALUE ary, VALUE args)
04693 {
04694     long n = RARRAY_LEN(ary);
04695     long k = NUM2LONG(RARRAY_PTR(args)[0]);
04696 
04697     return binomial_coefficient(k, n);
04698 }
04699 
04700 /*
04701  *  call-seq:
04702  *     ary.combination(n) { |c| block }    -> ary
04703  *     ary.combination(n)                  -> Enumerator
04704  *
04705  * When invoked with a block, yields all combinations of length +n+ of elements
04706  * from the array and then returns the array itself.
04707  *
04708  * The implementation makes no guarantees about the order in which the
04709  * combinations are yielded.
04710  *
04711  * If no block is given, an Enumerator is returned instead.
04712  *
04713  * Examples:
04714  *
04715  *     a = [1, 2, 3, 4]
04716  *     a.combination(1).to_a  #=> [[1],[2],[3],[4]]
04717  *     a.combination(2).to_a  #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
04718  *     a.combination(3).to_a  #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
04719  *     a.combination(4).to_a  #=> [[1,2,3,4]]
04720  *     a.combination(0).to_a  #=> [[]] # one combination of length 0
04721  *     a.combination(5).to_a  #=> []   # no combinations of length 5
04722  *
04723  */
04724 
04725 static VALUE
04726 rb_ary_combination(VALUE ary, VALUE num)
04727 {
04728     long n, i, len;
04729 
04730     n = NUM2LONG(num);
04731     RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size);
04732     len = RARRAY_LEN(ary);
04733     if (n < 0 || len < n) {
04734         /* yield nothing */
04735     }
04736     else if (n == 0) {
04737         rb_yield(rb_ary_new2(0));
04738     }
04739     else if (n == 1) {
04740         for (i = 0; i < len; i++) {
04741             rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
04742         }
04743     }
04744     else {
04745         VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
04746         volatile VALUE t0;
04747         long *stack = ALLOCV_N(long, t0, n+1);
04748         long lev = 0;
04749 
04750         RBASIC(ary0)->klass = 0;
04751         MEMZERO(stack+1, long, n);
04752         stack[0] = -1;
04753         for (;;) {
04754             for (lev++; lev < n; lev++) {
04755                 stack[lev+1] = stack[lev]+1;
04756             }
04757             if (!yield_indexed_values(ary0, n, stack+1)) {
04758                 rb_raise(rb_eRuntimeError, "combination reentered");
04759             }
04760             do {
04761                 if (lev == 0) goto done;
04762                 stack[lev--]++;
04763             } while (stack[lev+1]+n == len+lev+1);
04764         }
04765     done:
04766         ALLOCV_END(t0);
04767         RBASIC(ary0)->klass = rb_cArray;
04768     }
04769     return ary;
04770 }
04771 
04772 /*
04773  * Recursively compute repeated permutations of +r+ elements of the set
04774  * <code>[0..n-1]</code>.
04775  *
04776  * When we have a complete repeated permutation of array indexes, copy the
04777  * values at those indexes into a new array and yield that array.
04778  *
04779  * n: the size of the set
04780  * r: the number of elements in each permutation
04781  * p: the array (of size r) that we're filling in
04782  * index: what index we're filling in now
04783  * values: the Ruby array that holds the actual values to permute
04784  */
04785 static void
04786 rpermute0(long n, long r, long *p, long index, VALUE values)
04787 {
04788     long i;
04789     for (i = 0; i < n; i++) {
04790         p[index] = i;
04791         if (index < r-1) {              /* if not done yet */
04792             rpermute0(n, r, p, index+1, values); /* recurse */
04793         }
04794         else {
04795             if (!yield_indexed_values(values, r, p)) {
04796                 rb_raise(rb_eRuntimeError, "repeated permute reentered");
04797             }
04798         }
04799     }
04800 }
04801 
04802 static VALUE
04803 rb_ary_repeated_permutation_size(VALUE ary, VALUE args)
04804 {
04805     long n = RARRAY_LEN(ary);
04806     long k = NUM2LONG(RARRAY_PTR(args)[0]);
04807 
04808     if (k < 0) {
04809         return LONG2FIX(0);
04810     }
04811 
04812     return rb_funcall(LONG2NUM(n), id_power, 1, LONG2NUM(k));
04813 }
04814 
04815 /*
04816  *  call-seq:
04817  *     ary.repeated_permutation(n) { |p| block } -> ary
04818  *     ary.repeated_permutation(n)               -> Enumerator
04819  *
04820  * When invoked with a block, yield all repeated permutations of length +n+ of
04821  * the elements of the array, then return the array itself.
04822  *
04823  * The implementation makes no guarantees about the order in which the repeated
04824  * permutations are yielded.
04825  *
04826  * If no block is given, an Enumerator is returned instead.
04827  *
04828  * Examples:
04829  *
04830  *     a = [1, 2]
04831  *     a.repeated_permutation(1).to_a  #=> [[1], [2]]
04832  *     a.repeated_permutation(2).to_a  #=> [[1,1],[1,2],[2,1],[2,2]]
04833  *     a.repeated_permutation(3).to_a  #=> [[1,1,1],[1,1,2],[1,2,1],[1,2,2],
04834  *                                     #    [2,1,1],[2,1,2],[2,2,1],[2,2,2]]
04835  *     a.repeated_permutation(0).to_a  #=> [[]] # one permutation of length 0
04836  */
04837 
04838 static VALUE
04839 rb_ary_repeated_permutation(VALUE ary, VALUE num)
04840 {
04841     long r, n, i;
04842 
04843     n = RARRAY_LEN(ary);                  /* Array length */
04844     RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size);      /* Return Enumerator if no block */
04845     r = NUM2LONG(num);                    /* Permutation size from argument */
04846 
04847     if (r < 0) {
04848         /* no permutations: yield nothing */
04849     }
04850     else if (r == 0) { /* exactly one permutation: the zero-length array */
04851         rb_yield(rb_ary_new2(0));
04852     }
04853     else if (r == 1) { /* this is a special, easy case */
04854         for (i = 0; i < RARRAY_LEN(ary); i++) {
04855             rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
04856         }
04857     }
04858     else {             /* this is the general case */
04859         volatile VALUE t0 = tmpbuf(r, sizeof(long));
04860         long *p = (long*)RSTRING_PTR(t0);
04861         VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
04862         RBASIC(ary0)->klass = 0;
04863 
04864         rpermute0(n, r, p, 0, ary0); /* compute and yield repeated permutations */
04865         tmpbuf_discard(t0);
04866         RBASIC(ary0)->klass = rb_cArray;
04867     }
04868     return ary;
04869 }
04870 
04871 static void
04872 rcombinate0(long n, long r, long *p, long index, long rest, VALUE values)
04873 {
04874     if (rest > 0) {
04875         for (; index < n; ++index) {
04876             p[r-rest] = index;
04877             rcombinate0(n, r, p, index, rest-1, values);
04878         }
04879     }
04880     else {
04881         if (!yield_indexed_values(values, r, p)) {
04882             rb_raise(rb_eRuntimeError, "repeated combination reentered");
04883         }
04884     }
04885 }
04886 
04887 static VALUE
04888 rb_ary_repeated_combination_size(VALUE ary, VALUE args)
04889 {
04890     long n = RARRAY_LEN(ary);
04891     long k = NUM2LONG(RARRAY_PTR(args)[0]);
04892     if (k == 0) {
04893         return LONG2FIX(1);
04894     }
04895     return binomial_coefficient(k, n + k - 1);
04896 }
04897 
04898 /*
04899  *  call-seq:
04900  *     ary.repeated_combination(n) { |c| block } -> ary
04901  *     ary.repeated_combination(n)               -> Enumerator
04902  *
04903  * When invoked with a block, yields all repeated combinations of length +n+ of
04904  * elements from the array and then returns the array itself.
04905  *
04906  * The implementation makes no guarantees about the order in which the repeated
04907  * combinations are yielded.
04908  *
04909  * If no block is given, an Enumerator is returned instead.
04910  *
04911  * Examples:
04912  *
04913  *   a = [1, 2, 3]
04914  *   a.repeated_combination(1).to_a  #=> [[1], [2], [3]]
04915  *   a.repeated_combination(2).to_a  #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
04916  *   a.repeated_combination(3).to_a  #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
04917  *                                   #    [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
04918  *   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],
04919  *                                   #    [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
04920  *                                   #    [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]]
04921  *   a.repeated_combination(0).to_a  #=> [[]] # one combination of length 0
04922  *
04923  */
04924 
04925 static VALUE
04926 rb_ary_repeated_combination(VALUE ary, VALUE num)
04927 {
04928     long n, i, len;
04929 
04930     n = NUM2LONG(num);                 /* Combination size from argument */
04931     RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size);   /* Return enumerator if no block */
04932     len = RARRAY_LEN(ary);
04933     if (n < 0) {
04934         /* yield nothing */
04935     }
04936     else if (n == 0) {
04937         rb_yield(rb_ary_new2(0));
04938     }
04939     else if (n == 1) {
04940         for (i = 0; i < len; i++) {
04941             rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
04942         }
04943     }
04944     else if (len == 0) {
04945         /* yield nothing */
04946     }
04947     else {
04948         volatile VALUE t0 = tmpbuf(n, sizeof(long));
04949         long *p = (long*)RSTRING_PTR(t0);
04950         VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
04951         RBASIC(ary0)->klass = 0;
04952 
04953         rcombinate0(len, n, p, 0, n, ary0); /* compute and yield repeated combinations */
04954         tmpbuf_discard(t0);
04955         RBASIC(ary0)->klass = rb_cArray;
04956     }
04957     return ary;
04958 }
04959 
04960 /*
04961  *  call-seq:
04962  *     ary.product(other_ary, ...)                -> new_ary
04963  *     ary.product(other_ary, ...) { |p| block }  -> ary
04964  *
04965  *  Returns an array of all combinations of elements from all arrays.
04966  *
04967  *  The length of the returned array is the product of the length of +self+ and
04968  *  the argument arrays.
04969  *
04970  *  If given a block, #product will yield all combinations and return +self+
04971  *  instead.
04972  *
04973  *     [1,2,3].product([4,5])     #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
04974  *     [1,2].product([1,2])       #=> [[1,1],[1,2],[2,1],[2,2]]
04975  *     [1,2].product([3,4],[5,6]) #=> [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
04976  *                                #     [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
04977  *     [1,2].product()            #=> [[1],[2]]
04978  *     [1,2].product([])          #=> []
04979  */
04980 
04981 static VALUE
04982 rb_ary_product(int argc, VALUE *argv, VALUE ary)
04983 {
04984     int n = argc+1;    /* How many arrays we're operating on */
04985     volatile VALUE t0 = tmpary(n);
04986     volatile VALUE t1 = tmpbuf(n, sizeof(int));
04987     VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */
04988     int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */
04989     VALUE result = Qnil;      /* The array we'll be returning, when no block given */
04990     long i,j;
04991     long resultlen = 1;
04992 
04993     RBASIC(t0)->klass = 0;
04994     RBASIC(t1)->klass = 0;
04995 
04996     /* initialize the arrays of arrays */
04997     ARY_SET_LEN(t0, n);
04998     arrays[0] = ary;
04999     for (i = 1; i < n; i++) arrays[i] = Qnil;
05000     for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
05001 
05002     /* initialize the counters for the arrays */
05003     for (i = 0; i < n; i++) counters[i] = 0;
05004 
05005     /* Otherwise, allocate and fill in an array of results */
05006     if (rb_block_given_p()) {
05007         /* Make defensive copies of arrays; exit if any is empty */
05008         for (i = 0; i < n; i++) {
05009             if (RARRAY_LEN(arrays[i]) == 0) goto done;
05010             arrays[i] = ary_make_shared_copy(arrays[i]);
05011         }
05012     }
05013     else {
05014         /* Compute the length of the result array; return [] if any is empty */
05015         for (i = 0; i < n; i++) {
05016             long k = RARRAY_LEN(arrays[i]);
05017             if (k == 0) {
05018                 result = rb_ary_new2(0);
05019                 goto done;
05020             }
05021             if (MUL_OVERFLOW_LONG_P(resultlen, k))
05022                 rb_raise(rb_eRangeError, "too big to product");
05023             resultlen *= k;
05024         }
05025         result = rb_ary_new2(resultlen);
05026     }
05027     for (;;) {
05028         int m;
05029         /* fill in one subarray */
05030         VALUE subarray = rb_ary_new2(n);
05031         for (j = 0; j < n; j++) {
05032             rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
05033         }
05034 
05035         /* put it on the result array */
05036         if (NIL_P(result)) {
05037             FL_SET(t0, FL_USER5);
05038             rb_yield(subarray);
05039             if (! FL_TEST(t0, FL_USER5)) {
05040                 rb_raise(rb_eRuntimeError, "product reentered");
05041             }
05042             else {
05043                 FL_UNSET(t0, FL_USER5);
05044             }
05045         }
05046         else {
05047             rb_ary_push(result, subarray);
05048         }
05049 
05050         /*
05051          * Increment the last counter.  If it overflows, reset to 0
05052          * and increment the one before it.
05053          */
05054         m = n-1;
05055         counters[m]++;
05056         while (counters[m] == RARRAY_LEN(arrays[m])) {
05057             counters[m] = 0;
05058             /* If the first counter overflows, we are done */
05059             if (--m < 0) goto done;
05060             counters[m]++;
05061         }
05062     }
05063 done:
05064     tmpary_discard(t0);
05065     tmpbuf_discard(t1);
05066 
05067     return NIL_P(result) ? ary : result;
05068 }
05069 
05070 /*
05071  *  call-seq:
05072  *     ary.take(n)               -> new_ary
05073  *
05074  *  Returns first +n+ elements from the array.
05075  *
05076  *  If a negative number is given, raises an ArgumentError.
05077  *
05078  *  See also Array#drop
05079  *
05080  *     a = [1, 2, 3, 4, 5, 0]
05081  *     a.take(3)             #=> [1, 2, 3]
05082  *
05083  */
05084 
05085 static VALUE
05086 rb_ary_take(VALUE obj, VALUE n)
05087 {
05088     long len = NUM2LONG(n);
05089     if (len < 0) {
05090         rb_raise(rb_eArgError, "attempt to take negative size");
05091     }
05092     return rb_ary_subseq(obj, 0, len);
05093 }
05094 
05095 /*
05096  *  call-seq:
05097  *     ary.take_while { |arr| block }  -> new_ary
05098  *     ary.take_while                  -> Enumerator
05099  *
05100  *  Passes elements to the block until the block returns +nil+ or +false+, then
05101  *  stops iterating and returns an array of all prior elements.
05102  *
05103  *  If no block is given, an Enumerator is returned instead.
05104  *
05105  *  See also Array#drop_while
05106  *
05107  *     a = [1, 2, 3, 4, 5, 0]
05108  *     a.take_while { |i| i < 3 }  #=> [1, 2]
05109  *
05110  */
05111 
05112 static VALUE
05113 rb_ary_take_while(VALUE ary)
05114 {
05115     long i;
05116 
05117     RETURN_ENUMERATOR(ary, 0, 0);
05118     for (i = 0; i < RARRAY_LEN(ary); i++) {
05119         if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break;
05120     }
05121     return rb_ary_take(ary, LONG2FIX(i));
05122 }
05123 
05124 /*
05125  *  call-seq:
05126  *     ary.drop(n)               -> new_ary
05127  *
05128  *  Drops first +n+ elements from +ary+ and returns the rest of the elements in
05129  *  an array.
05130  *
05131  *  If a negative number is given, raises an ArgumentError.
05132  *
05133  *  See also Array#take
05134  *
05135  *     a = [1, 2, 3, 4, 5, 0]
05136  *     a.drop(3)             #=> [4, 5, 0]
05137  *
05138  */
05139 
05140 static VALUE
05141 rb_ary_drop(VALUE ary, VALUE n)
05142 {
05143     VALUE result;
05144     long pos = NUM2LONG(n);
05145     if (pos < 0) {
05146         rb_raise(rb_eArgError, "attempt to drop negative size");
05147     }
05148 
05149     result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary));
05150     if (result == Qnil) result = rb_ary_new();
05151     return result;
05152 }
05153 
05154 /*
05155  *  call-seq:
05156  *     ary.drop_while { |arr| block }   -> new_ary
05157  *     ary.drop_while                  -> Enumerator
05158  *
05159  *  Drops elements up to, but not including, the first element for which the
05160  *  block returns +nil+ or +false+ and returns an array containing the
05161  *  remaining elements.
05162  *
05163  *  If no block is given, an Enumerator is returned instead.
05164  *
05165  *  See also Array#take_while
05166  *
05167  *     a = [1, 2, 3, 4, 5, 0]
05168  *     a.drop_while {|i| i < 3 }   #=> [3, 4, 5, 0]
05169  *
05170  */
05171 
05172 static VALUE
05173 rb_ary_drop_while(VALUE ary)
05174 {
05175     long i;
05176 
05177     RETURN_ENUMERATOR(ary, 0, 0);
05178     for (i = 0; i < RARRAY_LEN(ary); i++) {
05179         if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break;
05180     }
05181     return rb_ary_drop(ary, LONG2FIX(i));
05182 }
05183 
05184 /*
05185  *  Arrays are ordered, integer-indexed collections of any object.
05186  *
05187  *  Array indexing starts at 0, as in C or Java.  A negative index is assumed
05188  *  to be relative to the end of the array---that is, an index of -1 indicates
05189  *  the last element of the array, -2 is the next to last element in the
05190  *  array, and so on.
05191  *
05192  *  == Creating Arrays
05193  *
05194  *  A new array can be created by using the literal constructor
05195  *  <code>[]</code>.  Arrays can contain different types of objects.  For
05196  *  example, the array below contains an Integer, a String and a Float:
05197  *
05198  *     ary = [1, "two", 3.0] #=> [1, "two", 3.0]
05199  *
05200  *  An array can also be created by explicitly calling Array.new with zero, one
05201  *  (the initial size of the Array) or two arguments (the initial size and a
05202  *  default object).
05203  *
05204  *     ary = Array.new    #=> []
05205  *     Array.new(3)       #=> [nil, nil, nil]
05206  *     Array.new(3, true) #=> [true, true, true]
05207  *
05208  *  Note that the second argument populates the array with references to the
05209  *  same object.  Therefore, it is only recommended in cases when you need to
05210  *  instantiate arrays with natively immutable objects such as Symbols,
05211  *  numbers, true or false.
05212  *
05213  *  To create an array with separate objects a block can be passed instead.
05214  *  This method is safe to use with mutable objects such as hashes, strings or
05215  *  other arrays:
05216  *
05217  *     Array.new(4) { Hash.new } #=> [{}, {}, {}, {}]
05218  *
05219  *  This is also a quick way to build up multi-dimensional arrays:
05220  *
05221  *     empty_table = Array.new(3) { Array.new(3) }
05222  *     #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
05223  *
05224  *  An array can also be created by using the Array() method, provided by
05225  *  Kernel, which tries to call #to_ary, then #to_a on its argument.
05226  *
05227  *      Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]]
05228  *
05229  *  == Example Usage
05230  *
05231  *  In addition to the methods it mixes in through the Enumerable module, the
05232  *  Array class has proprietary methods for accessing, searching and otherwise
05233  *  manipulating arrays.
05234  *
05235  *  Some of the more common ones are illustrated below.
05236  *
05237  *  == Accessing Elements
05238  *
05239  *  Elements in an array can be retrieved using the Array#[] method.  It can
05240  *  take a single integer argument (a numeric index), a pair of arguments
05241  *  (start and length) or a range.
05242  *
05243  *     arr = [1, 2, 3, 4, 5, 6]
05244  *     arr[2]    #=> 3
05245  *     arr[100]  #=> nil
05246  *     arr[-3]   #=> 4
05247  *     arr[2, 3] #=> [3, 4, 5]
05248  *     arr[1..4] #=> [2, 3, 4, 5]
05249  *
05250  *  Another way to access a particular array element is by using the #at method
05251  *
05252  *     arr.at(0) #=> 1
05253  *
05254  *  The #slice method works in an identical manner to Array#[].
05255  *
05256  *  To raise an error for indices outside of the array bounds or else to
05257  *  provide a default value when that happens, you can use #fetch.
05258  *
05259  *     arr = ['a', 'b', 'c', 'd', 'e', 'f']
05260  *     arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6
05261  *     arr.fetch(100, "oops") #=> "oops"
05262  *
05263  *  The special methods #first and #last will return the first and last
05264  *  elements of an array, respectively.
05265  *
05266  *     arr.first #=> 1
05267  *     arr.last  #=> 6
05268  *
05269  *  To return the first +n+ elements of an array, use #take
05270  *
05271  *     arr.take(3) #=> [1, 2, 3]
05272  *
05273  *  #drop does the opposite of #take, by returning the elements after +n+
05274  *  elements have been dropped:
05275  *
05276  *     arr.drop(3) #=> [4, 5, 6]
05277  *
05278  *  == Obtaining Information about an Array
05279  *
05280  *  Arrays keep track of their own length at all times.  To query an array
05281  *  about the number of elements it contains, use #length, #count or #size.
05282  *
05283  *    browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE']
05284  *    browsers.length #=> 5
05285  *    browsers.count #=> 5
05286  *
05287  *  To check whether an array contains any elements at all
05288  *
05289  *    browsers.empty? #=> false
05290  *
05291  *  To check whether a particular item is included in the array
05292  *
05293  *    browsers.include?('Konqueror') #=> false
05294  *
05295  *  == Adding Items to Arrays
05296  *
05297  *  Items can be added to the end of an array by using either #push or #<<
05298  *
05299  *    arr = [1, 2, 3, 4]
05300  *    arr.push(5) #=> [1, 2, 3, 4, 5]
05301  *    arr << 6    #=> [1, 2, 3, 4, 5, 6]
05302  *
05303  *  #unshift will add a new item to the beginning of an array.
05304  *
05305  *     arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]
05306  *
05307  *  With #insert you can add a new element to an array at any position.
05308  *
05309  *     arr.insert(3, 'apple')  #=> [0, 1, 2, 'apple', 3, 4, 5, 6]
05310  *
05311  *  Using the #insert method, you can also insert multiple values at once:
05312  *
05313  *     arr.insert(3, 'orange', 'pear', 'grapefruit')
05314  *     #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
05315  *
05316  *  == Removing Items from an Array
05317  *
05318  *  The method #pop removes the last element in an array and returns it:
05319  *
05320  *     arr =  [1, 2, 3, 4, 5, 6]
05321  *     arr.pop #=> 6
05322  *     arr #=> [1, 2, 3, 4, 5]
05323  *
05324  *  To retrieve and at the same time remove the first item, use #shift:
05325  *
05326  *     arr.shift #=> 1
05327  *     arr #=> [2, 3, 4, 5]
05328  *
05329  *  To delete an element at a particular index:
05330  *
05331  *     arr.delete_at(2) #=> 4
05332  *     arr #=> [2, 3, 5]
05333  *
05334  *  To delete a particular element anywhere in an array, use #delete:
05335  *
05336  *     arr = [1, 2, 2, 3]
05337  *     arr.delete(2) #=> [1, 3]
05338  *
05339  *  A useful method if you need to remove +nil+ values from an array is
05340  *  #compact:
05341  *
05342  *     arr = ['foo', 0, nil, 'bar', 7, 'baz', nil]
05343  *     arr.compact  #=> ['foo', 0, 'bar', 7, 'baz']
05344  *     arr          #=> ['foo', 0, nil, 'bar', 7, 'baz', nil]
05345  *     arr.compact! #=> ['foo', 0, 'bar', 7, 'baz']
05346  *     arr          #=> ['foo', 0, 'bar', 7, 'baz']
05347  *
05348  *  Another common need is to remove duplicate elements from an array.
05349  *
05350  *  It has the non-destructive #uniq, and destructive method #uniq!
05351  *
05352  *     arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
05353  *     arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
05354  *
05355  *  == Iterating over Arrays
05356  *
05357  *  Like all classes that include the Enumerable module, Array has an each
05358  *  method, which defines what elements should be iterated over and how.  In
05359  *  case of Array's #each, all elements in the Array instance are yielded to
05360  *  the supplied block in sequence.
05361  *
05362  *  Note that this operation leaves the array unchanged.
05363  *
05364  *     arr = [1, 2, 3, 4, 5]
05365  *     arr.each { |a| print a -= 10, " " }
05366  *     # prints: -9 -8 -7 -6 -5
05367  *     #=> [1, 2, 3, 4, 5]
05368  *
05369  *  Another sometimes useful iterator is #reverse_each which will iterate over
05370  *  the elements in the array in reverse order.
05371  *
05372  *     words = %w[rats live on no evil star]
05373  *     str = ""
05374  *     words.reverse_each { |word| str += "#{word.reverse} " }
05375  *     str #=> "rats live on no evil star "
05376  *
05377  *  The #map method can be used to create a new array based on the original
05378  *  array, but with the values modified by the supplied block:
05379  *
05380  *     arr.map { |a| 2*a }   #=> [2, 4, 6, 8, 10]
05381  *     arr                   #=> [1, 2, 3, 4, 5]
05382  *     arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25]
05383  *     arr                   #=> [1, 4, 9, 16, 25]
05384  *
05385  *  == Selecting Items from an Array
05386  *
05387  *  Elements can be selected from an array according to criteria defined in a
05388  *  block.  The selection can happen in a destructive or a non-destructive
05389  *  manner.  While the destructive operations will modify the array they were
05390  *  called on, the non-destructive methods usually return a new array with the
05391  *  selected elements, but leave the original array unchanged.
05392  *
05393  *  === Non-destructive Selection
05394  *
05395  *     arr = [1, 2, 3, 4, 5, 6]
05396  *     arr.select { |a| a > 3 }     #=> [4, 5, 6]
05397  *     arr.reject { |a| a < 3 }     #=> [3, 4, 5, 6]
05398  *     arr.drop_while { |a| a < 4 } #=> [4, 5, 6]
05399  *     arr                          #=> [1, 2, 3, 4, 5, 6]
05400  *
05401  *  === Destructive Selection
05402  *
05403  *  #select! and #reject! are the corresponding destructive methods to #select
05404  *  and #reject
05405  *
05406  *  Similar to #select vs. #reject, #delete_if and #keep_if have the exact
05407  *  opposite result when supplied with the same block:
05408  *
05409  *     arr.delete_if { |a| a < 4 } #=> [4, 5, 6]
05410  *     arr                         #=> [4, 5, 6]
05411  *
05412  *     arr = [1, 2, 3, 4, 5, 6]
05413  *     arr.keep_if { |a| a < 4 } #=> [1, 2, 3]
05414  *     arr                       #=> [1, 2, 3]
05415  *
05416  */
05417 
05418 void
05419 Init_Array(void)
05420 {
05421 #undef rb_intern
05422 #define rb_intern(str) rb_intern_const(str)
05423 
05424     rb_cArray  = rb_define_class("Array", rb_cObject);
05425     rb_include_module(rb_cArray, rb_mEnumerable);
05426 
05427     rb_define_alloc_func(rb_cArray, empty_ary_alloc);
05428     rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1);
05429     rb_define_singleton_method(rb_cArray, "try_convert", rb_ary_s_try_convert, 1);
05430     rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1);
05431     rb_define_method(rb_cArray, "initialize_copy", rb_ary_replace, 1);
05432 
05433     rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0);
05434     rb_define_alias(rb_cArray,  "to_s", "inspect");
05435     rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0);
05436     rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0);
05437     rb_define_method(rb_cArray, "frozen?",  rb_ary_frozen_p, 0);
05438 
05439     rb_define_method(rb_cArray, "==", rb_ary_equal, 1);
05440     rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1);
05441     rb_define_method(rb_cArray, "hash", rb_ary_hash, 0);
05442 
05443     rb_define_method(rb_cArray, "[]", rb_ary_aref, -1);
05444     rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1);
05445     rb_define_method(rb_cArray, "at", rb_ary_at, 1);
05446     rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1);
05447     rb_define_method(rb_cArray, "first", rb_ary_first, -1);
05448     rb_define_method(rb_cArray, "last", rb_ary_last, -1);
05449     rb_define_method(rb_cArray, "concat", rb_ary_concat, 1);
05450     rb_define_method(rb_cArray, "<<", rb_ary_push, 1);
05451     rb_define_method(rb_cArray, "push", rb_ary_push_m, -1);
05452     rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1);
05453     rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1);
05454     rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
05455     rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
05456     rb_define_method(rb_cArray, "each", rb_ary_each, 0);
05457     rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
05458     rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
05459     rb_define_method(rb_cArray, "length", rb_ary_length, 0);
05460     rb_define_alias(rb_cArray,  "size", "length");
05461     rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
05462     rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
05463     rb_define_method(rb_cArray, "index", rb_ary_index, -1);
05464     rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
05465     rb_define_method(rb_cArray, "join", rb_ary_join_m, -1);
05466     rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0);
05467     rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0);
05468     rb_define_method(rb_cArray, "rotate", rb_ary_rotate_m, -1);
05469     rb_define_method(rb_cArray, "rotate!", rb_ary_rotate_bang, -1);
05470     rb_define_method(rb_cArray, "sort", rb_ary_sort, 0);
05471     rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0);
05472     rb_define_method(rb_cArray, "sort_by!", rb_ary_sort_by_bang, 0);
05473     rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
05474     rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0);
05475     rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
05476     rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0);
05477     rb_define_method(rb_cArray, "select", rb_ary_select, 0);
05478     rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0);
05479     rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0);
05480     rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1);
05481     rb_define_method(rb_cArray, "delete", rb_ary_delete, 1);
05482     rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1);
05483     rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
05484     rb_define_method(rb_cArray, "reject", rb_ary_reject, 0);
05485     rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);
05486     rb_define_method(rb_cArray, "zip", rb_ary_zip, -1);
05487     rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0);
05488     rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);
05489     rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
05490     rb_define_method(rb_cArray, "fill", rb_ary_fill, -1);
05491     rb_define_method(rb_cArray, "include?", rb_ary_includes, 1);
05492     rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1);
05493 
05494     rb_define_method(rb_cArray, "slice", rb_ary_aref, -1);
05495     rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1);
05496 
05497     rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1);
05498     rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1);
05499 
05500     rb_define_method(rb_cArray, "+", rb_ary_plus, 1);
05501     rb_define_method(rb_cArray, "*", rb_ary_times, 1);
05502 
05503     rb_define_method(rb_cArray, "-", rb_ary_diff, 1);
05504     rb_define_method(rb_cArray, "&", rb_ary_and, 1);
05505     rb_define_method(rb_cArray, "|", rb_ary_or, 1);
05506 
05507     rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0);
05508     rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
05509     rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
05510     rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0);
05511     rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
05512     rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
05513     rb_define_method(rb_cArray, "count", rb_ary_count, -1);
05514     rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, -1);
05515     rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, -1);
05516     rb_define_method(rb_cArray, "sample", rb_ary_sample, -1);
05517     rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
05518     rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
05519     rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
05520     rb_define_method(rb_cArray, "repeated_permutation", rb_ary_repeated_permutation, 1);
05521     rb_define_method(rb_cArray, "repeated_combination", rb_ary_repeated_combination, 1);
05522     rb_define_method(rb_cArray, "product", rb_ary_product, -1);
05523 
05524     rb_define_method(rb_cArray, "take", rb_ary_take, 1);
05525     rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0);
05526     rb_define_method(rb_cArray, "drop", rb_ary_drop, 1);
05527     rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
05528     rb_define_method(rb_cArray, "bsearch", rb_ary_bsearch, 0);
05529 
05530     id_cmp = rb_intern("<=>");
05531     sym_random = ID2SYM(rb_intern("random"));
05532     id_div = rb_intern("div");
05533     id_power = rb_intern("**");
05534 }
05535