Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

array.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   array.c -
00004 
00005   $Author: matz $
00006   $Date: 2005/12/22 07:08:51 $
00007   created at: Fri Aug  6 09:46:12 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00011   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00012 
00013 **********************************************************************/
00014 
00015 #include "ruby.h"
00016 #include "util.h"
00017 #include "st.h"
00018 
00019 VALUE rb_cArray;
00020 static ID id_cmp;
00021 
00022 #define ARY_DEFAULT_SIZE 16
00023 
00024 void
00025 rb_mem_clear(mem, size)
00026     register VALUE *mem;
00027     register long size;
00028 {
00029     while (size--) {
00030         *mem++ = Qnil;
00031     }
00032 }
00033 
00034 static inline void
00035 memfill(mem, size, val)
00036     register VALUE *mem;
00037     register long size;
00038     register VALUE val;
00039 {
00040     while (size--) {
00041         *mem++ = val;
00042     }
00043 }
00044 
00045 #define ARY_TMPLOCK  FL_USER1
00046 
00047 static inline void
00048 rb_ary_modify_check(ary)
00049     VALUE ary;
00050 {
00051     if (OBJ_FROZEN(ary)) rb_error_frozen("array");
00052     if (FL_TEST(ary, ARY_TMPLOCK))
00053         rb_raise(rb_eRuntimeError, "can't modify array during iteration");
00054     if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
00055         rb_raise(rb_eSecurityError, "Insecure: can't modify array");
00056 }
00057 
00058 static void
00059 rb_ary_modify(ary)
00060     VALUE ary;
00061 {
00062     VALUE *ptr;
00063 
00064     rb_ary_modify_check(ary);
00065     if (FL_TEST(ary, ELTS_SHARED)) {
00066         ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
00067         FL_UNSET(ary, ELTS_SHARED);
00068         RARRAY(ary)->aux.capa = RARRAY(ary)->len;
00069         MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
00070         RARRAY(ary)->ptr = ptr;
00071     }
00072 }
00073 
00074 VALUE
00075 rb_ary_freeze(ary)
00076     VALUE ary;
00077 {
00078     return rb_obj_freeze(ary);
00079 }
00080 
00081 /*
00082  *  call-seq:
00083  *     array.frozen?  -> true or false
00084  *
00085  *  Return <code>true</code> if this array is frozen (or temporarily frozen
00086  *  while being sorted).
00087  */
00088 
00089 static VALUE
00090 rb_ary_frozen_p(ary)
00091     VALUE ary;
00092 {
00093     if (OBJ_FROZEN(ary)) return Qtrue;
00094     if (FL_TEST(ary, ARY_TMPLOCK)) return Qtrue;
00095     return Qfalse;
00096 }
00097 
00098 static VALUE ary_alloc (VALUE);
00099 static VALUE
00100 ary_alloc(klass)
00101     VALUE klass;
00102 {
00103     NEWOBJ(ary, struct RArray);
00104     OBJSETUP(ary, klass, T_ARRAY);
00105 
00106     ary->len = 0;
00107     ary->ptr = 0;
00108     ary->aux.capa = 0;
00109 
00110     return (VALUE)ary;
00111 }
00112 
00113 static VALUE
00114 ary_new(klass, len)
00115     VALUE klass;
00116     long len;
00117 {
00118     VALUE ary = ary_alloc(klass);
00119 
00120     if (len < 0) {
00121         rb_raise(rb_eArgError, "negative array size (or size too big)");
00122     }
00123     if (len > 0 && len * sizeof(VALUE) <= len) {
00124         rb_raise(rb_eArgError, "array size too big");
00125     }
00126     if (len == 0) len++;
00127     RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
00128     RARRAY(ary)->aux.capa = len;
00129 
00130     return ary;
00131 }
00132 
00133 VALUE
00134 rb_ary_new2(len)
00135     long len;
00136 {
00137     return ary_new(rb_cArray, len);
00138 }
00139 
00140 
00141 VALUE
00142 rb_ary_new()
00143 {
00144     return rb_ary_new2(ARY_DEFAULT_SIZE);
00145 }
00146 
00147 #ifdef HAVE_STDARG_PROTOTYPES
00148 #include <stdarg.h>
00149 #define va_init_list(a,b) va_start(a,b)
00150 #else
00151 #include <varargs.h>
00152 #define va_init_list(a,b) va_start(a)
00153 #endif
00154 
00155 VALUE
00156 #ifdef HAVE_STDARG_PROTOTYPES
00157 rb_ary_new3(long n, ...)
00158 #else
00159 rb_ary_new3(n, va_alist)
00160     long n;
00161     va_dcl
00162 #endif
00163 {
00164     va_list ar;
00165     VALUE ary;
00166     long i;
00167 
00168     ary = rb_ary_new2(n);
00169 
00170     va_init_list(ar, n);
00171     for (i=0; i<n; i++) {
00172         RARRAY(ary)->ptr[i] = va_arg(ar, VALUE);
00173     }
00174     va_end(ar);
00175 
00176     RARRAY(ary)->len = n;
00177     return ary;
00178 }
00179 
00180 VALUE
00181 rb_ary_new4(n, elts)
00182     long n;
00183     const VALUE *elts;
00184 {
00185     VALUE ary;
00186 
00187     ary = rb_ary_new2(n);
00188     if (n > 0 && elts) {
00189         MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n);
00190     }
00191     RARRAY(ary)->len = n;
00192 
00193     return ary;
00194 }
00195 
00196 VALUE
00197 rb_assoc_new(car, cdr)
00198     VALUE car, cdr;
00199 {
00200     VALUE ary;
00201 
00202     ary = rb_ary_new2(2);
00203     RARRAY(ary)->ptr[0] = car;
00204     RARRAY(ary)->ptr[1] = cdr;
00205     RARRAY(ary)->len = 2;
00206 
00207     return ary;
00208 }
00209 
00210 static VALUE
00211 to_ary(ary)
00212     VALUE ary;
00213 {
00214     return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
00215 }
00216 
00217 VALUE
00218 rb_check_array_type(ary)
00219     VALUE ary;
00220 {
00221     return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
00222 }
00223 
00224 static VALUE rb_ary_replace (VALUE, VALUE);
00225 
00226 /*
00227  *  call-seq:
00228  *     Array.new(size=0, obj=nil)
00229  *     Array.new(array)
00230  *     Array.new(size) {|index| block }
00231  *
00232  *  Returns a new array. In the first form, the new array is
00233  *  empty. In the second it is created with _size_ copies of _obj_
00234  *  (that is, _size_ references to the same
00235  *  _obj_). The third form creates a copy of the array
00236  *  passed as a parameter (the array is generated by calling
00237  *  to_ary  on the parameter). In the last form, an array
00238  *  of the given size is created. Each element in this array is
00239  *  calculated by passing the element's index to the given block and
00240  *  storing the return value.
00241  *
00242  *     Array.new
00243  *     Array.new(2)
00244  *     Array.new(5, "A")
00245  * 
00246  *     # only one copy of the object is created
00247  *     a = Array.new(2, Hash.new)
00248  *     a[0]['cat'] = 'feline'
00249  *     a
00250  *     a[1]['cat'] = 'Felix'
00251  *     a
00252  * 
00253  *     # here multiple copies are created
00254  *     a = Array.new(2) { Hash.new }
00255  *     a[0]['cat'] = 'feline'
00256  *     a
00257  * 
00258  *     squares = Array.new(5) {|i| i*i}
00259  *     squares
00260  * 
00261  *     copy = Array.new(squares)
00262  */
00263 
00264 static VALUE
00265 rb_ary_initialize(argc, argv, ary)
00266     int argc;
00267     VALUE *argv;
00268     VALUE ary;
00269 {
00270     long len;
00271     VALUE size, val;
00272 
00273     if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
00274         RARRAY(ary)->len = 0;
00275         if (rb_block_given_p()) {
00276             rb_warning("given block not used");
00277         }
00278         return ary;
00279     }
00280 
00281     if (argc == 1 && !FIXNUM_P(size)) {
00282         val = rb_check_array_type(size);
00283         if (!NIL_P(val)) {
00284             rb_ary_replace(ary, val);
00285             return ary;
00286         }
00287     }
00288 
00289     len = NUM2LONG(size);
00290     if (len < 0) {
00291         rb_raise(rb_eArgError, "negative array size");
00292     }
00293     if (len > 0 && len * (long)sizeof(VALUE) <= len) {
00294         rb_raise(rb_eArgError, "array size too big");
00295     }
00296     rb_ary_modify(ary);
00297     if (len > RARRAY(ary)->aux.capa) {
00298         REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
00299         RARRAY(ary)->aux.capa = len;
00300     }
00301     if (rb_block_given_p()) {
00302         long i;
00303 
00304         if (argc == 2) {
00305             rb_warn("block supersedes default value argument");
00306         }
00307         for (i=0; i<len; i++) {
00308             rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
00309             RARRAY(ary)->len = i + 1;
00310         }
00311     }
00312     else {
00313         memfill(RARRAY(ary)->ptr, len, val);
00314         RARRAY(ary)->len = len;
00315     }
00316 
00317     return ary;
00318 }
00319 
00320 
00321 /* 
00322 * Returns a new array populated with the given objects. 
00323 *
00324 *   Array.[]( 1, 'a', /^A/ )
00325 *   Array[ 1, 'a', /^A/ ]
00326 *   [ 1, 'a', /^A/ ]
00327 */
00328 
00329 static VALUE
00330 rb_ary_s_create(argc, argv, klass)
00331     int argc;
00332     VALUE *argv;
00333     VALUE klass;
00334 {
00335     VALUE ary = ary_alloc(klass);
00336 
00337     if (argc > 0) {
00338         RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
00339         MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
00340     }
00341     RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc;
00342 
00343     return ary;
00344 }
00345 
00346 void
00347 rb_ary_store(ary, idx, val)
00348     VALUE ary;
00349     long idx;
00350     VALUE val;
00351 {
00352     if (idx < 0) {
00353         idx += RARRAY(ary)->len;
00354         if (idx < 0) {
00355             rb_raise(rb_eIndexError, "index %ld out of array",
00356                     idx - RARRAY(ary)->len);
00357         }
00358     }
00359 
00360     rb_ary_modify(ary);
00361     if (idx >= RARRAY(ary)->aux.capa) {
00362         long new_capa = RARRAY(ary)->aux.capa / 2;
00363 
00364         if (new_capa < ARY_DEFAULT_SIZE) {
00365             new_capa = ARY_DEFAULT_SIZE;
00366         }
00367         new_capa += idx;
00368         if (new_capa * (long)sizeof(VALUE) <= new_capa) {
00369             rb_raise(rb_eArgError, "index too big");
00370         }
00371         REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa);
00372         RARRAY(ary)->aux.capa = new_capa;
00373     }
00374     if (idx > RARRAY(ary)->len) {
00375         rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len,
00376                      idx-RARRAY(ary)->len + 1);
00377     }
00378 
00379     if (idx >= RARRAY(ary)->len) {
00380         RARRAY(ary)->len = idx + 1;
00381     }
00382     RARRAY(ary)->ptr[idx] = val;
00383 }
00384 
00385 /*
00386  *  call-seq:
00387  *     array << obj            -> array
00388  *  
00389  *  Append---Pushes the given object on to the end of this array. This
00390  *  expression returns the array itself, so several appends
00391  *  may be chained together.
00392  *
00393  *     [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
00394  *             #=>  [ 1, 2, "c", "d", [ 3, 4 ] ]
00395  *
00396  */
00397 
00398 VALUE
00399 rb_ary_push(ary, item)
00400     VALUE ary;
00401     VALUE item;
00402 {
00403     rb_ary_store(ary, RARRAY(ary)->len, item);
00404     return ary;
00405 }
00406 
00407 /* 
00408  *  call-seq:
00409  *     array.push(obj, ... )   -> array
00410  *  
00411  *  Append---Pushes the given object(s) on to the end of this array. This
00412  *  expression returns the array itself, so several appends
00413  *  may be chained together.
00414  *
00415  *     a = [ "a", "b", "c" ]
00416  *     a.push("d", "e", "f")  
00417  *             #=> ["a", "b", "c", "d", "e", "f"]
00418  */
00419 
00420 static VALUE
00421 rb_ary_push_m(argc, argv, ary)
00422     int argc;
00423     VALUE *argv;
00424     VALUE ary;
00425 {
00426     while (argc--) {
00427         rb_ary_push(ary, *argv++);
00428     }
00429     return ary;
00430 }
00431 
00432 /*
00433  *  call-seq:
00434  *     array.pop  -> obj or nil
00435  *  
00436  *  Removes the last element from <i>self</i> and returns it, or
00437  *  <code>nil</code> if the array is empty.
00438  *     
00439  *     a = [ "a", "m", "z" ]
00440  *     a.pop   #=> "z"
00441  *     a       #=> ["a", "m"]
00442  */
00443 
00444 VALUE
00445 rb_ary_pop(ary)
00446     VALUE ary;
00447 {
00448     rb_ary_modify_check(ary);
00449     if (RARRAY(ary)->len == 0) return Qnil;
00450     if (!FL_TEST(ary, ELTS_SHARED) &&
00451             RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
00452             RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
00453         RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
00454         REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
00455     }
00456     return RARRAY(ary)->ptr[--RARRAY(ary)->len];
00457 }
00458 
00459 static VALUE
00460 ary_make_shared(ary)
00461     VALUE ary;
00462 {
00463     if (!FL_TEST(ary, ELTS_SHARED)) {
00464         NEWOBJ(shared, struct RArray);
00465         OBJSETUP(shared, rb_cArray, T_ARRAY);
00466 
00467         shared->len = RARRAY(ary)->len;
00468         shared->ptr = RARRAY(ary)->ptr;
00469         shared->aux.capa = RARRAY(ary)->aux.capa;
00470         RARRAY(ary)->aux.shared = (VALUE)shared;
00471         FL_SET(ary, ELTS_SHARED);
00472         OBJ_FREEZE(shared);
00473         return (VALUE)shared;
00474     }
00475     else {
00476         return RARRAY(ary)->aux.shared;
00477     }
00478 }
00479 
00480 /*
00481  *  call-seq:
00482  *     array.shift   ->   obj or nil
00483  *  
00484  *  Returns the first element of <i>self</i> and removes it (shifting all
00485  *  other elements down by one). Returns <code>nil</code> if the array
00486  *  is empty.
00487  *     
00488  *     args = [ "-m", "-q", "filename" ]
00489  *     args.shift   #=> "-m"
00490  *     args         #=> ["-q", "filename"]
00491  */
00492 
00493 VALUE
00494 rb_ary_shift(ary)
00495     VALUE ary;
00496 {
00497     VALUE top;
00498 
00499     rb_ary_modify_check(ary);
00500     if (RARRAY(ary)->len == 0) return Qnil;
00501     top = RARRAY(ary)->ptr[0];
00502     ary_make_shared(ary);
00503     RARRAY(ary)->ptr++;         /* shift ptr */
00504     RARRAY(ary)->len--;
00505 
00506     return top;
00507 }
00508 
00509 VALUE
00510 rb_ary_unshift(ary, item)
00511     VALUE ary, item;
00512 {
00513     rb_ary_modify(ary);
00514     if (RARRAY(ary)->len == RARRAY(ary)->aux.capa) {
00515         long capa_inc = RARRAY(ary)->aux.capa / 2;
00516         if (capa_inc < ARY_DEFAULT_SIZE) {
00517             capa_inc = ARY_DEFAULT_SIZE;
00518         }
00519         RARRAY(ary)->aux.capa += capa_inc;
00520         REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
00521     }
00522 
00523     /* sliding items */
00524     MEMMOVE(RARRAY(ary)->ptr + 1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
00525 
00526     RARRAY(ary)->len++;
00527     RARRAY(ary)->ptr[0] = item;
00528 
00529     return ary;
00530 }
00531 
00532 /*
00533  *  call-seq:
00534  *     array.unshift(obj, ...)  -> array
00535  *  
00536  *  Prepends objects to the front of <i>array</i>.
00537  *  other elements up one.
00538  *     
00539  *     a = [ "b", "c", "d" ]
00540  *     a.unshift("a")   #=> ["a", "b", "c", "d"]
00541  *     a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]
00542  */
00543 
00544 static VALUE
00545 rb_ary_unshift_m(argc, argv, ary)
00546     int argc;
00547     VALUE *argv;
00548     VALUE ary;
00549 {
00550     long len = RARRAY(ary)->len;
00551 
00552     if (argc == 0) return ary;
00553 
00554     /* make rooms by setting the last item */
00555     rb_ary_store(ary, len + argc - 1, Qnil);
00556 
00557     /* sliding items */
00558     MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
00559     MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
00560     
00561     return ary;
00562 }
00563 
00564 /* faster version - use this if you don't need to treat negative offset */
00565 static inline VALUE
00566 rb_ary_elt(ary, offset)
00567     VALUE ary;
00568     long offset;
00569 {
00570     if (RARRAY(ary)->len == 0) return Qnil;
00571     if (offset < 0 || RARRAY(ary)->len <= offset) {
00572         return Qnil;
00573     }
00574     return RARRAY(ary)->ptr[offset];
00575 }
00576 
00577 VALUE
00578 rb_ary_entry(ary, offset)
00579     VALUE ary;
00580     long offset;
00581 {
00582     if (offset < 0) {
00583         offset += RARRAY(ary)->len;
00584     }
00585     return rb_ary_elt(ary, offset);
00586 }
00587 
00588 static VALUE
00589 rb_ary_subseq(ary, beg, len)
00590     VALUE ary;
00591     long beg, len;
00592 {
00593     VALUE klass, ary2, shared;
00594     VALUE *ptr;
00595 
00596     if (beg > RARRAY(ary)->len) return Qnil;
00597     if (beg < 0 || len < 0) return Qnil;
00598 
00599     if (beg + len > RARRAY(ary)->len) {
00600         len = RARRAY(ary)->len - beg;
00601         if (len < 0)
00602             len = 0;
00603     }
00604     klass = rb_obj_class(ary);
00605     if (len == 0) return ary_new(klass, 0);
00606 
00607     shared = ary_make_shared(ary);
00608     ptr = RARRAY(ary)->ptr;
00609     ary2 = ary_alloc(klass);
00610     RARRAY(ary2)->ptr = ptr + beg;
00611     RARRAY(ary2)->len = len;
00612     RARRAY(ary2)->aux.shared = shared;
00613     FL_SET(ary2, ELTS_SHARED);
00614 
00615     return ary2;
00616 }
00617 
00618 /* 
00619  *  call-seq:
00620  *     array[index]                -> obj      or nil
00621  *     array[start, length]        -> an_array or nil
00622  *     array[range]                -> an_array or nil
00623  *     array.slice(index)          -> obj      or nil
00624  *     array.slice(start, length)  -> an_array or nil
00625  *     array.slice(range)          -> an_array or nil
00626  *
00627  *  Element Reference---Returns the element at _index_,
00628  *  or returns a subarray starting at _start_ and
00629  *  continuing for _length_ elements, or returns a subarray
00630  *  specified by _range_.
00631  *  Negative indices count backward from the end of the
00632  *  array (-1 is the last element). Returns nil if the index
00633  *  (or starting index) are out of range.
00634  *
00635  *     a = [ "a", "b", "c", "d", "e" ]
00636  *     a[2] +  a[0] + a[1]    #=> "cab"
00637  *     a[6]                   #=> nil
00638  *     a[1, 2]                #=> [ "b", "c" ]
00639  *     a[1..3]                #=> [ "b", "c", "d" ]
00640  *     a[4..7]                #=> [ "e" ]
00641  *     a[6..10]               #=> nil
00642  *     a[-3, 3]               #=> [ "c", "d", "e" ]
00643  *     # special cases
00644  *     a[5]                   #=> nil
00645  *     a[5, 1]                #=> []
00646  *     a[5..10]               #=> []
00647  *
00648  */
00649 
00650 VALUE
00651 rb_ary_aref(argc, argv, ary)
00652     int argc;
00653     VALUE *argv;
00654     VALUE ary;
00655 {
00656     VALUE arg;
00657     long beg, len;
00658 
00659     if (argc == 2) {
00660         if (SYMBOL_P(argv[0])) {
00661             rb_raise(rb_eTypeError, "Symbol as array index");
00662         }
00663         beg = NUM2LONG(argv[0]);
00664         len = NUM2LONG(argv[1]);
00665         if (beg < 0) {
00666             beg += RARRAY(ary)->len;
00667         }
00668         return rb_ary_subseq(ary, beg, len);
00669     }
00670     if (argc != 1) {
00671         rb_scan_args(argc, argv, "11", 0, 0);
00672     }
00673     arg = argv[0];
00674     /* special case - speeding up */
00675     if (FIXNUM_P(arg)) {
00676         return rb_ary_entry(ary, FIX2LONG(arg));
00677     }
00678     if (SYMBOL_P(arg)) {
00679         rb_raise(rb_eTypeError, "Symbol as array index");
00680     }
00681     /* check if idx is Range */
00682     switch (rb_range_beg_len(arg, &beg, &len, RARRAY(ary)->len, 0)) {
00683       case Qfalse:
00684         break;
00685       case Qnil:
00686         return Qnil;
00687       default:
00688         return rb_ary_subseq(ary, beg, len);
00689     }
00690     return rb_ary_entry(ary, NUM2LONG(arg));
00691 }
00692 
00693 /* 
00694  *  call-seq:
00695  *     array.at(index)   ->   obj  or nil
00696  *
00697  *  Returns the element at _index_. A
00698  *  negative index counts from the end of _self_.  Returns +nil+
00699  *  if the index is out of range. See also <code>Array#[]</code>.
00700  *  (<code>Array#at</code> is slightly faster than <code>Array#[]</code>,
00701  *  as it does not accept ranges and so on.)
00702  *
00703  *     a = [ "a", "b", "c", "d", "e" ]
00704  *     a.at(0)     #=> "a"
00705  *     a.at(-1)    #=> "e"
00706  */
00707 
00708 static VALUE
00709 rb_ary_at(ary, pos)
00710     VALUE ary, pos;
00711 {
00712     return rb_ary_entry(ary, NUM2LONG(pos));
00713 }
00714 
00715 /*
00716  *  call-seq:
00717  *     array.first   ->   obj or nil
00718  *     array.first(n) -> an_array
00719  *
00720  *  Returns the first element, or the first +n+ elements, of the array.
00721  *  If the array is empty, the first form returns <code>nil</code>, and the
00722  *  second form returns an empty array.
00723  *
00724  *     a = [ "q", "r", "s", "t" ]
00725  *     a.first    #=> "q"
00726  *     a.first(1) #=> ["q"]
00727  *     a.first(3) #=> ["q", "r", "s"]
00728  */
00729 
00730 static VALUE
00731 rb_ary_first(argc, argv, ary)
00732     int argc;
00733     VALUE *argv;
00734     VALUE ary;
00735 {
00736     if (argc == 0) {
00737         if (RARRAY(ary)->len == 0) return Qnil;
00738         return RARRAY(ary)->ptr[0];
00739     }
00740     else {
00741         VALUE nv, result;
00742         long n, i;
00743 
00744         rb_scan_args(argc, argv, "01", &nv);
00745         n = NUM2LONG(nv);
00746         if (n > RARRAY(ary)->len) n = RARRAY(ary)->len;
00747         result = rb_ary_new2(n);
00748         for (i=0; i<n; i++) {
00749             rb_ary_push(result, RARRAY(ary)->ptr[i]);
00750         }
00751         return result;
00752     }
00753 }
00754 
00755 /*
00756  *  call-seq:
00757  *     array.last     ->  obj or nil
00758  *     array.last(n)  ->  an_array
00759  *  
00760  *  Returns the last element(s) of <i>self</i>. If the array is empty,
00761  *  the first form returns <code>nil</code>.
00762  *     
00763  *     [ "w", "x", "y", "z" ].last   #=> "z"
00764  */
00765 
00766 static VALUE
00767 rb_ary_last(argc, argv, ary)
00768     int argc;
00769     VALUE *argv;
00770     VALUE ary;
00771 {
00772     if (argc == 0) {
00773         if (RARRAY(ary)->len == 0) return Qnil;
00774         return RARRAY(ary)->ptr[RARRAY(ary)->len-1];
00775     }
00776     else {
00777         VALUE nv, result;
00778         long n, i;
00779 
00780         rb_scan_args(argc, argv, "01", &nv);
00781         n = NUM2LONG(nv);
00782         if (n > RARRAY(ary)->len) n = RARRAY(ary)->len;
00783         result = rb_ary_new2(n);
00784         for (i=RARRAY(ary)->len-n; n--; i++) {
00785             rb_ary_push(result, RARRAY(ary)->ptr[i]);
00786         }
00787         return result;
00788     }
00789 }
00790 
00791 /*
00792  *  call-seq:
00793  *     array.fetch(index)                    -> obj
00794  *     array.fetch(index, default )          -> obj
00795  *     array.fetch(index) {|index| block }   -> obj
00796  *  
00797  *  Tries to return the element at position <i>index</i>. If the index
00798  *  lies outside the array, the first form throws an
00799  *  <code>IndexError</code> exception, the second form returns
00800  *  <i>default</i>, and the third form returns the value of invoking
00801  *  the block, passing in the index. Negative values of <i>index</i>
00802  *  count from the end of the array.
00803  *     
00804  *     a = [ 11, 22, 33, 44 ]
00805  *     a.fetch(1)               #=> 22
00806  *     a.fetch(-1)              #=> 44
00807  *     a.fetch(4, 'cat')        #=> "cat"
00808  *     a.fetch(4) { |i| i*i }   #=> 16
00809  */
00810 
00811 static VALUE
00812 rb_ary_fetch(argc, argv, ary)
00813     int argc;
00814     VALUE *argv;
00815     VALUE ary;
00816 {
00817     VALUE pos, ifnone;
00818     long block_given;
00819     long idx;
00820 
00821     rb_scan_args(argc, argv, "11", &pos, &ifnone);
00822     block_given = rb_block_given_p();
00823     if (block_given && argc == 2) {
00824         rb_warn("block supersedes default value argument");
00825     }
00826     idx = NUM2LONG(pos);
00827 
00828     if (idx < 0) {
00829         idx +=  RARRAY(ary)->len;
00830     }
00831     if (idx < 0 || RARRAY(ary)->len <= idx) {
00832         if (block_given) return rb_yield(pos);
00833         if (argc == 1) {
00834             rb_raise(rb_eIndexError, "index %ld out of array", idx);
00835         }
00836         return ifnone;
00837     }
00838     return RARRAY(ary)->ptr[idx];
00839 }
00840 
00841 /*
00842  *  call-seq:
00843  *     array.index(obj)   ->  int or nil
00844  *  
00845  *  Returns the index of the first object in <i>self</i> such that is 
00846  *  <code>==</code> to <i>obj</i>. Returns <code>nil</code> if
00847  *  no match is found.
00848  *     
00849  *     a = [ "a", "b", "c" ]
00850  *     a.index("b")   #=> 1
00851  *     a.index("z")   #=> nil
00852  */
00853 
00854 static VALUE
00855 rb_ary_index(ary, val)
00856     VALUE ary;
00857     VALUE val;
00858 {
00859     long i;
00860 
00861     for (i=0; i<RARRAY(ary)->len; i++) {
00862         if (rb_equal(RARRAY(ary)->ptr[i], val))
00863             return LONG2NUM(i);
00864     }
00865     return Qnil;
00866 }
00867 
00868 /*
00869  *  call-seq:
00870  *     array.rindex(obj)    ->  int or nil
00871  *  
00872  *  Returns the index of the last object in <i>array</i> 
00873  *  <code>==</code> to <i>obj</i>. Returns <code>nil</code> if
00874  *  no match is found.
00875  *     
00876  *     a = [ "a", "b", "b", "b", "c" ]
00877  *     a.rindex("b")   #=> 3
00878  *     a.rindex("z")   #=> nil
00879  */
00880 
00881 static VALUE
00882 rb_ary_rindex(ary, val)
00883     VALUE ary;
00884     VALUE val;
00885 {
00886     long i = RARRAY(ary)->len;
00887 
00888     while (i--) {
00889         if (i > RARRAY(ary)->len) {
00890             i = RARRAY(ary)->len;
00891             continue;
00892         }
00893         if (rb_equal(RARRAY(ary)->ptr[i], val))
00894             return LONG2NUM(i);
00895     }
00896     return Qnil;
00897 }
00898 
00899 /*
00900  *  call-seq:
00901  *     array.indexes( i1, i2, ... iN )   -> an_array
00902  *     array.indices( i1, i2, ... iN )   -> an_array
00903  *  
00904  *  Deprecated; use <code>Array#values_at</code>.
00905  */
00906 
00907 static VALUE
00908 rb_ary_indexes(argc, argv, ary)
00909     int argc;
00910     VALUE *argv;
00911     VALUE ary;
00912 {
00913     VALUE new_ary;
00914     long i;
00915 
00916     rb_warn("Array#%s is deprecated; use Array#values_at", rb_id2name(rb_frame_last_func()));
00917     new_ary = rb_ary_new2(argc);
00918     for (i=0; i<argc; i++) {
00919         rb_ary_push(new_ary, rb_ary_aref(1, argv+i, ary));
00920     }
00921 
00922     return new_ary;
00923 }
00924 
00925 VALUE
00926 rb_ary_to_ary(obj)
00927     VALUE obj;
00928 {
00929     if (TYPE(obj) == T_ARRAY) {
00930         return obj;
00931     }
00932     if (rb_respond_to(obj, rb_intern("to_ary"))) {
00933         return rb_convert_type(obj, T_ARRAY, "Array", "to_ary");
00934     }
00935     return rb_ary_new3(1, obj);
00936 }
00937 
00938 static void
00939 rb_ary_splice(ary, beg, len, rpl)
00940     VALUE ary;
00941     long beg, len;
00942     VALUE rpl;
00943 {
00944     long rlen;
00945 
00946     if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
00947     if (beg < 0) {
00948         beg += RARRAY(ary)->len;
00949         if (beg < 0) {
00950             beg -= RARRAY(ary)->len;
00951             rb_raise(rb_eIndexError, "index %ld out of array", beg);
00952         }
00953     }
00954     if (beg + len > RARRAY(ary)->len) {
00955         len = RARRAY(ary)->len - beg;
00956     }
00957 
00958     if (NIL_P(rpl)) {
00959         rlen = 0;
00960     }
00961     else {
00962         rpl = rb_ary_to_ary(rpl);
00963         rlen = RARRAY(rpl)->len;
00964     }
00965     rb_ary_modify(ary);
00966 
00967     if (beg >= RARRAY(ary)->len) {
00968         len = beg + rlen;
00969         if (len >= RARRAY(ary)->aux.capa) {
00970             REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
00971             RARRAY(ary)->aux.capa = len;
00972         }
00973         rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, beg - RARRAY(ary)->len);
00974         if (rlen > 0) {
00975             MEMCPY(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
00976         }
00977         RARRAY(ary)->len = len;
00978     }
00979     else {
00980         long alen;
00981 
00982         if (beg + len > RARRAY(ary)->len) {
00983             len = RARRAY(ary)->len - beg;
00984         }
00985 
00986         alen = RARRAY(ary)->len + rlen - len;
00987         if (alen >= RARRAY(ary)->aux.capa) {
00988             REALLOC_N(RARRAY(ary)->ptr, VALUE, alen);
00989             RARRAY(ary)->aux.capa = alen;
00990         }
00991 
00992         if (len != rlen) {
00993             MEMMOVE(RARRAY(ary)->ptr + beg + rlen, RARRAY(ary)->ptr + beg + len,
00994                     VALUE, RARRAY(ary)->len - (beg + len));
00995             RARRAY(ary)->len = alen;
00996         }
00997         if (rlen > 0) {
00998             MEMMOVE(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
00999         }
01000     }
01001 }
01002 
01003 /* 
01004  *  call-seq:
01005  *     array[index]         = obj                     ->  obj
01006  *     array[start, length] = obj or an_array or nil  ->  obj or an_array or nil
01007  *     array[range]         = obj or an_array or nil  ->  obj or an_array or nil
01008  *
01009  *  Element Assignment---Sets the element at _index_,
01010  *  or replaces a subarray starting at _start_ and
01011  *  continuing for _length_ elements, or replaces a subarray
01012  *  specified by _range_.  If indices are greater than
01013  *  the current capacity of the array, the array grows
01014  *  automatically. A negative indices will count backward
01015  *  from the end of the array. Inserts elements if _length_ is
01016  *  zero. If +nil+ is used in the second and third form,
01017  *  deletes elements from _self_. An +IndexError+ is raised if a
01018  *  negative index points past the beginning of the array. See also
01019  *  <code>Array#push</code>, and <code>Array#unshift</code>.
01020  * 
01021  *     a = Array.new
01022  *     a[4] = "4";                 #=> [nil, nil, nil, nil, "4"]
01023  *     a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
01024  *     a[1..2] = [ 1, 2 ]          #=> ["a", 1, 2, nil, "4"]
01025  *     a[0, 2] = "?"               #=> ["?", 2, nil, "4"]
01026  *     a[0..2] = "A"               #=> ["A", "4"]
01027  *     a[-1]   = "Z"               #=> ["A", "Z"]
01028  *     a[1..-1] = nil              #=> ["A"]
01029  */
01030 
01031 static VALUE
01032 rb_ary_aset(argc, argv, ary)
01033     int argc;
01034     VALUE *argv;
01035     VALUE ary;
01036 {
01037     long offset, beg, len;
01038 
01039     if (argc == 3) {
01040         if (SYMBOL_P(argv[0])) {
01041             rb_raise(rb_eTypeError, "Symbol as array index");
01042         }
01043         if (SYMBOL_P(argv[1])) {
01044             rb_raise(rb_eTypeError, "Symbol as subarray length");
01045         }
01046         rb_ary_splice(ary, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
01047         return argv[2];
01048     }
01049     if (argc != 2) {
01050         rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
01051     }
01052     if (FIXNUM_P(argv[0])) {
01053         offset = FIX2LONG(argv[0]);
01054         goto fixnum;
01055     }
01056     if (SYMBOL_P(argv[0])) {
01057         rb_raise(rb_eTypeError, "Symbol as array index");
01058     }
01059     if (rb_range_beg_len(argv[0], &beg, &len, RARRAY(ary)->len, 1)) {
01060         /* check if idx is Range */
01061         rb_ary_splice(ary, beg, len, argv[1]);
01062         return argv[1];
01063     }
01064 
01065     offset = NUM2LONG(argv[0]);
01066 fixnum:
01067     rb_ary_store(ary, offset, argv[1]);
01068     return argv[1];
01069 }
01070 
01071 /*
01072  *  call-seq:
01073  *     array.insert(index, obj...)  -> array
01074  *  
01075  *  Inserts the given values before the element with the given index
01076  *  (which may be negative).
01077  *     
01078  *     a = %w{ a b c d }
01079  *     a.insert(2, 99)         #=> ["a", "b", 99, "c", "d"]
01080  *     a.insert(-2, 1, 2, 3)   #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
01081  */
01082 
01083 static VALUE
01084 rb_ary_insert(argc, argv, ary)
01085     int argc;
01086     VALUE *argv;
01087     VALUE ary;
01088 {
01089     long pos;
01090 
01091     if (argc == 1) return ary;
01092     if (argc < 1) {
01093         rb_raise(rb_eArgError, "wrong number of arguments (at least 1)");
01094     }
01095     pos = NUM2LONG(argv[0]);
01096     if (pos == -1) {
01097         pos = RARRAY(ary)->len;
01098     }
01099     if (pos < 0) {
01100         pos++;
01101     }
01102     rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1));
01103     return ary;
01104 }
01105 
01106 /*
01107  *  call-seq:
01108  *     array.each {|item| block }   ->   array
01109  *  
01110  *  Calls <i>block</i> once for each element in <i>self</i>, passing that
01111  *  element as a parameter.
01112  *     
01113  *     a = [ "a", "b", "c" ]
01114  *     a.each {|x| print x, " -- " }
01115  *     
01116  *  produces:
01117  *     
01118  *     a -- b -- c --
01119  */
01120 
01121 VALUE
01122 rb_ary_each(ary)
01123     VALUE ary;
01124 {
01125     long i;
01126 
01127     for (i=0; i<RARRAY(ary)->len; i++) {
01128         rb_yield(RARRAY(ary)->ptr[i]);
01129     }
01130     return ary;
01131 }
01132 
01133 /*
01134  *  call-seq:
01135  *     array.each_index {|index| block }  ->  array
01136  *  
01137  *  Same as <code>Array#each</code>, but passes the index of the element
01138  *  instead of the element itself.
01139  *     
01140  *     a = [ "a", "b", "c" ]
01141  *     a.each_index {|x| print x, " -- " }
01142  *     
01143  *  produces:
01144  *     
01145  *     0 -- 1 -- 2 --
01146  */
01147 
01148 static VALUE
01149 rb_ary_each_index(ary)
01150     VALUE ary;
01151 {
01152     long i;
01153 
01154     for (i=0; i<RARRAY(ary)->len; i++) {
01155         rb_yield(LONG2NUM(i));
01156     }
01157     return ary;
01158 }
01159 
01160 /*
01161  *  call-seq:
01162  *     array.reverse_each {|item| block } 
01163  *  
01164  *  Same as <code>Array#each</code>, but traverses <i>self</i> in reverse
01165  *  order.
01166  *     
01167  *     a = [ "a", "b", "c" ]
01168  *     a.reverse_each {|x| print x, " " }
01169  *     
01170  *  produces:
01171  *     
01172  *     c b a
01173  */
01174 
01175 static VALUE
01176 rb_ary_reverse_each(ary)
01177     VALUE ary;
01178 {
01179     long len = RARRAY(ary)->len;
01180 
01181     while (len--) {
01182         rb_yield(RARRAY(ary)->ptr[len]);
01183         if (RARRAY(ary)->len < len) {
01184             len = RARRAY(ary)->len;
01185         }
01186     }
01187     return ary;
01188 }
01189 
01190 /*
01191  *  call-seq:
01192  *     array.length -> int
01193  *  
01194  *  Returns the number of elements in <i>self</i>. May be zero.
01195  *     
01196  *     [ 1, 2, 3, 4, 5 ].length   #=> 5
01197  */
01198 
01199 static VALUE
01200 rb_ary_length(ary)
01201     VALUE ary;
01202 {
01203     return LONG2NUM(RARRAY(ary)->len);
01204 }
01205 
01206 /*
01207  *  call-seq:
01208  *     array.empty?   -> true or false
01209  *  
01210  *  Returns <code>true</code> if <i>self</i> array contains no elements.
01211  *     
01212  *     [].empty?   #=> true
01213  */
01214 
01215 static VALUE
01216 rb_ary_empty_p(ary)
01217     VALUE ary;
01218 {
01219     if (RARRAY(ary)->len == 0)
01220         return Qtrue;
01221     return Qfalse;
01222 }
01223 
01224 VALUE
01225 rb_ary_dup(ary)
01226     VALUE ary;
01227 {
01228     VALUE dup = rb_ary_new2(RARRAY(ary)->len);
01229 
01230     DUPSETUP(dup, ary);
01231     MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
01232     RARRAY(dup)->len = RARRAY(ary)->len;
01233     return dup;
01234 }
01235 
01236 extern VALUE rb_output_fs;
01237 
01238 static VALUE
01239 inspect_join(ary, arg)
01240     VALUE ary;
01241     VALUE *arg;
01242 {
01243     return rb_ary_join(arg[0], arg[1]);
01244 }
01245 
01246 VALUE
01247 rb_ary_join(ary, sep)
01248     VALUE ary, sep;
01249 {
01250     long len = 1, i;
01251     int taint = Qfalse;
01252     VALUE result, tmp;
01253 
01254     if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
01255     if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue;
01256 
01257     for (i=0; i<RARRAY(ary)->len; i++) {
01258         tmp = rb_check_string_type(RARRAY(ary)->ptr[i]);
01259         len += NIL_P(tmp) ? 10 : RSTRING(tmp)->len;
01260     }
01261     if (!NIL_P(sep)) {
01262         StringValue(sep);
01263         len += RSTRING(sep)->len * (RARRAY(ary)->len - 1);
01264     }
01265     result = rb_str_buf_new(len);
01266     for (i=0; i<RARRAY(ary)->len; i++) {
01267         tmp = RARRAY(ary)->ptr[i];
01268         switch (TYPE(tmp)) {
01269           case T_STRING:
01270             break;
01271           case T_ARRAY:
01272             if (rb_inspecting_p(tmp)) {
01273                 tmp = rb_str_new2("[...]");
01274             }
01275             else {
01276                 VALUE args[2];
01277 
01278                 args[0] = tmp;
01279                 args[1] = sep;
01280                 tmp = rb_protect_inspect(inspect_join, ary, (VALUE)args);
01281             }
01282             break;
01283           default:
01284             tmp = rb_obj_as_string(tmp);
01285         }
01286         if (i > 0 && !NIL_P(sep))
01287             rb_str_buf_append(result, sep);
01288         rb_str_buf_append(result, tmp);
01289         if (OBJ_TAINTED(tmp)) taint = Qtrue;
01290     }
01291 
01292     if (taint) OBJ_TAINT(result);
01293     return result;
01294 }
01295 
01296 /*
01297  *  call-seq:
01298  *     array.join(sep=$,)    -> str
01299  *  
01300  *  Returns a string created by converting each element of the array to
01301  *  a string, separated by <i>sep</i>.
01302  *     
01303  *     [ "a", "b", "c" ].join        #=> "abc"
01304  *     [ "a", "b", "c" ].join("-")   #=> "a-b-c"
01305  */
01306 
01307 static VALUE
01308 rb_ary_join_m(argc, argv, ary)
01309     int argc;
01310     VALUE *argv;
01311     VALUE ary;
01312 {
01313     VALUE sep;
01314 
01315     rb_scan_args(argc, argv, "01", &sep);
01316     if (NIL_P(sep)) sep = rb_output_fs;
01317     
01318     return rb_ary_join(ary, sep);
01319 }
01320 
01321 /*
01322  *  call-seq:
01323  *     array.to_s -> string
01324  *  
01325  *  Returns _self_<code>.join</code>.
01326  *     
01327  *     [ "a", "e", "i", "o" ].to_s   #=> "aeio"
01328  *
01329  */
01330 
01331 VALUE
01332 rb_ary_to_s(ary)
01333     VALUE ary;
01334 {
01335     if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
01336     
01337     return rb_ary_join(ary, rb_output_fs);
01338 }
01339 
01340 static ID inspect_key;
01341 
01342 struct inspect_arg {
01343     VALUE (*func)();
01344     VALUE arg1, arg2;
01345 };
01346 
01347 static VALUE
01348 inspect_call(arg)
01349     struct inspect_arg *arg;
01350 {
01351     return (*arg->func)(arg->arg1, arg->arg2);
01352 }
01353 
01354 static VALUE
01355 get_inspect_tbl(create)
01356     int create;
01357 {
01358     VALUE inspect_tbl = rb_thread_local_aref(rb_thread_current(), inspect_key);
01359 
01360     if (NIL_P(inspect_tbl)) {
01361         if (create) {
01362           tbl_init:
01363             inspect_tbl = rb_ary_new();
01364             rb_thread_local_aset(rb_thread_current(), inspect_key, inspect_tbl);
01365         }
01366     }
01367     else if (TYPE(inspect_tbl) != T_ARRAY) {
01368         rb_warn("invalid inspect_tbl value");
01369         if (create) goto tbl_init;
01370         rb_thread_local_aset(rb_thread_current(), inspect_key, Qnil);
01371         return Qnil;
01372     }
01373     return inspect_tbl;
01374 }
01375 
01376 static VALUE
01377 inspect_ensure(obj)
01378     VALUE obj;
01379 {
01380     VALUE inspect_tbl;
01381 
01382     inspect_tbl = get_inspect_tbl(Qfalse);
01383     if (!NIL_P(inspect_tbl)) {
01384         rb_ary_pop(inspect_tbl);
01385     }
01386     return 0;
01387 }
01388 
01389 VALUE
01390 rb_protect_inspect(func, obj, arg)
01391     VALUE (*func)(ANYARGS);
01392     VALUE obj, arg;
01393 {
01394     struct inspect_arg iarg;
01395     VALUE inspect_tbl;
01396     VALUE id;
01397 
01398     inspect_tbl = get_inspect_tbl(Qtrue);
01399     id = rb_obj_id(obj);
01400     if (rb_ary_includes(inspect_tbl, id)) {
01401         return (*func)(obj, arg);
01402     }
01403     rb_ary_push(inspect_tbl, id);
01404     iarg.func = func;
01405     iarg.arg1 = obj;
01406     iarg.arg2 = arg;
01407 
01408     return rb_ensure(inspect_call, (VALUE)&iarg, inspect_ensure, obj);
01409 }
01410 
01411 VALUE
01412 rb_inspecting_p(obj)
01413     VALUE obj;
01414 {
01415     VALUE inspect_tbl;
01416 
01417     inspect_tbl = get_inspect_tbl(Qfalse);
01418     if (NIL_P(inspect_tbl)) return Qfalse;
01419     return rb_ary_includes(inspect_tbl, rb_obj_id(obj));
01420 }
01421 
01422 static VALUE
01423 inspect_ary(ary)
01424     VALUE ary;
01425 {
01426     int tainted = OBJ_TAINTED(ary);
01427     long i;
01428     VALUE s, str;
01429 
01430     str = rb_str_buf_new2("[");
01431     for (i=0; i<RARRAY(ary)->len; i++) {
01432         s = rb_inspect(RARRAY(ary)->ptr[i]);
01433         if (OBJ_TAINTED(s)) tainted = Qtrue;
01434         if (i > 0) rb_str_buf_cat2(str, ", ");
01435         rb_str_buf_append(str, s);
01436     }
01437     rb_str_buf_cat2(str, "]");
01438     if (tainted) OBJ_TAINT(str);
01439     return str;
01440 }
01441 
01442 /*
01443  *  call-seq:
01444  *     array.inspect  -> string
01445  *
01446  *  Create a printable version of <i>array</i>.
01447  */
01448 
01449 static VALUE
01450 rb_ary_inspect(ary)
01451     VALUE ary;
01452 {
01453     if (RARRAY(ary)->len == 0) return rb_str_new2("[]");
01454     if (rb_inspecting_p(ary)) return rb_str_new2("[...]");
01455     return rb_protect_inspect(inspect_ary, ary, 0);
01456 }
01457 
01458 /*
01459  *  call-seq:
01460  *     array.to_a     -> array
01461  *  
01462  *  Returns _self_. If called on a subclass of Array, converts
01463  *  the receiver to an Array object.
01464  */
01465 
01466 static VALUE
01467 rb_ary_to_a(ary)
01468     VALUE ary;
01469 {
01470     if (rb_obj_class(ary) != rb_cArray) {
01471         VALUE dup = rb_ary_new2(RARRAY(ary)->len);
01472         rb_ary_replace(dup, ary);
01473         return dup;
01474     }
01475     return ary;
01476 }
01477 
01478 /*
01479  *  call-seq:
01480  *     array.to_ary -> array
01481  *  
01482  *  Returns _self_.
01483  */
01484 
01485 static VALUE
01486 rb_ary_to_ary_m(ary)
01487     VALUE ary;
01488 {
01489     return ary;
01490 }
01491 
01492 VALUE
01493 rb_ary_reverse(ary)
01494     VALUE ary;
01495 {
01496     VALUE *p1, *p2;
01497     VALUE tmp;
01498 
01499     rb_ary_modify(ary);
01500     if (RARRAY(ary)->len > 1) {
01501         p1 = RARRAY(ary)->ptr;
01502         p2 = p1 + RARRAY(ary)->len - 1; /* points last item */
01503 
01504         while (p1 < p2) {
01505             tmp = *p1;
01506             *p1++ = *p2;
01507             *p2-- = tmp;
01508         }
01509     }
01510     return ary;
01511 }
01512 
01513 /*
01514  *  call-seq:
01515  *     array.reverse!   -> array 
01516  *  
01517  *  Reverses _self_ in place.
01518  *     
01519  *     a = [ "a", "b", "c" ]
01520  *     a.reverse!       #=> ["c", "b", "a"]
01521  *     a                #=> ["c", "b", "a"]
01522  */
01523 
01524 static VALUE
01525 rb_ary_reverse_bang(ary)
01526     VALUE ary;
01527 {
01528     return rb_ary_reverse(ary);
01529 }
01530 
01531 /*
01532  *  call-seq:
01533  *     array.reverse -> an_array
01534  *  
01535  *  Returns a new array containing <i>self</i>'s elements in reverse order.
01536  *     
01537  *     [ "a", "b", "c" ].reverse   #=> ["c", "b", "a"]
01538  *     [ 1 ].reverse               #=> [1]
01539  */
01540 
01541 static VALUE
01542 rb_ary_reverse_m(ary)
01543     VALUE ary;
01544 {
01545     return rb_ary_reverse(rb_ary_dup(ary));
01546 }
01547 
01548 struct ary_sort_data {
01549     VALUE ary;
01550     VALUE *ptr;
01551     long len;
01552 };
01553 
01554 static void
01555 ary_sort_check(data)
01556     struct ary_sort_data *data;
01557 {
01558     if (RARRAY(data->ary)->ptr != data->ptr || RARRAY(data->ary)->len != data->len) {
01559         rb_raise(rb_eArgError, "array modified during sort");
01560     }
01561 }
01562 
01563 static int
01564 sort_1(a, b, data)
01565     VALUE *a, *b;
01566     struct ary_sort_data *data;
01567 {
01568     VALUE retval = rb_yield_values(2, *a, *b);
01569     int n;
01570 
01571     n = rb_cmpint(retval, *a, *b);
01572     ary_sort_check(data);
01573     return n;
01574 }
01575 
01576 static int
01577 sort_2(ap, bp, data)
01578     VALUE *ap, *bp;
01579     struct ary_sort_data *data;
01580 {
01581     VALUE retval;
01582     VALUE a = *ap, b = *bp;
01583     int n;
01584 
01585     if (FIXNUM_P(a) && FIXNUM_P(b)) {
01586         if ((long)a > (long)b) return 1;
01587         if ((long)a < (long)b) return -1;
01588         return 0;
01589     }
01590     if (TYPE(a) == T_STRING) {
01591         if (TYPE(b) == T_STRING) return rb_str_cmp(a, b);
01592     }
01593 
01594     retval = rb_funcall(a, id_cmp, 1, b);
01595     n = rb_cmpint(retval, a, b);
01596     ary_sort_check(data);
01597 
01598     return n;
01599 }
01600 
01601 static VALUE
01602 sort_internal(ary)
01603     VALUE ary;
01604 {
01605     struct ary_sort_data data;
01606 
01607     data.ary = ary;
01608     data.ptr = RARRAY(ary)->ptr; data.len = RARRAY(ary)->len;
01609     qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
01610           rb_block_given_p()?sort_1:sort_2, &data);
01611     return ary;
01612 }
01613 
01614 static VALUE
01615 sort_unlock(ary)
01616     VALUE ary;
01617 {
01618     FL_UNSET(ary, ARY_TMPLOCK);
01619     return ary;
01620 }
01621 
01622 /*
01623  *  call-seq:
01624  *     array.sort!                   -> array
01625  *     array.sort! {| a,b | block }  -> array 
01626  *  
01627  *  Sorts _self_. Comparisons for
01628  *  the sort will be done using the <code><=></code> operator or using
01629  *  an optional code block. The block implements a comparison between
01630  *  <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
01631  *  <code>Enumerable#sort_by</code>.
01632  *     
01633  *     a = [ "d", "a", "e", "c", "b" ]
01634  *     a.sort                    #=> ["a", "b", "c", "d", "e"]
01635  *     a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]
01636  */
01637 
01638 VALUE
01639 rb_ary_sort_bang(ary)
01640     VALUE ary;
01641 {
01642     rb_ary_modify(ary);
01643     if (RARRAY(ary)->len > 1) {
01644         FL_SET(ary, ARY_TMPLOCK);       /* prohibit modification during sort */
01645         rb_ensure(sort_internal, ary, sort_unlock, ary);
01646     }
01647     return ary;
01648 }
01649 
01650 /*
01651  *  call-seq:
01652  *     array.sort                   -> an_array 
01653  *     array.sort {| a,b | block }  -> an_array 
01654  *  
01655  *  Returns a new array created by sorting <i>self</i>. Comparisons for
01656  *  the sort will be done using the <code><=></code> operator or using
01657  *  an optional code block. The block implements a comparison between
01658  *  <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
01659  *  <code>Enumerable#sort_by</code>.
01660  *     
01661  *     a = [ "d", "a", "e", "c", "b" ]
01662  *     a.sort                    #=> ["a", "b", "c", "d", "e"]
01663  *     a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]
01664  */
01665 
01666 VALUE
01667 rb_ary_sort(ary)
01668     VALUE ary;
01669 {
01670     ary = rb_ary_dup(ary);
01671     rb_ary_sort_bang(ary);
01672     return ary;
01673 }
01674 
01675 /*
01676  *  call-seq:
01677  *     array.collect {|item| block }  -> an_array
01678  *     array.map     {|item| block }  -> an_array
01679  *  
01680  *  Invokes <i>block</i> once for each element of <i>self</i>. Creates a 
01681  *  new array containing the values returned by the block.
01682  *  See also <code>Enumerable#collect</code>.
01683  *     
01684  *     a = [ "a", "b", "c", "d" ]
01685  *     a.collect {|x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
01686  *     a                          #=> ["a", "b", "c", "d"]
01687  */
01688 
01689 static VALUE
01690 rb_ary_collect(ary)
01691     VALUE ary;
01692 {
01693     long i;
01694     VALUE collect;
01695 
01696     if (!rb_block_given_p()) {
01697         return rb_ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr);
01698     }
01699 
01700     collect = rb_ary_new2(RARRAY(ary)->len);
01701     for (i = 0; i < RARRAY(ary)->len; i++) {
01702         rb_ary_push(collect, rb_yield(RARRAY(ary)->ptr[i]));
01703     }
01704     return collect;
01705 }
01706 
01707 /* 
01708  *  call-seq:
01709  *     array.collect! {|item| block }   ->   array
01710  *     array.map!     {|item| block }   ->   array
01711  *
01712  *  Invokes the block once for each element of _self_, replacing the
01713  *  element with the value returned by _block_.
01714  *  See also <code>Enumerable#collect</code>.
01715  *   
01716  *     a = [ "a", "b", "c", "d" ]
01717  *     a.collect! {|x| x + "!" }
01718  *     a             #=>  [ "a!", "b!", "c!", "d!" ]
01719  */
01720 
01721 static VALUE
01722 rb_ary_collect_bang(ary)
01723     VALUE ary;
01724 {
01725     long i;
01726 
01727     rb_ary_modify(ary);
01728     for (i = 0; i < RARRAY(ary)->len; i++) {
01729         rb_ary_store(ary, i, rb_yield(RARRAY(ary)->ptr[i]));
01730     }
01731     return ary;
01732 }
01733 
01734 VALUE
01735 rb_values_at(obj, olen, argc, argv, func)
01736     VALUE obj;
01737     long olen;
01738     int argc;
01739     VALUE *argv;
01740     VALUE (*func) (VALUE,long);
01741 {
01742     VALUE result = rb_ary_new2(argc);
01743     long beg, len, i, j;
01744 
01745     for (i=0; i<argc; i++) {
01746         if (FIXNUM_P(argv[i])) {
01747