00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "ruby/util.h"
00014 #include "node.h"
00015 #include "id.h"
00016 #include "internal.h"
00017
00018 #define STATIC_ASSERT(name, expr) typedef int static_assert_##name##_check[1 - 2*!(expr)]
00019
00020 VALUE rb_mEnumerable;
00021
00022 static ID id_next;
00023 static ID id_div;
00024 static ID id_call;
00025 static ID id_size;
00026
00027 #define id_each idEach
00028 #define id_eqq idEqq
00029 #define id_cmp idCmp
00030 #define id_lshift idLTLT
00031
00032 VALUE
00033 rb_enum_values_pack(int argc, VALUE *argv)
00034 {
00035 if (argc == 0) return Qnil;
00036 if (argc == 1) return argv[0];
00037 return rb_ary_new4(argc, argv);
00038 }
00039
00040 #define ENUM_WANT_SVALUE() do { \
00041 i = rb_enum_values_pack(argc, argv); \
00042 } while (0)
00043
00044 #define enum_yield rb_yield_values2
00045
00046 static VALUE
00047 grep_i(VALUE i, VALUE args, int argc, VALUE *argv)
00048 {
00049 NODE *memo = RNODE(args);
00050 ENUM_WANT_SVALUE();
00051
00052 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) {
00053 rb_ary_push(memo->u2.value, i);
00054 }
00055 return Qnil;
00056 }
00057
00058 static VALUE
00059 grep_iter_i(VALUE i, VALUE args, int argc, VALUE *argv)
00060 {
00061 NODE *memo = RNODE(args);
00062 ENUM_WANT_SVALUE();
00063
00064 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) {
00065 rb_ary_push(memo->u2.value, rb_yield(i));
00066 }
00067 return Qnil;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 static VALUE
00089 enum_grep(VALUE obj, VALUE pat)
00090 {
00091 VALUE ary = rb_ary_new();
00092 NODE *memo = NEW_MEMO(pat, ary, 0);
00093
00094 rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)memo);
00095
00096 return ary;
00097 }
00098
00099 static VALUE
00100 count_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00101 {
00102 NODE *memo = RNODE(memop);
00103
00104 ENUM_WANT_SVALUE();
00105
00106 if (rb_equal(i, memo->u1.value)) {
00107 memo->u3.cnt++;
00108 }
00109 return Qnil;
00110 }
00111
00112 static VALUE
00113 count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00114 {
00115 NODE *memo = RNODE(memop);
00116
00117 if (RTEST(enum_yield(argc, argv))) {
00118 memo->u3.cnt++;
00119 }
00120 return Qnil;
00121 }
00122
00123 static VALUE
00124 count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00125 {
00126 NODE *memo = RNODE(memop);
00127
00128 memo->u3.cnt++;
00129 return Qnil;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 static VALUE
00151 enum_count(int argc, VALUE *argv, VALUE obj)
00152 {
00153 VALUE item = Qnil;
00154 NODE *memo;
00155 rb_block_call_func *func;
00156
00157 if (argc == 0) {
00158 if (rb_block_given_p()) {
00159 func = count_iter_i;
00160 }
00161 else {
00162 func = count_all_i;
00163 }
00164 }
00165 else {
00166 rb_scan_args(argc, argv, "1", &item);
00167 if (rb_block_given_p()) {
00168 rb_warn("given block not used");
00169 }
00170 func = count_i;
00171 }
00172
00173 memo = NEW_MEMO(item, 0, 0);
00174 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
00175 return INT2NUM(memo->u3.cnt);
00176 }
00177
00178 static VALUE
00179 find_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00180 {
00181 ENUM_WANT_SVALUE();
00182
00183 if (RTEST(rb_yield(i))) {
00184 NODE *memo = RNODE(memop);
00185 memo->u1.value = i;
00186 memo->u3.cnt = 1;
00187 rb_iter_break();
00188 }
00189 return Qnil;
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 static VALUE
00212 enum_find(int argc, VALUE *argv, VALUE obj)
00213 {
00214 NODE *memo;
00215 VALUE if_none;
00216
00217 rb_scan_args(argc, argv, "01", &if_none);
00218 RETURN_ENUMERATOR(obj, argc, argv);
00219 memo = NEW_MEMO(Qundef, 0, 0);
00220 rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
00221 if (memo->u3.cnt) {
00222 return memo->u1.value;
00223 }
00224 if (!NIL_P(if_none)) {
00225 return rb_funcall(if_none, id_call, 0, 0);
00226 }
00227 return Qnil;
00228 }
00229
00230 static VALUE
00231 find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00232 {
00233 NODE *memo = RNODE(memop);
00234
00235 ENUM_WANT_SVALUE();
00236
00237 if (rb_equal(i, memo->u2.value)) {
00238 memo->u1.value = UINT2NUM(memo->u3.cnt);
00239 rb_iter_break();
00240 }
00241 memo->u3.cnt++;
00242 return Qnil;
00243 }
00244
00245 static VALUE
00246 find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv)
00247 {
00248 NODE *memo = RNODE(memop);
00249
00250 if (RTEST(enum_yield(argc, argv))) {
00251 memo->u1.value = UINT2NUM(memo->u3.cnt);
00252 rb_iter_break();
00253 }
00254 memo->u3.cnt++;
00255 return Qnil;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 static VALUE
00278 enum_find_index(int argc, VALUE *argv, VALUE obj)
00279 {
00280 NODE *memo;
00281 VALUE condition_value = Qnil;
00282 rb_block_call_func *func;
00283
00284 if (argc == 0) {
00285 RETURN_ENUMERATOR(obj, 0, 0);
00286 func = find_index_iter_i;
00287 }
00288 else {
00289 rb_scan_args(argc, argv, "1", &condition_value);
00290 if (rb_block_given_p()) {
00291 rb_warn("given block not used");
00292 }
00293 func = find_index_i;
00294 }
00295
00296 memo = NEW_MEMO(Qnil, condition_value, 0);
00297 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
00298 return memo->u1.value;
00299 }
00300
00301 static VALUE
00302 find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv)
00303 {
00304 ENUM_WANT_SVALUE();
00305
00306 if (RTEST(rb_yield(i))) {
00307 rb_ary_push(ary, i);
00308 }
00309 return Qnil;
00310 }
00311
00312 static VALUE
00313 enum_size(VALUE self, VALUE args)
00314 {
00315 VALUE r;
00316 r = rb_check_funcall(self, id_size, 0, 0);
00317 return (r == Qundef) ? Qnil : r;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 static VALUE
00341 enum_find_all(VALUE obj)
00342 {
00343 VALUE ary;
00344
00345 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00346
00347 ary = rb_ary_new();
00348 rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
00349
00350 return ary;
00351 }
00352
00353 static VALUE
00354 reject_i(VALUE i, VALUE ary, int argc, VALUE *argv)
00355 {
00356 ENUM_WANT_SVALUE();
00357
00358 if (!RTEST(rb_yield(i))) {
00359 rb_ary_push(ary, i);
00360 }
00361 return Qnil;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 static VALUE
00382 enum_reject(VALUE obj)
00383 {
00384 VALUE ary;
00385
00386 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00387
00388 ary = rb_ary_new();
00389 rb_block_call(obj, id_each, 0, 0, reject_i, ary);
00390
00391 return ary;
00392 }
00393
00394 static VALUE
00395 collect_i(VALUE i, VALUE ary, int argc, VALUE *argv)
00396 {
00397 rb_ary_push(ary, enum_yield(argc, argv));
00398
00399 return Qnil;
00400 }
00401
00402 static VALUE
00403 collect_all(VALUE i, VALUE ary, int argc, VALUE *argv)
00404 {
00405 rb_thread_check_ints();
00406 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
00407
00408 return Qnil;
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 static VALUE
00429 enum_collect(VALUE obj)
00430 {
00431 VALUE ary;
00432
00433 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00434
00435 ary = rb_ary_new();
00436 rb_block_call(obj, id_each, 0, 0, collect_i, ary);
00437
00438 return ary;
00439 }
00440
00441 static VALUE
00442 flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv)
00443 {
00444 VALUE tmp;
00445
00446 i = enum_yield(argc, argv);
00447 tmp = rb_check_array_type(i);
00448
00449 if (NIL_P(tmp)) {
00450 rb_ary_push(ary, i);
00451 }
00452 else {
00453 rb_ary_concat(ary, tmp);
00454 }
00455 return Qnil;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 static VALUE
00476 enum_flat_map(VALUE obj)
00477 {
00478 VALUE ary;
00479
00480 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00481
00482 ary = rb_ary_new();
00483 rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);
00484
00485 return ary;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 static VALUE
00499 enum_to_a(int argc, VALUE *argv, VALUE obj)
00500 {
00501 VALUE ary = rb_ary_new();
00502
00503 rb_block_call(obj, id_each, argc, argv, collect_all, ary);
00504 OBJ_INFECT(ary, obj);
00505
00506 return ary;
00507 }
00508
00509 static VALUE
00510 inject_i(VALUE i, VALUE p, int argc, VALUE *argv)
00511 {
00512 NODE *memo = RNODE(p);
00513
00514 ENUM_WANT_SVALUE();
00515
00516 if (memo->u2.argc == 0) {
00517 memo->u2.argc = 1;
00518 memo->u1.value = i;
00519 }
00520 else {
00521 memo->u1.value = rb_yield_values(2, memo->u1.value, i);
00522 }
00523 return Qnil;
00524 }
00525
00526 static VALUE
00527 inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv)
00528 {
00529 NODE *memo = RNODE(p);
00530
00531 ENUM_WANT_SVALUE();
00532
00533 if (memo->u2.argc == 0) {
00534 memo->u2.argc = 1;
00535 memo->u1.value = i;
00536 }
00537 else {
00538 memo->u1.value = rb_funcall(memo->u1.value, memo->u3.id, 1, i);
00539 }
00540 return Qnil;
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 static VALUE
00587 enum_inject(int argc, VALUE *argv, VALUE obj)
00588 {
00589 NODE *memo;
00590 VALUE init, op;
00591 VALUE (*iter)(VALUE, VALUE, int, VALUE*) = inject_i;
00592
00593 switch (rb_scan_args(argc, argv, "02", &init, &op)) {
00594 case 0:
00595 break;
00596 case 1:
00597 if (rb_block_given_p()) {
00598 break;
00599 }
00600 op = (VALUE)rb_to_id(init);
00601 argc = 0;
00602 init = Qnil;
00603 iter = inject_op_i;
00604 break;
00605 case 2:
00606 if (rb_block_given_p()) {
00607 rb_warning("given block not used");
00608 }
00609 op = (VALUE)rb_to_id(op);
00610 iter = inject_op_i;
00611 break;
00612 }
00613 memo = NEW_MEMO(init, argc, op);
00614 rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
00615 return memo->u1.value;
00616 }
00617
00618 static VALUE
00619 partition_i(VALUE i, VALUE arys, int argc, VALUE *argv)
00620 {
00621 NODE *memo = RNODE(arys);
00622 VALUE ary;
00623 ENUM_WANT_SVALUE();
00624
00625 if (RTEST(rb_yield(i))) {
00626 ary = memo->u1.value;
00627 }
00628 else {
00629 ary = memo->u2.value;
00630 }
00631 rb_ary_push(ary, i);
00632 return Qnil;
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 static VALUE
00651 enum_partition(VALUE obj)
00652 {
00653 NODE *memo;
00654
00655 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00656
00657 memo = NEW_MEMO(rb_ary_new(), rb_ary_new(), 0);
00658 rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
00659
00660 return rb_assoc_new(memo->u1.value, memo->u2.value);
00661 }
00662
00663 static VALUE
00664 group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv)
00665 {
00666 VALUE group;
00667 VALUE values;
00668
00669 ENUM_WANT_SVALUE();
00670
00671 group = rb_yield(i);
00672 values = rb_hash_aref(hash, group);
00673 if (!RB_TYPE_P(values, T_ARRAY)) {
00674 values = rb_ary_new3(1, i);
00675 rb_hash_aset(hash, group, values);
00676 }
00677 else {
00678 rb_ary_push(values, i);
00679 }
00680 return Qnil;
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 static VALUE
00699 enum_group_by(VALUE obj)
00700 {
00701 VALUE hash;
00702
00703 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00704
00705 hash = rb_hash_new();
00706 rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
00707 OBJ_INFECT(hash, obj);
00708
00709 return hash;
00710 }
00711
00712 static VALUE
00713 first_i(VALUE i, VALUE params, int argc, VALUE *argv)
00714 {
00715 NODE *memo = RNODE(params);
00716 ENUM_WANT_SVALUE();
00717
00718 memo->u1.value = i;
00719 rb_iter_break();
00720
00721 UNREACHABLE;
00722 }
00723
00724 static VALUE enum_take(VALUE obj, VALUE n);
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 static VALUE
00743 enum_first(int argc, VALUE *argv, VALUE obj)
00744 {
00745 NODE *memo;
00746 rb_check_arity(argc, 0, 1);
00747 if (argc > 0) {
00748 return enum_take(obj, argv[0]);
00749 }
00750 else {
00751 memo = NEW_MEMO(Qnil, 0, 0);
00752 rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
00753 return memo->u1.value;
00754 }
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775 static VALUE
00776 enum_sort(VALUE obj)
00777 {
00778 return rb_ary_sort(enum_to_a(0, 0, obj));
00779 }
00780
00781 #define SORT_BY_BUFSIZE 16
00782 struct sort_by_data {
00783 VALUE ary;
00784 VALUE buf;
00785 long n;
00786 };
00787
00788 static VALUE
00789 sort_by_i(VALUE i, VALUE _data, int argc, VALUE *argv)
00790 {
00791 struct sort_by_data *data = (struct sort_by_data *)&RNODE(_data)->u1;
00792 VALUE ary = data->ary;
00793 VALUE v;
00794
00795 ENUM_WANT_SVALUE();
00796
00797 v = rb_yield(i);
00798
00799 if (RBASIC(ary)->klass) {
00800 rb_raise(rb_eRuntimeError, "sort_by reentered");
00801 }
00802 if (RARRAY_LEN(data->buf) != SORT_BY_BUFSIZE*2) {
00803 rb_raise(rb_eRuntimeError, "sort_by reentered");
00804 }
00805
00806 RARRAY_PTR(data->buf)[data->n*2] = v;
00807 RARRAY_PTR(data->buf)[data->n*2+1] = i;
00808 data->n++;
00809 if (data->n == SORT_BY_BUFSIZE) {
00810 rb_ary_concat(ary, data->buf);
00811 data->n = 0;
00812 }
00813 return Qnil;
00814 }
00815
00816 static int
00817 sort_by_cmp(const void *ap, const void *bp, void *data)
00818 {
00819 VALUE a;
00820 VALUE b;
00821 VALUE ary = (VALUE)data;
00822
00823 if (RBASIC(ary)->klass) {
00824 rb_raise(rb_eRuntimeError, "sort_by reentered");
00825 }
00826
00827 a = *(VALUE *)ap;
00828 b = *(VALUE *)bp;
00829
00830 return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 static VALUE
00905 enum_sort_by(VALUE obj)
00906 {
00907 VALUE ary, buf;
00908 NODE *memo;
00909 long i;
00910 struct sort_by_data *data;
00911
00912 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
00913
00914 if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) {
00915 ary = rb_ary_new2(RARRAY_LEN(obj)*2);
00916 }
00917 else {
00918 ary = rb_ary_new();
00919 }
00920 RBASIC(ary)->klass = 0;
00921 buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2);
00922 rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
00923 memo = NEW_MEMO(0, 0, 0);
00924 OBJ_INFECT(memo, obj);
00925 data = (struct sort_by_data *)&memo->u1;
00926 data->ary = ary;
00927 data->buf = buf;
00928 data->n = 0;
00929 rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
00930 ary = data->ary;
00931 buf = data->buf;
00932 if (data->n) {
00933 rb_ary_resize(buf, data->n*2);
00934 rb_ary_concat(ary, buf);
00935 }
00936 if (RARRAY_LEN(ary) > 2) {
00937 ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
00938 sort_by_cmp, (void *)ary);
00939 }
00940 if (RBASIC(ary)->klass) {
00941 rb_raise(rb_eRuntimeError, "sort_by reentered");
00942 }
00943 for (i=1; i<RARRAY_LEN(ary); i+=2) {
00944 RARRAY_PTR(ary)[i/2] = RARRAY_PTR(ary)[i];
00945 }
00946 rb_ary_resize(ary, RARRAY_LEN(ary)/2);
00947 RBASIC(ary)->klass = rb_cArray;
00948 OBJ_INFECT(ary, memo);
00949
00950 return ary;
00951 }
00952
00953 #define ENUMFUNC(name) rb_block_given_p() ? name##_iter_i : name##_i
00954
00955 #define DEFINE_ENUMFUNCS(name) \
00956 static VALUE enum_##name##_func(VALUE result, NODE *memo); \
00957 \
00958 static VALUE \
00959 name##_i(VALUE i, VALUE memo, int argc, VALUE *argv) \
00960 { \
00961 return enum_##name##_func(rb_enum_values_pack(argc, argv), RNODE(memo)); \
00962 } \
00963 \
00964 static VALUE \
00965 name##_iter_i(VALUE i, VALUE memo, int argc, VALUE *argv) \
00966 { \
00967 return enum_##name##_func(enum_yield(argc, argv), RNODE(memo)); \
00968 } \
00969 \
00970 static VALUE \
00971 enum_##name##_func(VALUE result, NODE *memo)
00972
00973 DEFINE_ENUMFUNCS(all)
00974 {
00975 if (!RTEST(result)) {
00976 memo->u1.value = Qfalse;
00977 rb_iter_break();
00978 }
00979 return Qnil;
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999 static VALUE
01000 enum_all(VALUE obj)
01001 {
01002 NODE *memo = NEW_MEMO(Qtrue, 0, 0);
01003 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
01004 return memo->u1.value;
01005 }
01006
01007 DEFINE_ENUMFUNCS(any)
01008 {
01009 if (RTEST(result)) {
01010 memo->u1.value = Qtrue;
01011 rb_iter_break();
01012 }
01013 return Qnil;
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033 static VALUE
01034 enum_any(VALUE obj)
01035 {
01036 NODE *memo = NEW_MEMO(Qfalse, 0, 0);
01037 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
01038 return memo->u1.value;
01039 }
01040
01041 DEFINE_ENUMFUNCS(one)
01042 {
01043 if (RTEST(result)) {
01044 if (memo->u1.value == Qundef) {
01045 memo->u1.value = Qtrue;
01046 }
01047 else if (memo->u1.value == Qtrue) {
01048 memo->u1.value = Qfalse;
01049 rb_iter_break();
01050 }
01051 }
01052 return Qnil;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073 static VALUE
01074 enum_one(VALUE obj)
01075 {
01076 NODE *memo = NEW_MEMO(Qundef, 0, 0);
01077 VALUE result;
01078
01079 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
01080 result = memo->u1.value;
01081 if (result == Qundef) return Qfalse;
01082 return result;
01083 }
01084
01085 DEFINE_ENUMFUNCS(none)
01086 {
01087 if (RTEST(result)) {
01088 memo->u1.value = Qfalse;
01089 rb_iter_break();
01090 }
01091 return Qnil;
01092 }
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 static VALUE
01110 enum_none(VALUE obj)
01111 {
01112 NODE *memo = NEW_MEMO(Qtrue, 0, 0);
01113 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
01114 return memo->u1.value;
01115 }
01116
01117 static VALUE
01118 min_i(VALUE i, VALUE args, int argc, VALUE *argv)
01119 {
01120 VALUE cmp;
01121 NODE *memo = RNODE(args);
01122
01123 ENUM_WANT_SVALUE();
01124
01125 if (memo->u1.value == Qundef) {
01126 memo->u1.value = i;
01127 }
01128 else {
01129 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
01130 if (rb_cmpint(cmp, i, memo->u1.value) < 0) {
01131 memo->u1.value = i;
01132 }
01133 }
01134 return Qnil;
01135 }
01136
01137 static VALUE
01138 min_ii(VALUE i, VALUE args, int argc, VALUE *argv)
01139 {
01140 VALUE cmp;
01141 NODE *memo = RNODE(args);
01142
01143 ENUM_WANT_SVALUE();
01144
01145 if (memo->u1.value == Qundef) {
01146 memo->u1.value = i;
01147 }
01148 else {
01149 cmp = rb_yield_values(2, i, memo->u1.value);
01150 if (rb_cmpint(cmp, i, memo->u1.value) < 0) {
01151 memo->u1.value = i;
01152 }
01153 }
01154 return Qnil;
01155 }
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172 static VALUE
01173 enum_min(VALUE obj)
01174 {
01175 NODE *memo = NEW_MEMO(Qundef, 0, 0);
01176 VALUE result;
01177
01178 if (rb_block_given_p()) {
01179 rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)memo);
01180 }
01181 else {
01182 rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)memo);
01183 }
01184 result = memo->u1.value;
01185 if (result == Qundef) return Qnil;
01186 return result;
01187 }
01188
01189 static VALUE
01190 max_i(VALUE i, VALUE args, int argc, VALUE *argv)
01191 {
01192 NODE *memo = RNODE(args);
01193 VALUE cmp;
01194
01195 ENUM_WANT_SVALUE();
01196
01197 if (memo->u1.value == Qundef) {
01198 memo->u1.value = i;
01199 }
01200 else {
01201 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value);
01202 if (rb_cmpint(cmp, i, memo->u1.value) > 0) {
01203 memo->u1.value = i;
01204 }
01205 }
01206 return Qnil;
01207 }
01208
01209 static VALUE
01210 max_ii(VALUE i, VALUE args, int argc, VALUE *argv)
01211 {
01212 NODE *memo = RNODE(args);
01213 VALUE cmp;
01214
01215 ENUM_WANT_SVALUE();
01216
01217 if (memo->u1.value == Qundef) {
01218 memo->u1.value = i;
01219 }
01220 else {
01221 cmp = rb_yield_values(2, i, memo->u1.value);
01222 if (rb_cmpint(cmp, i, memo->u1.value) > 0) {
01223 memo->u1.value = i;
01224 }
01225 }
01226 return Qnil;
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243 static VALUE
01244 enum_max(VALUE obj)
01245 {
01246 NODE *memo = NEW_MEMO(Qundef, 0, 0);
01247 VALUE result;
01248
01249 if (rb_block_given_p()) {
01250 rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo);
01251 }
01252 else {
01253 rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo);
01254 }
01255 result = memo->u1.value;
01256 if (result == Qundef) return Qnil;
01257 return result;
01258 }
01259
01260 struct minmax_t {
01261 VALUE min;
01262 VALUE max;
01263 VALUE last;
01264 };
01265
01266 STATIC_ASSERT(minmax_t, sizeof(struct minmax_t) <= sizeof(NODE) - offsetof(NODE, u1));
01267
01268 static void
01269 minmax_i_update(VALUE i, VALUE j, struct minmax_t *memo)
01270 {
01271 int n;
01272
01273 if (memo->min == Qundef) {
01274 memo->min = i;
01275 memo->max = j;
01276 }
01277 else {
01278 n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo->min), i, memo->min);
01279 if (n < 0) {
01280 memo->min = i;
01281 }
01282 n = rb_cmpint(rb_funcall(j, id_cmp, 1, memo->max), j, memo->max);
01283 if (n > 0) {
01284 memo->max = j;
01285 }
01286 }
01287 }
01288
01289 static VALUE
01290 minmax_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
01291 {
01292 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value;
01293 int n;
01294 VALUE j;
01295
01296 ENUM_WANT_SVALUE();
01297
01298 if (memo->last == Qundef) {
01299 memo->last = i;
01300 return Qnil;
01301 }
01302 j = memo->last;
01303 memo->last = Qundef;
01304
01305 n = rb_cmpint(rb_funcall(j, id_cmp, 1, i), j, i);
01306 if (n == 0)
01307 i = j;
01308 else if (n < 0) {
01309 VALUE tmp;
01310 tmp = i;
01311 i = j;
01312 j = tmp;
01313 }
01314
01315 minmax_i_update(i, j, memo);
01316
01317 return Qnil;
01318 }
01319
01320 static void
01321 minmax_ii_update(VALUE i, VALUE j, struct minmax_t *memo)
01322 {
01323 int n;
01324
01325 if (memo->min == Qundef) {
01326 memo->min = i;
01327 memo->max = j;
01328 }
01329 else {
01330 n = rb_cmpint(rb_yield_values(2, i, memo->min), i, memo->min);
01331 if (n < 0) {
01332 memo->min = i;
01333 }
01334 n = rb_cmpint(rb_yield_values(2, j, memo->max), j, memo->max);
01335 if (n > 0) {
01336 memo->max = j;
01337 }
01338 }
01339 }
01340
01341 static VALUE
01342 minmax_ii(VALUE i, VALUE _memo, int argc, VALUE *argv)
01343 {
01344 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value;
01345 int n;
01346 VALUE j;
01347
01348 ENUM_WANT_SVALUE();
01349
01350 if (memo->last == Qundef) {
01351 memo->last = i;
01352 return Qnil;
01353 }
01354 j = memo->last;
01355 memo->last = Qundef;
01356
01357 n = rb_cmpint(rb_yield_values(2, j, i), j, i);
01358 if (n == 0)
01359 i = j;
01360 else if (n < 0) {
01361 VALUE tmp;
01362 tmp = i;
01363 i = j;
01364 j = tmp;
01365 }
01366
01367 minmax_ii_update(i, j, memo);
01368
01369 return Qnil;
01370 }
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 static VALUE
01388 enum_minmax(VALUE obj)
01389 {
01390 NODE *memo = NEW_MEMO(Qundef, Qundef, Qundef);
01391 struct minmax_t *m = (struct minmax_t *)&memo->u1.value;
01392 VALUE ary = rb_ary_new3(2, Qnil, Qnil);
01393
01394 m->min = Qundef;
01395 m->last = Qundef;
01396 if (rb_block_given_p()) {
01397 rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)memo);
01398 if (m->last != Qundef)
01399 minmax_ii_update(m->last, m->last, m);
01400 }
01401 else {
01402 rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)memo);
01403 if (m->last != Qundef)
01404 minmax_i_update(m->last, m->last, m);
01405 }
01406 if (m->min != Qundef) {
01407 rb_ary_store(ary, 0, m->min);
01408 rb_ary_store(ary, 1, m->max);
01409 }
01410 return ary;
01411 }
01412
01413 static VALUE
01414 min_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
01415 {
01416 NODE *memo = RNODE(args);
01417 VALUE v;
01418
01419 ENUM_WANT_SVALUE();
01420
01421 v = rb_yield(i);
01422 if (memo->u1.value == Qundef) {
01423 memo->u1.value = v;
01424 memo->u2.value = i;
01425 }
01426 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) < 0) {
01427 memo->u1.value = v;
01428 memo->u2.value = i;
01429 }
01430 return Qnil;
01431 }
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447 static VALUE
01448 enum_min_by(VALUE obj)
01449 {
01450 NODE *memo;
01451
01452 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
01453
01454 memo = NEW_MEMO(Qundef, Qnil, 0);
01455 rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
01456 return memo->u2.value;
01457 }
01458
01459 static VALUE
01460 max_by_i(VALUE i, VALUE args, int argc, VALUE *argv)
01461 {
01462 NODE *memo = RNODE(args);
01463 VALUE v;
01464
01465 ENUM_WANT_SVALUE();
01466
01467 v = rb_yield(i);
01468 if (memo->u1.value == Qundef) {
01469 memo->u1.value = v;
01470 memo->u2.value = i;
01471 }
01472 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) > 0) {
01473 memo->u1.value = v;
01474 memo->u2.value = i;
01475 }
01476 return Qnil;
01477 }
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493 static VALUE
01494 enum_max_by(VALUE obj)
01495 {
01496 NODE *memo;
01497
01498 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
01499
01500 memo = NEW_MEMO(Qundef, Qnil, 0);
01501 rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
01502 return memo->u2.value;
01503 }
01504
01505 struct minmax_by_t {
01506 VALUE min_bv;
01507 VALUE max_bv;
01508 VALUE min;
01509 VALUE max;
01510 VALUE last_bv;
01511 VALUE last;
01512 };
01513
01514 static void
01515 minmax_by_i_update(VALUE v1, VALUE v2, VALUE i1, VALUE i2, struct minmax_by_t *memo)
01516 {
01517 if (memo->min_bv == Qundef) {
01518 memo->min_bv = v1;
01519 memo->max_bv = v2;
01520 memo->min = i1;
01521 memo->max = i2;
01522 }
01523 else {
01524 if (rb_cmpint(rb_funcall(v1, id_cmp, 1, memo->min_bv), v1, memo->min_bv) < 0) {
01525 memo->min_bv = v1;
01526 memo->min = i1;
01527 }
01528 if (rb_cmpint(rb_funcall(v2, id_cmp, 1, memo->max_bv), v2, memo->max_bv) > 0) {
01529 memo->max_bv = v2;
01530 memo->max = i2;
01531 }
01532 }
01533 }
01534
01535 static VALUE
01536 minmax_by_i(VALUE i, VALUE _memo, int argc, VALUE *argv)
01537 {
01538 struct minmax_by_t *memo = MEMO_FOR(struct minmax_by_t, _memo);
01539 VALUE vi, vj, j;
01540 int n;
01541
01542 ENUM_WANT_SVALUE();
01543
01544 vi = rb_yield(i);
01545
01546 if (memo->last_bv == Qundef) {
01547 memo->last_bv = vi;
01548 memo->last = i;
01549 return Qnil;
01550 }
01551 vj = memo->last_bv;
01552 j = memo->last;
01553 memo->last_bv = Qundef;
01554
01555 n = rb_cmpint(rb_funcall(vj, id_cmp, 1, vi), vj, vi);
01556 if (n == 0) {
01557 i = j;
01558 vi = vj;
01559 }
01560 else if (n < 0) {
01561 VALUE tmp;
01562 tmp = i;
01563 i = j;
01564 j = tmp;
01565 tmp = vi;
01566 vi = vj;
01567 vj = tmp;
01568 }
01569
01570 minmax_by_i_update(vi, vj, i, j, memo);
01571
01572 return Qnil;
01573 }
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590 static VALUE
01591 enum_minmax_by(VALUE obj)
01592 {
01593 VALUE memo;
01594 struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo);
01595
01596 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
01597
01598 m->min_bv = Qundef;
01599 m->max_bv = Qundef;
01600 m->min = Qnil;
01601 m->max = Qnil;
01602 m->last_bv = Qundef;
01603 m->last = Qundef;
01604 rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo);
01605 if (m->last_bv != Qundef)
01606 minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m);
01607 m = MEMO_FOR(struct minmax_by_t, memo);
01608 return rb_assoc_new(m->min, m->max);
01609 }
01610
01611 static VALUE
01612 member_i(VALUE iter, VALUE args, int argc, VALUE *argv)
01613 {
01614 NODE *memo = RNODE(args);
01615
01616 if (rb_equal(rb_enum_values_pack(argc, argv), memo->u1.value)) {
01617 memo->u2.value = Qtrue;
01618 rb_iter_break();
01619 }
01620 return Qnil;
01621 }
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636 static VALUE
01637 enum_member(VALUE obj, VALUE val)
01638 {
01639 NODE *memo = NEW_MEMO(val, Qfalse, 0);
01640
01641 rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
01642 return memo->u2.value;
01643 }
01644
01645 static VALUE
01646 each_with_index_i(VALUE i, VALUE memo, int argc, VALUE *argv)
01647 {
01648 long n = RNODE(memo)->u3.cnt++;
01649
01650 return rb_yield_values(2, rb_enum_values_pack(argc, argv), INT2NUM(n));
01651 }
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 static VALUE
01673 enum_each_with_index(int argc, VALUE *argv, VALUE obj)
01674 {
01675 NODE *memo;
01676
01677 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
01678
01679 memo = NEW_MEMO(0, 0, 0);
01680 rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
01681 return obj;
01682 }
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703 static VALUE
01704 enum_reverse_each(int argc, VALUE *argv, VALUE obj)
01705 {
01706 VALUE ary;
01707 long i;
01708
01709 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
01710
01711 ary = enum_to_a(argc, argv, obj);
01712
01713 for (i = RARRAY_LEN(ary); --i >= 0; ) {
01714 rb_yield(RARRAY_PTR(ary)[i]);
01715 }
01716
01717 return obj;
01718 }
01719
01720
01721 static VALUE
01722 each_val_i(VALUE i, VALUE p, int argc, VALUE *argv)
01723 {
01724 ENUM_WANT_SVALUE();
01725 rb_yield(i);
01726 return Qnil;
01727 }
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758 static VALUE
01759 enum_each_entry(int argc, VALUE *argv, VALUE obj)
01760 {
01761 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
01762 rb_block_call(obj, id_each, argc, argv, each_val_i, 0);
01763 return obj;
01764 }
01765
01766 static VALUE
01767 each_slice_i(VALUE i, VALUE m, int argc, VALUE *argv)
01768 {
01769 NODE *memo = RNODE(m);
01770 VALUE ary = memo->u1.value;
01771 VALUE v = Qnil;
01772 long size = memo->u3.cnt;
01773 ENUM_WANT_SVALUE();
01774
01775 rb_ary_push(ary, i);
01776
01777 if (RARRAY_LEN(ary) == size) {
01778 v = rb_yield(ary);
01779 memo->u1.value = rb_ary_new2(size);
01780 }
01781
01782 return v;
01783 }
01784
01785 static VALUE
01786 enum_each_slice_size(VALUE obj, VALUE args)
01787 {
01788 VALUE n, size;
01789 long slice_size = NUM2LONG(RARRAY_PTR(args)[0]);
01790 if (slice_size <= 0) rb_raise(rb_eArgError, "invalid slice size");
01791
01792 size = enum_size(obj, 0);
01793 if (size == Qnil) return Qnil;
01794
01795 n = rb_funcall(size, '+', 1, LONG2NUM(slice_size-1));
01796 return rb_funcall(n, id_div, 1, LONG2FIX(slice_size));
01797 }
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815 static VALUE
01816 enum_each_slice(VALUE obj, VALUE n)
01817 {
01818 long size = NUM2LONG(n);
01819 VALUE ary;
01820 NODE *memo;
01821
01822 if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
01823 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
01824 ary = rb_ary_new2(size);
01825 memo = NEW_MEMO(ary, 0, size);
01826 rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
01827 ary = memo->u1.value;
01828 if (RARRAY_LEN(ary) > 0) rb_yield(ary);
01829
01830 return Qnil;
01831 }
01832
01833 static VALUE
01834 each_cons_i(VALUE i, VALUE args, int argc, VALUE *argv)
01835 {
01836 NODE *memo = RNODE(args);
01837 VALUE ary = memo->u1.value;
01838 VALUE v = Qnil;
01839 long size = memo->u3.cnt;
01840 ENUM_WANT_SVALUE();
01841
01842 if (RARRAY_LEN(ary) == size) {
01843 rb_ary_shift(ary);
01844 }
01845 rb_ary_push(ary, i);
01846 if (RARRAY_LEN(ary) == size) {
01847 v = rb_yield(rb_ary_dup(ary));
01848 }
01849 return v;
01850 }
01851
01852 static VALUE
01853 enum_each_cons_size(VALUE obj, VALUE args)
01854 {
01855 VALUE n, size;
01856 long cons_size = NUM2LONG(RARRAY_PTR(args)[0]);
01857 if (cons_size <= 0) rb_raise(rb_eArgError, "invalid size");
01858
01859 size = enum_size(obj, 0);
01860 if (size == Qnil) return Qnil;
01861
01862 n = rb_funcall(size, '+', 1, LONG2NUM(1 - cons_size));
01863 return (rb_cmpint(rb_funcall(n, id_cmp, 1, LONG2FIX(0)), n, LONG2FIX(0)) == -1) ? LONG2FIX(0) : n;
01864 }
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887 static VALUE
01888 enum_each_cons(VALUE obj, VALUE n)
01889 {
01890 long size = NUM2LONG(n);
01891 NODE *memo;
01892
01893 if (size <= 0) rb_raise(rb_eArgError, "invalid size");
01894 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
01895 memo = NEW_MEMO(rb_ary_new2(size), 0, size);
01896 rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
01897
01898 return Qnil;
01899 }
01900
01901 static VALUE
01902 each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv)
01903 {
01904 ENUM_WANT_SVALUE();
01905 return rb_yield_values(2, i, memo);
01906 }
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922 static VALUE
01923 enum_each_with_object(VALUE obj, VALUE memo)
01924 {
01925 RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size);
01926
01927 rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo);
01928
01929 return memo;
01930 }
01931
01932 static VALUE
01933 zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv)
01934 {
01935 volatile VALUE result = memo->u1.value;
01936 volatile VALUE args = memo->u2.value;
01937 long n = memo->u3.cnt++;
01938 volatile VALUE tmp;
01939 int i;
01940
01941 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
01942 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
01943 for (i=0; i<RARRAY_LEN(args); i++) {
01944 VALUE e = RARRAY_PTR(args)[i];
01945
01946 if (RARRAY_LEN(e) <= n) {
01947 rb_ary_push(tmp, Qnil);
01948 }
01949 else {
01950 rb_ary_push(tmp, RARRAY_PTR(e)[n]);
01951 }
01952 }
01953 if (NIL_P(result)) {
01954 rb_yield(tmp);
01955 }
01956 else {
01957 rb_ary_push(result, tmp);
01958 }
01959 return Qnil;
01960 }
01961
01962 static VALUE
01963 call_next(VALUE *v)
01964 {
01965 return v[0] = rb_funcall(v[1], id_next, 0, 0);
01966 }
01967
01968 static VALUE
01969 call_stop(VALUE *v)
01970 {
01971 return v[0] = Qundef;
01972 }
01973
01974 static VALUE
01975 zip_i(VALUE val, NODE *memo, int argc, VALUE *argv)
01976 {
01977 volatile VALUE result = memo->u1.value;
01978 volatile VALUE args = memo->u2.value;
01979 volatile VALUE tmp;
01980 int i;
01981
01982 tmp = rb_ary_new2(RARRAY_LEN(args) + 1);
01983 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv));
01984 for (i=0; i<RARRAY_LEN(args); i++) {
01985 if (NIL_P(RARRAY_PTR(args)[i])) {
01986 rb_ary_push(tmp, Qnil);
01987 }
01988 else {
01989 VALUE v[2];
01990
01991 v[1] = RARRAY_PTR(args)[i];
01992 rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, (VALUE)0);
01993 if (v[0] == Qundef) {
01994 RARRAY_PTR(args)[i] = Qnil;
01995 v[0] = Qnil;
01996 }
01997 rb_ary_push(tmp, v[0]);
01998 }
01999 }
02000 if (NIL_P(result)) {
02001 rb_yield(tmp);
02002 }
02003 else {
02004 rb_ary_push(result, tmp);
02005 }
02006 return Qnil;
02007 }
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032 static VALUE
02033 enum_zip(int argc, VALUE *argv, VALUE obj)
02034 {
02035 int i;
02036 ID conv;
02037 NODE *memo;
02038 VALUE result = Qnil;
02039 VALUE args = rb_ary_new4(argc, argv);
02040 int allary = TRUE;
02041
02042 argv = RARRAY_PTR(args);
02043 for (i=0; i<argc; i++) {
02044 VALUE ary = rb_check_array_type(argv[i]);
02045 if (NIL_P(ary)) {
02046 allary = FALSE;
02047 break;
02048 }
02049 argv[i] = ary;
02050 }
02051 if (!allary) {
02052 CONST_ID(conv, "to_enum");
02053 for (i=0; i<argc; i++) {
02054 if (!rb_respond_to(argv[i], id_each)) {
02055 rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
02056 rb_obj_classname(argv[i]));
02057 }
02058 argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
02059 }
02060 }
02061 if (!rb_block_given_p()) {
02062 result = rb_ary_new();
02063 }
02064
02065 memo = rb_node_newnode(NODE_DOT2, result, args, 0);
02066 rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
02067
02068 return result;
02069 }
02070
02071 static VALUE
02072 take_i(VALUE i, VALUE args, int argc, VALUE *argv)
02073 {
02074 NODE *memo = RNODE(args);
02075 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv));
02076 if (--memo->u3.cnt == 0) rb_iter_break();
02077 return Qnil;
02078 }
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091 static VALUE
02092 enum_take(VALUE obj, VALUE n)
02093 {
02094 NODE *memo;
02095 VALUE result;
02096 long len = NUM2LONG(n);
02097
02098 if (len < 0) {
02099 rb_raise(rb_eArgError, "attempt to take negative size");
02100 }
02101
02102 if (len == 0) return rb_ary_new2(0);
02103 result = rb_ary_new2(len);
02104 memo = NEW_MEMO(result, 0, len);
02105 rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
02106 return result;
02107 }
02108
02109
02110 static VALUE
02111 take_while_i(VALUE i, VALUE ary, int argc, VALUE *argv)
02112 {
02113 if (!RTEST(enum_yield(argc, argv))) rb_iter_break();
02114 rb_ary_push(ary, rb_enum_values_pack(argc, argv));
02115 return Qnil;
02116 }
02117
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133 static VALUE
02134 enum_take_while(VALUE obj)
02135 {
02136 VALUE ary;
02137
02138 RETURN_ENUMERATOR(obj, 0, 0);
02139 ary = rb_ary_new();
02140 rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
02141 return ary;
02142 }
02143
02144 static VALUE
02145 drop_i(VALUE i, VALUE args, int argc, VALUE *argv)
02146 {
02147 NODE *memo = RNODE(args);
02148 if (memo->u3.cnt == 0) {
02149 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv));
02150 }
02151 else {
02152 memo->u3.cnt--;
02153 }
02154 return Qnil;
02155 }
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169 static VALUE
02170 enum_drop(VALUE obj, VALUE n)
02171 {
02172 VALUE result;
02173 NODE *memo;
02174 long len = NUM2LONG(n);
02175
02176 if (len < 0) {
02177 rb_raise(rb_eArgError, "attempt to drop negative size");
02178 }
02179
02180 result = rb_ary_new();
02181 memo = NEW_MEMO(result, 0, len);
02182 rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
02183 return result;
02184 }
02185
02186
02187 static VALUE
02188 drop_while_i(VALUE i, VALUE args, int argc, VALUE *argv)
02189 {
02190 NODE *memo = RNODE(args);
02191 ENUM_WANT_SVALUE();
02192
02193 if (!memo->u3.state && !RTEST(rb_yield(i))) {
02194 memo->u3.state = TRUE;
02195 }
02196 if (memo->u3.state) {
02197 rb_ary_push(memo->u1.value, i);
02198 }
02199 return Qnil;
02200 }
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218 static VALUE
02219 enum_drop_while(VALUE obj)
02220 {
02221 VALUE result;
02222 NODE *memo;
02223
02224 RETURN_ENUMERATOR(obj, 0, 0);
02225 result = rb_ary_new();
02226 memo = NEW_MEMO(result, 0, FALSE);
02227 rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
02228 return result;
02229 }
02230
02231 static VALUE
02232 cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv)
02233 {
02234 ENUM_WANT_SVALUE();
02235
02236 rb_ary_push(ary, i);
02237 rb_yield(i);
02238 return Qnil;
02239 }
02240
02241 static VALUE
02242 enum_cycle_size(VALUE self, VALUE args)
02243 {
02244 long mul;
02245 VALUE n = Qnil;
02246 VALUE size = enum_size(self, args);
02247
02248 if (size == Qnil) return Qnil;
02249
02250 if (args && (RARRAY_LEN(args) > 0)) {
02251 n = RARRAY_PTR(args)[0];
02252 }
02253 if (n == Qnil) return DBL2NUM(INFINITY);
02254 mul = NUM2LONG(n);
02255 if (mul <= 0) return INT2FIX(0);
02256 return rb_funcall(size, '*', 1, LONG2FIX(mul));
02257 }
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280 static VALUE
02281 enum_cycle(int argc, VALUE *argv, VALUE obj)
02282 {
02283 VALUE ary;
02284 VALUE nv = Qnil;
02285 long n, i, len;
02286
02287 rb_scan_args(argc, argv, "01", &nv);
02288
02289 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
02290 if (NIL_P(nv)) {
02291 n = -1;
02292 }
02293 else {
02294 n = NUM2LONG(nv);
02295 if (n <= 0) return Qnil;
02296 }
02297 ary = rb_ary_new();
02298 RBASIC(ary)->klass = 0;
02299 rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
02300 len = RARRAY_LEN(ary);
02301 if (len == 0) return Qnil;
02302 while (n < 0 || 0 < --n) {
02303 for (i=0; i<len; i++) {
02304 rb_yield(RARRAY_PTR(ary)[i]);
02305 }
02306 }
02307 return Qnil;
02308 }
02309
02310 struct chunk_arg {
02311 VALUE categorize;
02312 VALUE state;
02313 VALUE prev_value;
02314 VALUE prev_elts;
02315 VALUE yielder;
02316 };
02317
02318 static VALUE
02319 chunk_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
02320 {
02321 struct chunk_arg *argp = MEMO_FOR(struct chunk_arg, _argp);
02322 VALUE v;
02323 VALUE alone = ID2SYM(rb_intern("_alone"));
02324 VALUE separator = ID2SYM(rb_intern("_separator"));
02325
02326 ENUM_WANT_SVALUE();
02327
02328 if (NIL_P(argp->state))
02329 v = rb_funcall(argp->categorize, id_call, 1, i);
02330 else
02331 v = rb_funcall(argp->categorize, id_call, 2, i, argp->state);
02332
02333 if (v == alone) {
02334 if (!NIL_P(argp->prev_value)) {
02335 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
02336 argp->prev_value = argp->prev_elts = Qnil;
02337 }
02338 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(v, rb_ary_new3(1, i)));
02339 }
02340 else if (NIL_P(v) || v == separator) {
02341 if (!NIL_P(argp->prev_value)) {
02342 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
02343 argp->prev_value = argp->prev_elts = Qnil;
02344 }
02345 }
02346 else if (SYMBOL_P(v) && rb_id2name(SYM2ID(v))[0] == '_') {
02347 rb_raise(rb_eRuntimeError, "symbol begins with an underscore is reserved");
02348 }
02349 else {
02350 if (NIL_P(argp->prev_value)) {
02351 argp->prev_value = v;
02352 argp->prev_elts = rb_ary_new3(1, i);
02353 }
02354 else {
02355 if (rb_equal(argp->prev_value, v)) {
02356 rb_ary_push(argp->prev_elts, i);
02357 }
02358 else {
02359 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts));
02360 argp->prev_value = v;
02361 argp->prev_elts = rb_ary_new3(1, i);
02362 }
02363 }
02364 }
02365 return Qnil;
02366 }
02367
02368 static VALUE
02369 chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
02370 {
02371 VALUE enumerable;
02372 VALUE arg;
02373 struct chunk_arg *memo = NEW_MEMO_FOR(struct chunk_arg, arg);
02374
02375 enumerable = rb_ivar_get(enumerator, rb_intern("chunk_enumerable"));
02376 memo->categorize = rb_ivar_get(enumerator, rb_intern("chunk_categorize"));
02377 memo->state = rb_ivar_get(enumerator, rb_intern("chunk_initial_state"));
02378 memo->prev_value = Qnil;
02379 memo->prev_elts = Qnil;
02380 memo->yielder = yielder;
02381
02382 if (!NIL_P(memo->state))
02383 memo->state = rb_obj_dup(memo->state);
02384
02385 rb_block_call(enumerable, id_each, 0, 0, chunk_ii, arg);
02386 memo = MEMO_FOR(struct chunk_arg, arg);
02387 if (!NIL_P(memo->prev_elts))
02388 rb_funcall(memo->yielder, id_lshift, 1, rb_assoc_new(memo->prev_value, memo->prev_elts));
02389 return Qnil;
02390 }
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486 static VALUE
02487 enum_chunk(int argc, VALUE *argv, VALUE enumerable)
02488 {
02489 VALUE initial_state;
02490 VALUE enumerator;
02491
02492 if (!rb_block_given_p())
02493 rb_raise(rb_eArgError, "no block given");
02494 rb_scan_args(argc, argv, "01", &initial_state);
02495
02496 enumerator = rb_obj_alloc(rb_cEnumerator);
02497 rb_ivar_set(enumerator, rb_intern("chunk_enumerable"), enumerable);
02498 rb_ivar_set(enumerator, rb_intern("chunk_categorize"), rb_block_proc());
02499 rb_ivar_set(enumerator, rb_intern("chunk_initial_state"), initial_state);
02500 rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
02501 return enumerator;
02502 }
02503
02504
02505 struct slicebefore_arg {
02506 VALUE sep_pred;
02507 VALUE sep_pat;
02508 VALUE state;
02509 VALUE prev_elts;
02510 VALUE yielder;
02511 };
02512
02513 static VALUE
02514 slicebefore_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
02515 {
02516 struct slicebefore_arg *argp = MEMO_FOR(struct slicebefore_arg, _argp);
02517 VALUE header_p;
02518
02519 ENUM_WANT_SVALUE();
02520
02521 if (!NIL_P(argp->sep_pat))
02522 header_p = rb_funcall(argp->sep_pat, id_eqq, 1, i);
02523 else if (NIL_P(argp->state))
02524 header_p = rb_funcall(argp->sep_pred, id_call, 1, i);
02525 else
02526 header_p = rb_funcall(argp->sep_pred, id_call, 2, i, argp->state);
02527 if (RTEST(header_p)) {
02528 if (!NIL_P(argp->prev_elts))
02529 rb_funcall(argp->yielder, id_lshift, 1, argp->prev_elts);
02530 argp->prev_elts = rb_ary_new3(1, i);
02531 }
02532 else {
02533 if (NIL_P(argp->prev_elts))
02534 argp->prev_elts = rb_ary_new3(1, i);
02535 else
02536 rb_ary_push(argp->prev_elts, i);
02537 }
02538
02539 return Qnil;
02540 }
02541
02542 static VALUE
02543 slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
02544 {
02545 VALUE enumerable;
02546 VALUE arg;
02547 struct slicebefore_arg *memo = NEW_MEMO_FOR(struct slicebefore_arg, arg);
02548
02549 enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable"));
02550 memo->sep_pred = rb_attr_get(enumerator, rb_intern("slicebefore_sep_pred"));
02551 memo->sep_pat = NIL_P(memo->sep_pred) ? rb_ivar_get(enumerator, rb_intern("slicebefore_sep_pat")) : Qnil;
02552 memo->state = rb_attr_get(enumerator, rb_intern("slicebefore_initial_state"));
02553 memo->prev_elts = Qnil;
02554 memo->yielder = yielder;
02555
02556 if (!NIL_P(memo->state))
02557 memo->state = rb_obj_dup(memo->state);
02558
02559 rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, arg);
02560 memo = MEMO_FOR(struct slicebefore_arg, arg);
02561 if (!NIL_P(memo->prev_elts))
02562 rb_funcall(memo->yielder, id_lshift, 1, memo->prev_elts);
02563 return Qnil;
02564 }
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703 static VALUE
02704 enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
02705 {
02706 VALUE enumerator;
02707
02708 if (rb_block_given_p()) {
02709 VALUE initial_state;
02710 rb_scan_args(argc, argv, "01", &initial_state);
02711 enumerator = rb_obj_alloc(rb_cEnumerator);
02712 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc());
02713 rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state);
02714 }
02715 else {
02716 VALUE sep_pat;
02717 rb_scan_args(argc, argv, "1", &sep_pat);
02718 enumerator = rb_obj_alloc(rb_cEnumerator);
02719 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat);
02720 }
02721 rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable);
02722 rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
02723 return enumerator;
02724 }
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737 void
02738 Init_Enumerable(void)
02739 {
02740 #undef rb_intern
02741 #define rb_intern(str) rb_intern_const(str)
02742
02743 rb_mEnumerable = rb_define_module("Enumerable");
02744
02745 rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
02746 rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
02747
02748 rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
02749 rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
02750 rb_define_method(rb_mEnumerable, "grep", enum_grep, 1);
02751 rb_define_method(rb_mEnumerable, "count", enum_count, -1);
02752 rb_define_method(rb_mEnumerable, "find", enum_find, -1);
02753 rb_define_method(rb_mEnumerable, "detect", enum_find, -1);
02754 rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
02755 rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
02756 rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
02757 rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
02758 rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
02759 rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
02760 rb_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0);
02761 rb_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0);
02762 rb_define_method(rb_mEnumerable, "inject", enum_inject, -1);
02763 rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
02764 rb_define_method(rb_mEnumerable, "partition", enum_partition, 0);
02765 rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
02766 rb_define_method(rb_mEnumerable, "first", enum_first, -1);
02767 rb_define_method(rb_mEnumerable, "all?", enum_all, 0);
02768 rb_define_method(rb_mEnumerable, "any?", enum_any, 0);
02769 rb_define_method(rb_mEnumerable, "one?", enum_one, 0);
02770 rb_define_method(rb_mEnumerable, "none?", enum_none, 0);
02771 rb_define_method(rb_mEnumerable, "min", enum_min, 0);
02772 rb_define_method(rb_mEnumerable, "max", enum_max, 0);
02773 rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
02774 rb_define_method(rb_mEnumerable, "min_by", enum_min_by, 0);
02775 rb_define_method(rb_mEnumerable, "max_by", enum_max_by, 0);
02776 rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
02777 rb_define_method(rb_mEnumerable, "member?", enum_member, 1);
02778 rb_define_method(rb_mEnumerable, "include?", enum_member, 1);
02779 rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1);
02780 rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
02781 rb_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1);
02782 rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
02783 rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
02784 rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1);
02785 rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
02786 rb_define_method(rb_mEnumerable, "take", enum_take, 1);
02787 rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
02788 rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
02789 rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
02790 rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
02791 rb_define_method(rb_mEnumerable, "chunk", enum_chunk, -1);
02792 rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1);
02793
02794 id_next = rb_intern("next");
02795 id_call = rb_intern("call");
02796 id_size = rb_intern("size");
02797 id_div = rb_intern("div");
02798 }
02799