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