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