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