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