array.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7