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