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