|
Ruby
1.9.3p286(2012-10-12revision37165)
|
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
1.7.6.1