1/********************************************************************** 2 3 enum.c - 4 5 $Author: zzak $ 6 created at: Fri Oct 1 15:15:19 JST 1993 7 8 Copyright (C) 1993-2007 Yukihiro Matsumoto 9 10**********************************************************************/ 11 12#include "ruby/ruby.h" 13#include "ruby/util.h" 14#include "node.h" 15#include "id.h" 16#include "internal.h" 17 18#define STATIC_ASSERT(name, expr) typedef int static_assert_##name##_check[1 - 2*!(expr)] 19 20VALUE rb_mEnumerable; 21 22static ID id_next; 23static ID id_div; 24static ID id_call; 25static ID id_size; 26 27#define id_each idEach 28#define id_eqq idEqq 29#define id_cmp idCmp 30#define id_lshift idLTLT 31 32VALUE 33rb_enum_values_pack(int argc, VALUE *argv) 34{ 35 if (argc == 0) return Qnil; 36 if (argc == 1) return argv[0]; 37 return rb_ary_new4(argc, argv); 38} 39 40#define ENUM_WANT_SVALUE() do { \ 41 i = rb_enum_values_pack(argc, argv); \ 42} while (0) 43 44#define enum_yield rb_yield_values2 45 46static VALUE 47grep_i(VALUE i, VALUE args, int argc, VALUE *argv) 48{ 49 NODE *memo = RNODE(args); 50 ENUM_WANT_SVALUE(); 51 52 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) { 53 rb_ary_push(memo->u2.value, i); 54 } 55 return Qnil; 56} 57 58static VALUE 59grep_iter_i(VALUE i, VALUE args, int argc, VALUE *argv) 60{ 61 NODE *memo = RNODE(args); 62 ENUM_WANT_SVALUE(); 63 64 if (RTEST(rb_funcall(memo->u1.value, id_eqq, 1, i))) { 65 rb_ary_push(memo->u2.value, rb_yield(i)); 66 } 67 return Qnil; 68} 69 70/* 71 * call-seq: 72 * enum.grep(pattern) -> array 73 * enum.grep(pattern) { |obj| block } -> array 74 * 75 * Returns an array of every element in <i>enum</i> for which 76 * <code>Pattern === element</code>. If the optional <em>block</em> is 77 * supplied, each matching element is passed to it, and the block's 78 * result is stored in the output array. 79 * 80 * (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44] 81 * c = IO.constants 82 * c.grep(/SEEK/) #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END] 83 * res = c.grep(/SEEK/) { |v| IO.const_get(v) } 84 * res #=> [0, 1, 2] 85 * 86 */ 87 88static VALUE 89enum_grep(VALUE obj, VALUE pat) 90{ 91 VALUE ary = rb_ary_new(); 92 NODE *memo = NEW_MEMO(pat, ary, 0); 93 94 rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)memo); 95 96 return ary; 97} 98 99static VALUE 100count_i(VALUE i, VALUE memop, int argc, VALUE *argv) 101{ 102 NODE *memo = RNODE(memop); 103 104 ENUM_WANT_SVALUE(); 105 106 if (rb_equal(i, memo->u1.value)) { 107 memo->u3.cnt++; 108 } 109 return Qnil; 110} 111 112static VALUE 113count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv) 114{ 115 NODE *memo = RNODE(memop); 116 117 if (RTEST(enum_yield(argc, argv))) { 118 memo->u3.cnt++; 119 } 120 return Qnil; 121} 122 123static VALUE 124count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv) 125{ 126 NODE *memo = RNODE(memop); 127 128 memo->u3.cnt++; 129 return Qnil; 130} 131 132/* 133 * call-seq: 134 * enum.count -> int 135 * enum.count(item) -> int 136 * enum.count { |obj| block } -> int 137 * 138 * Returns the number of items in +enum+ through enumeration. 139 * If an argument is given, the number of items in +enum+ that 140 * are equal to +item+ are counted. If a block is given, it 141 * counts the number of elements yielding a true value. 142 * 143 * ary = [1, 2, 4, 2] 144 * ary.count #=> 4 145 * ary.count(2) #=> 2 146 * ary.count{ |x| x%2==0 } #=> 3 147 * 148 */ 149 150static VALUE 151enum_count(int argc, VALUE *argv, VALUE obj) 152{ 153 VALUE item = Qnil; 154 NODE *memo; 155 rb_block_call_func *func; 156 157 if (argc == 0) { 158 if (rb_block_given_p()) { 159 func = count_iter_i; 160 } 161 else { 162 func = count_all_i; 163 } 164 } 165 else { 166 rb_scan_args(argc, argv, "1", &item); 167 if (rb_block_given_p()) { 168 rb_warn("given block not used"); 169 } 170 func = count_i; 171 } 172 173 memo = NEW_MEMO(item, 0, 0); 174 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo); 175 return INT2NUM(memo->u3.cnt); 176} 177 178static VALUE 179find_i(VALUE i, VALUE memop, int argc, VALUE *argv) 180{ 181 ENUM_WANT_SVALUE(); 182 183 if (RTEST(rb_yield(i))) { 184 NODE *memo = RNODE(memop); 185 memo->u1.value = i; 186 memo->u3.cnt = 1; 187 rb_iter_break(); 188 } 189 return Qnil; 190} 191 192/* 193 * call-seq: 194 * enum.detect(ifnone = nil) { |obj| block } -> obj or nil 195 * enum.find(ifnone = nil) { |obj| block } -> obj or nil 196 * enum.detect(ifnone = nil) -> an_enumerator 197 * enum.find(ifnone = nil) -> an_enumerator 198 * 199 * Passes each entry in <i>enum</i> to <em>block</em>. Returns the 200 * first for which <em>block</em> is not false. If no 201 * object matches, calls <i>ifnone</i> and returns its result when it 202 * is specified, or returns <code>nil</code> otherwise. 203 * 204 * If no block is given, an enumerator is returned instead. 205 * 206 * (1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil 207 * (1..100).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> 35 208 * 209 */ 210 211static VALUE 212enum_find(int argc, VALUE *argv, VALUE obj) 213{ 214 NODE *memo; 215 VALUE if_none; 216 217 rb_scan_args(argc, argv, "01", &if_none); 218 RETURN_ENUMERATOR(obj, argc, argv); 219 memo = NEW_MEMO(Qundef, 0, 0); 220 rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo); 221 if (memo->u3.cnt) { 222 return memo->u1.value; 223 } 224 if (!NIL_P(if_none)) { 225 return rb_funcall(if_none, id_call, 0, 0); 226 } 227 return Qnil; 228} 229 230static VALUE 231find_index_i(VALUE i, VALUE memop, int argc, VALUE *argv) 232{ 233 NODE *memo = RNODE(memop); 234 235 ENUM_WANT_SVALUE(); 236 237 if (rb_equal(i, memo->u2.value)) { 238 memo->u1.value = UINT2NUM(memo->u3.cnt); 239 rb_iter_break(); 240 } 241 memo->u3.cnt++; 242 return Qnil; 243} 244 245static VALUE 246find_index_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv) 247{ 248 NODE *memo = RNODE(memop); 249 250 if (RTEST(enum_yield(argc, argv))) { 251 memo->u1.value = UINT2NUM(memo->u3.cnt); 252 rb_iter_break(); 253 } 254 memo->u3.cnt++; 255 return Qnil; 256} 257 258/* 259 * call-seq: 260 * enum.find_index(value) -> int or nil 261 * enum.find_index { |obj| block } -> int or nil 262 * enum.find_index -> an_enumerator 263 * 264 * Compares each entry in <i>enum</i> with <em>value</em> or passes 265 * to <em>block</em>. Returns the index for the first for which the 266 * evaluated value is non-false. If no object matches, returns 267 * <code>nil</code> 268 * 269 * If neither block nor argument is given, an enumerator is returned instead. 270 * 271 * (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil 272 * (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34 273 * (1..100).find_index(50) #=> 49 274 * 275 */ 276 277static VALUE 278enum_find_index(int argc, VALUE *argv, VALUE obj) 279{ 280 NODE *memo; /* [return value, current index, ] */ 281 VALUE condition_value = Qnil; 282 rb_block_call_func *func; 283 284 if (argc == 0) { 285 RETURN_ENUMERATOR(obj, 0, 0); 286 func = find_index_iter_i; 287 } 288 else { 289 rb_scan_args(argc, argv, "1", &condition_value); 290 if (rb_block_given_p()) { 291 rb_warn("given block not used"); 292 } 293 func = find_index_i; 294 } 295 296 memo = NEW_MEMO(Qnil, condition_value, 0); 297 rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo); 298 return memo->u1.value; 299} 300 301static VALUE 302find_all_i(VALUE i, VALUE ary, int argc, VALUE *argv) 303{ 304 ENUM_WANT_SVALUE(); 305 306 if (RTEST(rb_yield(i))) { 307 rb_ary_push(ary, i); 308 } 309 return Qnil; 310} 311 312static VALUE 313enum_size(VALUE self, VALUE args) 314{ 315 VALUE r; 316 r = rb_check_funcall(self, id_size, 0, 0); 317 return (r == Qundef) ? Qnil : r; 318} 319 320/* 321 * call-seq: 322 * enum.find_all { |obj| block } -> array 323 * enum.select { |obj| block } -> array 324 * enum.find_all -> an_enumerator 325 * enum.select -> an_enumerator 326 * 327 * Returns an array containing all elements of +enum+ 328 * for which the given +block+ returns a true value. 329 * 330 * If no block is given, an Enumerator is returned instead. 331 * 332 * 333 * (1..10).find_all { |i| i % 3 == 0 } #=> [3, 6, 9] 334 * 335 * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4] 336 * 337 * See also Enumerable#reject. 338 */ 339 340static VALUE 341enum_find_all(VALUE obj) 342{ 343 VALUE ary; 344 345 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 346 347 ary = rb_ary_new(); 348 rb_block_call(obj, id_each, 0, 0, find_all_i, ary); 349 350 return ary; 351} 352 353static VALUE 354reject_i(VALUE i, VALUE ary, int argc, VALUE *argv) 355{ 356 ENUM_WANT_SVALUE(); 357 358 if (!RTEST(rb_yield(i))) { 359 rb_ary_push(ary, i); 360 } 361 return Qnil; 362} 363 364/* 365 * call-seq: 366 * enum.reject { |obj| block } -> array 367 * enum.reject -> an_enumerator 368 * 369 * Returns an array for all elements of +enum+ for which the given 370 * +block+ returns false. 371 * 372 * If no block is given, an Enumerator is returned instead. 373 * 374 * (1..10).reject { |i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10] 375 * 376 * [1, 2, 3, 4, 5].reject { |num| num.even? } #=> [1, 3, 5] 377 * 378 * See also Enumerable#find_all. 379 */ 380 381static VALUE 382enum_reject(VALUE obj) 383{ 384 VALUE ary; 385 386 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 387 388 ary = rb_ary_new(); 389 rb_block_call(obj, id_each, 0, 0, reject_i, ary); 390 391 return ary; 392} 393 394static VALUE 395collect_i(VALUE i, VALUE ary, int argc, VALUE *argv) 396{ 397 rb_ary_push(ary, enum_yield(argc, argv)); 398 399 return Qnil; 400} 401 402static VALUE 403collect_all(VALUE i, VALUE ary, int argc, VALUE *argv) 404{ 405 rb_thread_check_ints(); 406 rb_ary_push(ary, rb_enum_values_pack(argc, argv)); 407 408 return Qnil; 409} 410 411/* 412 * call-seq: 413 * enum.collect { |obj| block } -> array 414 * enum.map { |obj| block } -> array 415 * enum.collect -> an_enumerator 416 * enum.map -> an_enumerator 417 * 418 * Returns a new array with the results of running <em>block</em> once 419 * for every element in <i>enum</i>. 420 * 421 * If no block is given, an enumerator is returned instead. 422 * 423 * (1..4).collect { |i| i*i } #=> [1, 4, 9, 16] 424 * (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"] 425 * 426 */ 427 428static VALUE 429enum_collect(VALUE obj) 430{ 431 VALUE ary; 432 433 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 434 435 ary = rb_ary_new(); 436 rb_block_call(obj, id_each, 0, 0, collect_i, ary); 437 438 return ary; 439} 440 441static VALUE 442flat_map_i(VALUE i, VALUE ary, int argc, VALUE *argv) 443{ 444 VALUE tmp; 445 446 i = enum_yield(argc, argv); 447 tmp = rb_check_array_type(i); 448 449 if (NIL_P(tmp)) { 450 rb_ary_push(ary, i); 451 } 452 else { 453 rb_ary_concat(ary, tmp); 454 } 455 return Qnil; 456} 457 458/* 459 * call-seq: 460 * enum.flat_map { |obj| block } -> array 461 * enum.collect_concat { |obj| block } -> array 462 * enum.flat_map -> an_enumerator 463 * enum.collect_concat -> an_enumerator 464 * 465 * Returns a new array with the concatenated results of running 466 * <em>block</em> once for every element in <i>enum</i>. 467 * 468 * If no block is given, an enumerator is returned instead. 469 * 470 * [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4] 471 * [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100] 472 * 473 */ 474 475static VALUE 476enum_flat_map(VALUE obj) 477{ 478 VALUE ary; 479 480 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 481 482 ary = rb_ary_new(); 483 rb_block_call(obj, id_each, 0, 0, flat_map_i, ary); 484 485 return ary; 486} 487 488/* 489 * call-seq: 490 * enum.to_a -> array 491 * enum.entries -> array 492 * 493 * Returns an array containing the items in <i>enum</i>. 494 * 495 * (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7] 496 * { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]] 497 */ 498static VALUE 499enum_to_a(int argc, VALUE *argv, VALUE obj) 500{ 501 VALUE ary = rb_ary_new(); 502 503 rb_block_call(obj, id_each, argc, argv, collect_all, ary); 504 OBJ_INFECT(ary, obj); 505 506 return ary; 507} 508 509static VALUE 510inject_i(VALUE i, VALUE p, int argc, VALUE *argv) 511{ 512 NODE *memo = RNODE(p); 513 514 ENUM_WANT_SVALUE(); 515 516 if (memo->u2.argc == 0) { 517 memo->u2.argc = 1; 518 memo->u1.value = i; 519 } 520 else { 521 memo->u1.value = rb_yield_values(2, memo->u1.value, i); 522 } 523 return Qnil; 524} 525 526static VALUE 527inject_op_i(VALUE i, VALUE p, int argc, VALUE *argv) 528{ 529 NODE *memo = RNODE(p); 530 531 ENUM_WANT_SVALUE(); 532 533 if (memo->u2.argc == 0) { 534 memo->u2.argc = 1; 535 memo->u1.value = i; 536 } 537 else { 538 memo->u1.value = rb_funcall(memo->u1.value, memo->u3.id, 1, i); 539 } 540 return Qnil; 541} 542 543/* 544 * call-seq: 545 * enum.inject(initial, sym) -> obj 546 * enum.inject(sym) -> obj 547 * enum.inject(initial) { |memo, obj| block } -> obj 548 * enum.inject { |memo, obj| block } -> obj 549 * enum.reduce(initial, sym) -> obj 550 * enum.reduce(sym) -> obj 551 * enum.reduce(initial) { |memo, obj| block } -> obj 552 * enum.reduce { |memo, obj| block } -> obj 553 * 554 * Combines all elements of <i>enum</i> by applying a binary 555 * operation, specified by a block or a symbol that names a 556 * method or operator. 557 * 558 * If you specify a block, then for each element in <i>enum</i> 559 * the block is passed an accumulator value (<i>memo</i>) and the element. 560 * If you specify a symbol instead, then each element in the collection 561 * will be passed to the named method of <i>memo</i>. 562 * In either case, the result becomes the new value for <i>memo</i>. 563 * At the end of the iteration, the final value of <i>memo</i> is the 564 * return value for the method. 565 * 566 * If you do not explicitly specify an <i>initial</i> value for <i>memo</i>, 567 * then the first element of collection is used as the initial value 568 * of <i>memo</i>. 569 * 570 * 571 * # Sum some numbers 572 * (5..10).reduce(:+) #=> 45 573 * # Same using a block and inject 574 * (5..10).inject { |sum, n| sum + n } #=> 45 575 * # Multiply some numbers 576 * (5..10).reduce(1, :*) #=> 151200 577 * # Same using a block 578 * (5..10).inject(1) { |product, n| product * n } #=> 151200 579 * # find the longest word 580 * longest = %w{ cat sheep bear }.inject do |memo, word| 581 * memo.length > word.length ? memo : word 582 * end 583 * longest #=> "sheep" 584 * 585 */ 586static VALUE 587enum_inject(int argc, VALUE *argv, VALUE obj) 588{ 589 NODE *memo; 590 VALUE init, op; 591 VALUE (*iter)(VALUE, VALUE, int, VALUE*) = inject_i; 592 593 switch (rb_scan_args(argc, argv, "02", &init, &op)) { 594 case 0: 595 break; 596 case 1: 597 if (rb_block_given_p()) { 598 break; 599 } 600 op = (VALUE)rb_to_id(init); 601 argc = 0; 602 init = Qnil; 603 iter = inject_op_i; 604 break; 605 case 2: 606 if (rb_block_given_p()) { 607 rb_warning("given block not used"); 608 } 609 op = (VALUE)rb_to_id(op); 610 iter = inject_op_i; 611 break; 612 } 613 memo = NEW_MEMO(init, argc, op); 614 rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo); 615 return memo->u1.value; 616} 617 618static VALUE 619partition_i(VALUE i, VALUE arys, int argc, VALUE *argv) 620{ 621 NODE *memo = RNODE(arys); 622 VALUE ary; 623 ENUM_WANT_SVALUE(); 624 625 if (RTEST(rb_yield(i))) { 626 ary = memo->u1.value; 627 } 628 else { 629 ary = memo->u2.value; 630 } 631 rb_ary_push(ary, i); 632 return Qnil; 633} 634 635/* 636 * call-seq: 637 * enum.partition { |obj| block } -> [ true_array, false_array ] 638 * enum.partition -> an_enumerator 639 * 640 * Returns two arrays, the first containing the elements of 641 * <i>enum</i> for which the block evaluates to true, the second 642 * containing the rest. 643 * 644 * If no block is given, an enumerator is returned instead. 645 * 646 * (1..6).partition { |v| v.even? } #=> [[2, 4, 6], [1, 3, 5]] 647 * 648 */ 649 650static VALUE 651enum_partition(VALUE obj) 652{ 653 NODE *memo; 654 655 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 656 657 memo = NEW_MEMO(rb_ary_new(), rb_ary_new(), 0); 658 rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo); 659 660 return rb_assoc_new(memo->u1.value, memo->u2.value); 661} 662 663static VALUE 664group_by_i(VALUE i, VALUE hash, int argc, VALUE *argv) 665{ 666 VALUE group; 667 VALUE values; 668 669 ENUM_WANT_SVALUE(); 670 671 group = rb_yield(i); 672 values = rb_hash_aref(hash, group); 673 if (!RB_TYPE_P(values, T_ARRAY)) { 674 values = rb_ary_new3(1, i); 675 rb_hash_aset(hash, group, values); 676 } 677 else { 678 rb_ary_push(values, i); 679 } 680 return Qnil; 681} 682 683/* 684 * call-seq: 685 * enum.group_by { |obj| block } -> a_hash 686 * enum.group_by -> an_enumerator 687 * 688 * Groups the collection by result of the block. Returns a hash where the 689 * keys are the evaluated result from the block and the values are 690 * arrays of elements in the collection that correspond to the key. 691 * 692 * If no block is given an enumerator is returned. 693 * 694 * (1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]} 695 * 696 */ 697 698static VALUE 699enum_group_by(VALUE obj) 700{ 701 VALUE hash; 702 703 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 704 705 hash = rb_hash_new(); 706 rb_block_call(obj, id_each, 0, 0, group_by_i, hash); 707 OBJ_INFECT(hash, obj); 708 709 return hash; 710} 711 712static VALUE 713first_i(VALUE i, VALUE params, int argc, VALUE *argv) 714{ 715 NODE *memo = RNODE(params); 716 ENUM_WANT_SVALUE(); 717 718 memo->u1.value = i; 719 rb_iter_break(); 720 721 UNREACHABLE; 722} 723 724static VALUE enum_take(VALUE obj, VALUE n); 725 726/* 727 * call-seq: 728 * enum.first -> obj or nil 729 * enum.first(n) -> an_array 730 * 731 * Returns the first element, or the first +n+ elements, of the enumerable. 732 * If the enumerable is empty, the first form returns <code>nil</code>, and the 733 * second form returns an empty array. 734 * 735 * %w[foo bar baz].first #=> "foo" 736 * %w[foo bar baz].first(2) #=> ["foo", "bar"] 737 * %w[foo bar baz].first(10) #=> ["foo", "bar", "baz"] 738 * [].first #=> nil 739 * 740 */ 741 742static VALUE 743enum_first(int argc, VALUE *argv, VALUE obj) 744{ 745 NODE *memo; 746 rb_check_arity(argc, 0, 1); 747 if (argc > 0) { 748 return enum_take(obj, argv[0]); 749 } 750 else { 751 memo = NEW_MEMO(Qnil, 0, 0); 752 rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo); 753 return memo->u1.value; 754 } 755} 756 757 758/* 759 * call-seq: 760 * enum.sort -> array 761 * enum.sort { |a, b| block } -> array 762 * 763 * Returns an array containing the items in <i>enum</i> sorted, 764 * either according to their own <code><=></code> method, or by using 765 * the results of the supplied block. The block should return -1, 0, or 766 * +1 depending on the comparison between <i>a</i> and <i>b</i>. As of 767 * Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a 768 * built-in Schwartzian Transform, useful when key computation or 769 * comparison is expensive. 770 * 771 * %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"] 772 * (1..10).sort { |a, b| b <=> a } #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 773 */ 774 775static VALUE 776enum_sort(VALUE obj) 777{ 778 return rb_ary_sort(enum_to_a(0, 0, obj)); 779} 780 781#define SORT_BY_BUFSIZE 16 782struct sort_by_data { 783 VALUE ary; 784 VALUE buf; 785 long n; 786}; 787 788static VALUE 789sort_by_i(VALUE i, VALUE _data, int argc, VALUE *argv) 790{ 791 struct sort_by_data *data = (struct sort_by_data *)&RNODE(_data)->u1; 792 VALUE ary = data->ary; 793 VALUE v; 794 795 ENUM_WANT_SVALUE(); 796 797 v = rb_yield(i); 798 799 if (RBASIC(ary)->klass) { 800 rb_raise(rb_eRuntimeError, "sort_by reentered"); 801 } 802 if (RARRAY_LEN(data->buf) != SORT_BY_BUFSIZE*2) { 803 rb_raise(rb_eRuntimeError, "sort_by reentered"); 804 } 805 806 RARRAY_PTR(data->buf)[data->n*2] = v; 807 RARRAY_PTR(data->buf)[data->n*2+1] = i; 808 data->n++; 809 if (data->n == SORT_BY_BUFSIZE) { 810 rb_ary_concat(ary, data->buf); 811 data->n = 0; 812 } 813 return Qnil; 814} 815 816static int 817sort_by_cmp(const void *ap, const void *bp, void *data) 818{ 819 VALUE a; 820 VALUE b; 821 VALUE ary = (VALUE)data; 822 823 if (RBASIC(ary)->klass) { 824 rb_raise(rb_eRuntimeError, "sort_by reentered"); 825 } 826 827 a = *(VALUE *)ap; 828 b = *(VALUE *)bp; 829 830 return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b); 831} 832 833/* 834 * call-seq: 835 * enum.sort_by { |obj| block } -> array 836 * enum.sort_by -> an_enumerator 837 * 838 * Sorts <i>enum</i> using a set of keys generated by mapping the 839 * values in <i>enum</i> through the given block. 840 * 841 * If no block is given, an enumerator is returned instead. 842 * 843 * %w{apple pear fig}.sort_by { |word| word.length} 844 * #=> ["fig", "pear", "apple"] 845 * 846 * The current implementation of <code>sort_by</code> generates an 847 * array of tuples containing the original collection element and the 848 * mapped value. This makes <code>sort_by</code> fairly expensive when 849 * the keysets are simple. 850 * 851 * require 'benchmark' 852 * 853 * a = (1..100000).map { rand(100000) } 854 * 855 * Benchmark.bm(10) do |b| 856 * b.report("Sort") { a.sort } 857 * b.report("Sort by") { a.sort_by { |a| a } } 858 * end 859 * 860 * <em>produces:</em> 861 * 862 * user system total real 863 * Sort 0.180000 0.000000 0.180000 ( 0.175469) 864 * Sort by 1.980000 0.040000 2.020000 ( 2.013586) 865 * 866 * However, consider the case where comparing the keys is a non-trivial 867 * operation. The following code sorts some files on modification time 868 * using the basic <code>sort</code> method. 869 * 870 * files = Dir["*"] 871 * sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime } 872 * sorted #=> ["mon", "tues", "wed", "thurs"] 873 * 874 * This sort is inefficient: it generates two new <code>File</code> 875 * objects during every comparison. A slightly better technique is to 876 * use the <code>Kernel#test</code> method to generate the modification 877 * times directly. 878 * 879 * files = Dir["*"] 880 * sorted = files.sort { |a, b| 881 * test(?M, a) <=> test(?M, b) 882 * } 883 * sorted #=> ["mon", "tues", "wed", "thurs"] 884 * 885 * This still generates many unnecessary <code>Time</code> objects. A 886 * more efficient technique is to cache the sort keys (modification 887 * times in this case) before the sort. Perl users often call this 888 * approach a Schwartzian Transform, after Randal Schwartz. We 889 * construct a temporary array, where each element is an array 890 * containing our sort key along with the filename. We sort this array, 891 * and then extract the filename from the result. 892 * 893 * sorted = Dir["*"].collect { |f| 894 * [test(?M, f), f] 895 * }.sort.collect { |f| f[1] } 896 * sorted #=> ["mon", "tues", "wed", "thurs"] 897 * 898 * This is exactly what <code>sort_by</code> does internally. 899 * 900 * sorted = Dir["*"].sort_by { |f| test(?M, f) } 901 * sorted #=> ["mon", "tues", "wed", "thurs"] 902 */ 903 904static VALUE 905enum_sort_by(VALUE obj) 906{ 907 VALUE ary, buf; 908 NODE *memo; 909 long i; 910 struct sort_by_data *data; 911 912 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 913 914 if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) { 915 ary = rb_ary_new2(RARRAY_LEN(obj)*2); 916 } 917 else { 918 ary = rb_ary_new(); 919 } 920 RBASIC(ary)->klass = 0; 921 buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2); 922 rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil); 923 memo = NEW_MEMO(0, 0, 0); 924 OBJ_INFECT(memo, obj); 925 data = (struct sort_by_data *)&memo->u1; 926 data->ary = ary; 927 data->buf = buf; 928 data->n = 0; 929 rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo); 930 ary = data->ary; 931 buf = data->buf; 932 if (data->n) { 933 rb_ary_resize(buf, data->n*2); 934 rb_ary_concat(ary, buf); 935 } 936 if (RARRAY_LEN(ary) > 2) { 937 ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary)/2, 2*sizeof(VALUE), 938 sort_by_cmp, (void *)ary); 939 } 940 if (RBASIC(ary)->klass) { 941 rb_raise(rb_eRuntimeError, "sort_by reentered"); 942 } 943 for (i=1; i<RARRAY_LEN(ary); i+=2) { 944 RARRAY_PTR(ary)[i/2] = RARRAY_PTR(ary)[i]; 945 } 946 rb_ary_resize(ary, RARRAY_LEN(ary)/2); 947 RBASIC(ary)->klass = rb_cArray; 948 OBJ_INFECT(ary, memo); 949 950 return ary; 951} 952 953#define ENUMFUNC(name) rb_block_given_p() ? name##_iter_i : name##_i 954 955#define DEFINE_ENUMFUNCS(name) \ 956static VALUE enum_##name##_func(VALUE result, NODE *memo); \ 957\ 958static VALUE \ 959name##_i(VALUE i, VALUE memo, int argc, VALUE *argv) \ 960{ \ 961 return enum_##name##_func(rb_enum_values_pack(argc, argv), RNODE(memo)); \ 962} \ 963\ 964static VALUE \ 965name##_iter_i(VALUE i, VALUE memo, int argc, VALUE *argv) \ 966{ \ 967 return enum_##name##_func(enum_yield(argc, argv), RNODE(memo)); \ 968} \ 969\ 970static VALUE \ 971enum_##name##_func(VALUE result, NODE *memo) 972 973DEFINE_ENUMFUNCS(all) 974{ 975 if (!RTEST(result)) { 976 memo->u1.value = Qfalse; 977 rb_iter_break(); 978 } 979 return Qnil; 980} 981 982/* 983 * call-seq: 984 * enum.all? [{ |obj| block } ] -> true or false 985 * 986 * Passes each element of the collection to the given block. The method 987 * returns <code>true</code> if the block never returns 988 * <code>false</code> or <code>nil</code>. If the block is not given, 989 * Ruby adds an implicit block of <code>{ |obj| obj }</code> which will 990 * cause #all? to return +true+ when none of the collection members are 991 * +false+ or +nil+. 992 * 993 * %w[ant bear cat].all? { |word| word.length >= 3 } #=> true 994 * %w[ant bear cat].all? { |word| word.length >= 4 } #=> false 995 * [nil, true, 99].all? #=> false 996 * 997 */ 998 999static VALUE 1000enum_all(VALUE obj) 1001{ 1002 NODE *memo = NEW_MEMO(Qtrue, 0, 0); 1003 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo); 1004 return memo->u1.value; 1005} 1006 1007DEFINE_ENUMFUNCS(any) 1008{ 1009 if (RTEST(result)) { 1010 memo->u1.value = Qtrue; 1011 rb_iter_break(); 1012 } 1013 return Qnil; 1014} 1015 1016/* 1017 * call-seq: 1018 * enum.any? [{ |obj| block }] -> true or false 1019 * 1020 * Passes each element of the collection to the given block. The method 1021 * returns <code>true</code> if the block ever returns a value other 1022 * than <code>false</code> or <code>nil</code>. If the block is not 1023 * given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that 1024 * will cause #any? to return +true+ if at least one of the collection 1025 * members is not +false+ or +nil+. 1026 * 1027 * %w[ant bear cat].any? { |word| word.length >= 3 } #=> true 1028 * %w[ant bear cat].any? { |word| word.length >= 4 } #=> true 1029 * [nil, true, 99].any? #=> true 1030 * 1031 */ 1032 1033static VALUE 1034enum_any(VALUE obj) 1035{ 1036 NODE *memo = NEW_MEMO(Qfalse, 0, 0); 1037 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo); 1038 return memo->u1.value; 1039} 1040 1041DEFINE_ENUMFUNCS(one) 1042{ 1043 if (RTEST(result)) { 1044 if (memo->u1.value == Qundef) { 1045 memo->u1.value = Qtrue; 1046 } 1047 else if (memo->u1.value == Qtrue) { 1048 memo->u1.value = Qfalse; 1049 rb_iter_break(); 1050 } 1051 } 1052 return Qnil; 1053} 1054 1055/* 1056 * call-seq: 1057 * enum.one? [{ |obj| block }] -> true or false 1058 * 1059 * Passes each element of the collection to the given block. The method 1060 * returns <code>true</code> if the block returns <code>true</code> 1061 * exactly once. If the block is not given, <code>one?</code> will return 1062 * <code>true</code> only if exactly one of the collection members is 1063 * true. 1064 * 1065 * %w{ant bear cat}.one? { |word| word.length == 4 } #=> true 1066 * %w{ant bear cat}.one? { |word| word.length > 4 } #=> false 1067 * %w{ant bear cat}.one? { |word| word.length < 4 } #=> false 1068 * [ nil, true, 99 ].one? #=> false 1069 * [ nil, true, false ].one? #=> true 1070 * 1071 */ 1072 1073static VALUE 1074enum_one(VALUE obj) 1075{ 1076 NODE *memo = NEW_MEMO(Qundef, 0, 0); 1077 VALUE result; 1078 1079 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo); 1080 result = memo->u1.value; 1081 if (result == Qundef) return Qfalse; 1082 return result; 1083} 1084 1085DEFINE_ENUMFUNCS(none) 1086{ 1087 if (RTEST(result)) { 1088 memo->u1.value = Qfalse; 1089 rb_iter_break(); 1090 } 1091 return Qnil; 1092} 1093 1094/* 1095 * call-seq: 1096 * enum.none? [{ |obj| block }] -> true or false 1097 * 1098 * Passes each element of the collection to the given block. The method 1099 * returns <code>true</code> if the block never returns <code>true</code> 1100 * for all elements. If the block is not given, <code>none?</code> will return 1101 * <code>true</code> only if none of the collection members is true. 1102 * 1103 * %w{ant bear cat}.none? { |word| word.length == 5 } #=> true 1104 * %w{ant bear cat}.none? { |word| word.length >= 4 } #=> false 1105 * [].none? #=> true 1106 * [nil].none? #=> true 1107 * [nil, false].none? #=> true 1108 */ 1109static VALUE 1110enum_none(VALUE obj) 1111{ 1112 NODE *memo = NEW_MEMO(Qtrue, 0, 0); 1113 rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo); 1114 return memo->u1.value; 1115} 1116 1117static VALUE 1118min_i(VALUE i, VALUE args, int argc, VALUE *argv) 1119{ 1120 VALUE cmp; 1121 NODE *memo = RNODE(args); 1122 1123 ENUM_WANT_SVALUE(); 1124 1125 if (memo->u1.value == Qundef) { 1126 memo->u1.value = i; 1127 } 1128 else { 1129 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value); 1130 if (rb_cmpint(cmp, i, memo->u1.value) < 0) { 1131 memo->u1.value = i; 1132 } 1133 } 1134 return Qnil; 1135} 1136 1137static VALUE 1138min_ii(VALUE i, VALUE args, int argc, VALUE *argv) 1139{ 1140 VALUE cmp; 1141 NODE *memo = RNODE(args); 1142 1143 ENUM_WANT_SVALUE(); 1144 1145 if (memo->u1.value == Qundef) { 1146 memo->u1.value = i; 1147 } 1148 else { 1149 cmp = rb_yield_values(2, i, memo->u1.value); 1150 if (rb_cmpint(cmp, i, memo->u1.value) < 0) { 1151 memo->u1.value = i; 1152 } 1153 } 1154 return Qnil; 1155} 1156 1157 1158/* 1159 * call-seq: 1160 * enum.min -> obj 1161 * enum.min { |a, b| block } -> obj 1162 * 1163 * Returns the object in <i>enum</i> with the minimum value. The 1164 * first form assumes all objects implement <code>Comparable</code>; 1165 * the second uses the block to return <em>a <=> b</em>. 1166 * 1167 * a = %w(albatross dog horse) 1168 * a.min #=> "albatross" 1169 * a.min { |a, b| a.length <=> b.length } #=> "dog" 1170 */ 1171 1172static VALUE 1173enum_min(VALUE obj) 1174{ 1175 NODE *memo = NEW_MEMO(Qundef, 0, 0); 1176 VALUE result; 1177 1178 if (rb_block_given_p()) { 1179 rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)memo); 1180 } 1181 else { 1182 rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)memo); 1183 } 1184 result = memo->u1.value; 1185 if (result == Qundef) return Qnil; 1186 return result; 1187} 1188 1189static VALUE 1190max_i(VALUE i, VALUE args, int argc, VALUE *argv) 1191{ 1192 NODE *memo = RNODE(args); 1193 VALUE cmp; 1194 1195 ENUM_WANT_SVALUE(); 1196 1197 if (memo->u1.value == Qundef) { 1198 memo->u1.value = i; 1199 } 1200 else { 1201 cmp = rb_funcall(i, id_cmp, 1, memo->u1.value); 1202 if (rb_cmpint(cmp, i, memo->u1.value) > 0) { 1203 memo->u1.value = i; 1204 } 1205 } 1206 return Qnil; 1207} 1208 1209static VALUE 1210max_ii(VALUE i, VALUE args, int argc, VALUE *argv) 1211{ 1212 NODE *memo = RNODE(args); 1213 VALUE cmp; 1214 1215 ENUM_WANT_SVALUE(); 1216 1217 if (memo->u1.value == Qundef) { 1218 memo->u1.value = i; 1219 } 1220 else { 1221 cmp = rb_yield_values(2, i, memo->u1.value); 1222 if (rb_cmpint(cmp, i, memo->u1.value) > 0) { 1223 memo->u1.value = i; 1224 } 1225 } 1226 return Qnil; 1227} 1228 1229/* 1230 * call-seq: 1231 * enum.max -> obj 1232 * enum.max { |a, b| block } -> obj 1233 * 1234 * Returns the object in _enum_ with the maximum value. The 1235 * first form assumes all objects implement <code>Comparable</code>; 1236 * the second uses the block to return <em>a <=> b</em>. 1237 * 1238 * a = %w(albatross dog horse) 1239 * a.max #=> "horse" 1240 * a.max { |a, b| a.length <=> b.length } #=> "albatross" 1241 */ 1242 1243static VALUE 1244enum_max(VALUE obj) 1245{ 1246 NODE *memo = NEW_MEMO(Qundef, 0, 0); 1247 VALUE result; 1248 1249 if (rb_block_given_p()) { 1250 rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo); 1251 } 1252 else { 1253 rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo); 1254 } 1255 result = memo->u1.value; 1256 if (result == Qundef) return Qnil; 1257 return result; 1258} 1259 1260struct minmax_t { 1261 VALUE min; 1262 VALUE max; 1263 VALUE last; 1264}; 1265 1266STATIC_ASSERT(minmax_t, sizeof(struct minmax_t) <= sizeof(NODE) - offsetof(NODE, u1)); 1267 1268static void 1269minmax_i_update(VALUE i, VALUE j, struct minmax_t *memo) 1270{ 1271 int n; 1272 1273 if (memo->min == Qundef) { 1274 memo->min = i; 1275 memo->max = j; 1276 } 1277 else { 1278 n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo->min), i, memo->min); 1279 if (n < 0) { 1280 memo->min = i; 1281 } 1282 n = rb_cmpint(rb_funcall(j, id_cmp, 1, memo->max), j, memo->max); 1283 if (n > 0) { 1284 memo->max = j; 1285 } 1286 } 1287} 1288 1289static VALUE 1290minmax_i(VALUE i, VALUE _memo, int argc, VALUE *argv) 1291{ 1292 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value; 1293 int n; 1294 VALUE j; 1295 1296 ENUM_WANT_SVALUE(); 1297 1298 if (memo->last == Qundef) { 1299 memo->last = i; 1300 return Qnil; 1301 } 1302 j = memo->last; 1303 memo->last = Qundef; 1304 1305 n = rb_cmpint(rb_funcall(j, id_cmp, 1, i), j, i); 1306 if (n == 0) 1307 i = j; 1308 else if (n < 0) { 1309 VALUE tmp; 1310 tmp = i; 1311 i = j; 1312 j = tmp; 1313 } 1314 1315 minmax_i_update(i, j, memo); 1316 1317 return Qnil; 1318} 1319 1320static void 1321minmax_ii_update(VALUE i, VALUE j, struct minmax_t *memo) 1322{ 1323 int n; 1324 1325 if (memo->min == Qundef) { 1326 memo->min = i; 1327 memo->max = j; 1328 } 1329 else { 1330 n = rb_cmpint(rb_yield_values(2, i, memo->min), i, memo->min); 1331 if (n < 0) { 1332 memo->min = i; 1333 } 1334 n = rb_cmpint(rb_yield_values(2, j, memo->max), j, memo->max); 1335 if (n > 0) { 1336 memo->max = j; 1337 } 1338 } 1339} 1340 1341static VALUE 1342minmax_ii(VALUE i, VALUE _memo, int argc, VALUE *argv) 1343{ 1344 struct minmax_t *memo = (struct minmax_t *)&RNODE(_memo)->u1.value; 1345 int n; 1346 VALUE j; 1347 1348 ENUM_WANT_SVALUE(); 1349 1350 if (memo->last == Qundef) { 1351 memo->last = i; 1352 return Qnil; 1353 } 1354 j = memo->last; 1355 memo->last = Qundef; 1356 1357 n = rb_cmpint(rb_yield_values(2, j, i), j, i); 1358 if (n == 0) 1359 i = j; 1360 else if (n < 0) { 1361 VALUE tmp; 1362 tmp = i; 1363 i = j; 1364 j = tmp; 1365 } 1366 1367 minmax_ii_update(i, j, memo); 1368 1369 return Qnil; 1370} 1371 1372/* 1373 * call-seq: 1374 * enum.minmax -> [min, max] 1375 * enum.minmax { |a, b| block } -> [min, max] 1376 * 1377 * Returns two elements array which contains the minimum and the 1378 * maximum value in the enumerable. The first form assumes all 1379 * objects implement <code>Comparable</code>; the second uses the 1380 * block to return <em>a <=> b</em>. 1381 * 1382 * a = %w(albatross dog horse) 1383 * a.minmax #=> ["albatross", "horse"] 1384 * a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"] 1385 */ 1386 1387static VALUE 1388enum_minmax(VALUE obj) 1389{ 1390 NODE *memo = NEW_MEMO(Qundef, Qundef, Qundef); 1391 struct minmax_t *m = (struct minmax_t *)&memo->u1.value; 1392 VALUE ary = rb_ary_new3(2, Qnil, Qnil); 1393 1394 m->min = Qundef; 1395 m->last = Qundef; 1396 if (rb_block_given_p()) { 1397 rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)memo); 1398 if (m->last != Qundef) 1399 minmax_ii_update(m->last, m->last, m); 1400 } 1401 else { 1402 rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)memo); 1403 if (m->last != Qundef) 1404 minmax_i_update(m->last, m->last, m); 1405 } 1406 if (m->min != Qundef) { 1407 rb_ary_store(ary, 0, m->min); 1408 rb_ary_store(ary, 1, m->max); 1409 } 1410 return ary; 1411} 1412 1413static VALUE 1414min_by_i(VALUE i, VALUE args, int argc, VALUE *argv) 1415{ 1416 NODE *memo = RNODE(args); 1417 VALUE v; 1418 1419 ENUM_WANT_SVALUE(); 1420 1421 v = rb_yield(i); 1422 if (memo->u1.value == Qundef) { 1423 memo->u1.value = v; 1424 memo->u2.value = i; 1425 } 1426 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) < 0) { 1427 memo->u1.value = v; 1428 memo->u2.value = i; 1429 } 1430 return Qnil; 1431} 1432 1433/* 1434 * call-seq: 1435 * enum.min_by { |obj| block } -> obj 1436 * enum.min_by -> an_enumerator 1437 * 1438 * Returns the object in <i>enum</i> that gives the minimum 1439 * value from the given block. 1440 * 1441 * If no block is given, an enumerator is returned instead. 1442 * 1443 * a = %w(albatross dog horse) 1444 * a.min_by { |x| x.length } #=> "dog" 1445 */ 1446 1447static VALUE 1448enum_min_by(VALUE obj) 1449{ 1450 NODE *memo; 1451 1452 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 1453 1454 memo = NEW_MEMO(Qundef, Qnil, 0); 1455 rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo); 1456 return memo->u2.value; 1457} 1458 1459static VALUE 1460max_by_i(VALUE i, VALUE args, int argc, VALUE *argv) 1461{ 1462 NODE *memo = RNODE(args); 1463 VALUE v; 1464 1465 ENUM_WANT_SVALUE(); 1466 1467 v = rb_yield(i); 1468 if (memo->u1.value == Qundef) { 1469 memo->u1.value = v; 1470 memo->u2.value = i; 1471 } 1472 else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo->u1.value), v, memo->u1.value) > 0) { 1473 memo->u1.value = v; 1474 memo->u2.value = i; 1475 } 1476 return Qnil; 1477} 1478 1479/* 1480 * call-seq: 1481 * enum.max_by { |obj| block } -> obj 1482 * enum.max_by -> an_enumerator 1483 * 1484 * Returns the object in <i>enum</i> that gives the maximum 1485 * value from the given block. 1486 * 1487 * If no block is given, an enumerator is returned instead. 1488 * 1489 * a = %w(albatross dog horse) 1490 * a.max_by { |x| x.length } #=> "albatross" 1491 */ 1492 1493static VALUE 1494enum_max_by(VALUE obj) 1495{ 1496 NODE *memo; 1497 1498 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 1499 1500 memo = NEW_MEMO(Qundef, Qnil, 0); 1501 rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo); 1502 return memo->u2.value; 1503} 1504 1505struct minmax_by_t { 1506 VALUE min_bv; 1507 VALUE max_bv; 1508 VALUE min; 1509 VALUE max; 1510 VALUE last_bv; 1511 VALUE last; 1512}; 1513 1514static void 1515minmax_by_i_update(VALUE v1, VALUE v2, VALUE i1, VALUE i2, struct minmax_by_t *memo) 1516{ 1517 if (memo->min_bv == Qundef) { 1518 memo->min_bv = v1; 1519 memo->max_bv = v2; 1520 memo->min = i1; 1521 memo->max = i2; 1522 } 1523 else { 1524 if (rb_cmpint(rb_funcall(v1, id_cmp, 1, memo->min_bv), v1, memo->min_bv) < 0) { 1525 memo->min_bv = v1; 1526 memo->min = i1; 1527 } 1528 if (rb_cmpint(rb_funcall(v2, id_cmp, 1, memo->max_bv), v2, memo->max_bv) > 0) { 1529 memo->max_bv = v2; 1530 memo->max = i2; 1531 } 1532 } 1533} 1534 1535static VALUE 1536minmax_by_i(VALUE i, VALUE _memo, int argc, VALUE *argv) 1537{ 1538 struct minmax_by_t *memo = MEMO_FOR(struct minmax_by_t, _memo); 1539 VALUE vi, vj, j; 1540 int n; 1541 1542 ENUM_WANT_SVALUE(); 1543 1544 vi = rb_yield(i); 1545 1546 if (memo->last_bv == Qundef) { 1547 memo->last_bv = vi; 1548 memo->last = i; 1549 return Qnil; 1550 } 1551 vj = memo->last_bv; 1552 j = memo->last; 1553 memo->last_bv = Qundef; 1554 1555 n = rb_cmpint(rb_funcall(vj, id_cmp, 1, vi), vj, vi); 1556 if (n == 0) { 1557 i = j; 1558 vi = vj; 1559 } 1560 else if (n < 0) { 1561 VALUE tmp; 1562 tmp = i; 1563 i = j; 1564 j = tmp; 1565 tmp = vi; 1566 vi = vj; 1567 vj = tmp; 1568 } 1569 1570 minmax_by_i_update(vi, vj, i, j, memo); 1571 1572 return Qnil; 1573} 1574 1575/* 1576 * call-seq: 1577 * enum.minmax_by { |obj| block } -> [min, max] 1578 * enum.minmax_by -> an_enumerator 1579 * 1580 * Returns a two element array containing the objects in 1581 * <i>enum</i> that correspond to the minimum and maximum values respectively 1582 * from the given block. 1583 * 1584 * If no block is given, an enumerator is returned instead. 1585 * 1586 * a = %w(albatross dog horse) 1587 * a.minmax_by { |x| x.length } #=> ["dog", "albatross"] 1588 */ 1589 1590static VALUE 1591enum_minmax_by(VALUE obj) 1592{ 1593 VALUE memo; 1594 struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo); 1595 1596 RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size); 1597 1598 m->min_bv = Qundef; 1599 m->max_bv = Qundef; 1600 m->min = Qnil; 1601 m->max = Qnil; 1602 m->last_bv = Qundef; 1603 m->last = Qundef; 1604 rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo); 1605 if (m->last_bv != Qundef) 1606 minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m); 1607 m = MEMO_FOR(struct minmax_by_t, memo); 1608 return rb_assoc_new(m->min, m->max); 1609} 1610 1611static VALUE 1612member_i(VALUE iter, VALUE args, int argc, VALUE *argv) 1613{ 1614 NODE *memo = RNODE(args); 1615 1616 if (rb_equal(rb_enum_values_pack(argc, argv), memo->u1.value)) { 1617 memo->u2.value = Qtrue; 1618 rb_iter_break(); 1619 } 1620 return Qnil; 1621} 1622 1623/* 1624 * call-seq: 1625 * enum.include?(obj) -> true or false 1626 * enum.member?(obj) -> true or false 1627 * 1628 * Returns <code>true</code> if any member of <i>enum</i> equals 1629 * <i>obj</i>. Equality is tested using <code>==</code>. 1630 * 1631 * IO.constants.include? :SEEK_SET #=> true 1632 * IO.constants.include? :SEEK_NO_FURTHER #=> false 1633 * 1634 */ 1635 1636static VALUE 1637enum_member(VALUE obj, VALUE val) 1638{ 1639 NODE *memo = NEW_MEMO(val, Qfalse, 0); 1640 1641 rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo); 1642 return memo->u2.value; 1643} 1644 1645static VALUE 1646each_with_index_i(VALUE i, VALUE memo, int argc, VALUE *argv) 1647{ 1648 long n = RNODE(memo)->u3.cnt++; 1649 1650 return rb_yield_values(2, rb_enum_values_pack(argc, argv), INT2NUM(n)); 1651} 1652 1653/* 1654 * call-seq: 1655 * enum.each_with_index(*args) { |obj, i| block } -> enum 1656 * enum.each_with_index(*args) -> an_enumerator 1657 * 1658 * Calls <em>block</em> with two arguments, the item and its index, 1659 * for each item in <i>enum</i>. Given arguments are passed through 1660 * to #each(). 1661 * 1662 * If no block is given, an enumerator is returned instead. 1663 * 1664 * hash = Hash.new 1665 * %w(cat dog wombat).each_with_index { |item, index| 1666 * hash[item] = index 1667 * } 1668 * hash #=> {"cat"=>0, "dog"=>1, "wombat"=>2} 1669 * 1670 */ 1671 1672static VALUE 1673enum_each_with_index(int argc, VALUE *argv, VALUE obj) 1674{ 1675 NODE *memo; 1676 1677 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size); 1678 1679 memo = NEW_MEMO(0, 0, 0); 1680 rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo); 1681 return obj; 1682} 1683 1684 1685/* 1686 * call-seq: 1687 * enum.reverse_each(*args) { |item| block } -> enum 1688 * enum.reverse_each(*args) -> an_enumerator 1689 * 1690 * Builds a temporary array and traverses that array in reverse order. 1691 * 1692 * If no block is given, an enumerator is returned instead. 1693 * 1694 * (1..3).reverse_each { |v| p v } 1695 * 1696 * produces: 1697 * 1698 * 3 1699 * 2 1700 * 1 1701 */ 1702 1703static VALUE 1704enum_reverse_each(int argc, VALUE *argv, VALUE obj) 1705{ 1706 VALUE ary; 1707 long i; 1708 1709 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size); 1710 1711 ary = enum_to_a(argc, argv, obj); 1712 1713 for (i = RARRAY_LEN(ary); --i >= 0; ) { 1714 rb_yield(RARRAY_PTR(ary)[i]); 1715 } 1716 1717 return obj; 1718} 1719 1720 1721static VALUE 1722each_val_i(VALUE i, VALUE p, int argc, VALUE *argv) 1723{ 1724 ENUM_WANT_SVALUE(); 1725 rb_yield(i); 1726 return Qnil; 1727} 1728 1729/* 1730 * call-seq: 1731 * enum.each_entry { |obj| block } -> enum 1732 * enum.each_entry -> an_enumerator 1733 * 1734 * Calls <i>block</i> once for each element in +self+, passing that 1735 * element as a parameter, converting multiple values from yield to an 1736 * array. 1737 * 1738 * If no block is given, an enumerator is returned instead. 1739 * 1740 * class Foo 1741 * include Enumerable 1742 * def each 1743 * yield 1 1744 * yield 1, 2 1745 * yield 1746 * end 1747 * end 1748 * Foo.new.each_entry{ |o| p o } 1749 * 1750 * produces: 1751 * 1752 * 1 1753 * [1, 2] 1754 * nil 1755 * 1756 */ 1757 1758static VALUE 1759enum_each_entry(int argc, VALUE *argv, VALUE obj) 1760{ 1761 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size); 1762 rb_block_call(obj, id_each, argc, argv, each_val_i, 0); 1763 return obj; 1764} 1765 1766static VALUE 1767each_slice_i(VALUE i, VALUE m, int argc, VALUE *argv) 1768{ 1769 NODE *memo = RNODE(m); 1770 VALUE ary = memo->u1.value; 1771 VALUE v = Qnil; 1772 long size = memo->u3.cnt; 1773 ENUM_WANT_SVALUE(); 1774 1775 rb_ary_push(ary, i); 1776 1777 if (RARRAY_LEN(ary) == size) { 1778 v = rb_yield(ary); 1779 memo->u1.value = rb_ary_new2(size); 1780 } 1781 1782 return v; 1783} 1784 1785static VALUE 1786enum_each_slice_size(VALUE obj, VALUE args) 1787{ 1788 VALUE n, size; 1789 long slice_size = NUM2LONG(RARRAY_PTR(args)[0]); 1790 if (slice_size <= 0) rb_raise(rb_eArgError, "invalid slice size"); 1791 1792 size = enum_size(obj, 0); 1793 if (size == Qnil) return Qnil; 1794 1795 n = rb_funcall(size, '+', 1, LONG2NUM(slice_size-1)); 1796 return rb_funcall(n, id_div, 1, LONG2FIX(slice_size)); 1797} 1798 1799/* 1800 * call-seq: 1801 * enum.each_slice(n) { ... } -> nil 1802 * enum.each_slice(n) -> an_enumerator 1803 * 1804 * Iterates the given block for each slice of <n> elements. If no 1805 * block is given, returns an enumerator. 1806 * 1807 * (1..10).each_slice(3) { |a| p a } 1808 * # outputs below 1809 * [1, 2, 3] 1810 * [4, 5, 6] 1811 * [7, 8, 9] 1812 * [10] 1813 * 1814 */ 1815static VALUE 1816enum_each_slice(VALUE obj, VALUE n) 1817{ 1818 long size = NUM2LONG(n); 1819 VALUE ary; 1820 NODE *memo; 1821 1822 if (size <= 0) rb_raise(rb_eArgError, "invalid slice size"); 1823 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size); 1824 ary = rb_ary_new2(size); 1825 memo = NEW_MEMO(ary, 0, size); 1826 rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo); 1827 ary = memo->u1.value; 1828 if (RARRAY_LEN(ary) > 0) rb_yield(ary); 1829 1830 return Qnil; 1831} 1832 1833static VALUE 1834each_cons_i(VALUE i, VALUE args, int argc, VALUE *argv) 1835{ 1836 NODE *memo = RNODE(args); 1837 VALUE ary = memo->u1.value; 1838 VALUE v = Qnil; 1839 long size = memo->u3.cnt; 1840 ENUM_WANT_SVALUE(); 1841 1842 if (RARRAY_LEN(ary) == size) { 1843 rb_ary_shift(ary); 1844 } 1845 rb_ary_push(ary, i); 1846 if (RARRAY_LEN(ary) == size) { 1847 v = rb_yield(rb_ary_dup(ary)); 1848 } 1849 return v; 1850} 1851 1852static VALUE 1853enum_each_cons_size(VALUE obj, VALUE args) 1854{ 1855 VALUE n, size; 1856 long cons_size = NUM2LONG(RARRAY_PTR(args)[0]); 1857 if (cons_size <= 0) rb_raise(rb_eArgError, "invalid size"); 1858 1859 size = enum_size(obj, 0); 1860 if (size == Qnil) return Qnil; 1861 1862 n = rb_funcall(size, '+', 1, LONG2NUM(1 - cons_size)); 1863 return (rb_cmpint(rb_funcall(n, id_cmp, 1, LONG2FIX(0)), n, LONG2FIX(0)) == -1) ? LONG2FIX(0) : n; 1864} 1865 1866/* 1867 * call-seq: 1868 * enum.each_cons(n) { ... } -> nil 1869 * enum.each_cons(n) -> an_enumerator 1870 * 1871 * Iterates the given block for each array of consecutive <n> 1872 * elements. If no block is given, returns an enumerator. 1873 * 1874 * e.g.: 1875 * (1..10).each_cons(3) { |a| p a } 1876 * # outputs below 1877 * [1, 2, 3] 1878 * [2, 3, 4] 1879 * [3, 4, 5] 1880 * [4, 5, 6] 1881 * [5, 6, 7] 1882 * [6, 7, 8] 1883 * [7, 8, 9] 1884 * [8, 9, 10] 1885 * 1886 */ 1887static VALUE 1888enum_each_cons(VALUE obj, VALUE n) 1889{ 1890 long size = NUM2LONG(n); 1891 NODE *memo; 1892 1893 if (size <= 0) rb_raise(rb_eArgError, "invalid size"); 1894 RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size); 1895 memo = NEW_MEMO(rb_ary_new2(size), 0, size); 1896 rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo); 1897 1898 return Qnil; 1899} 1900 1901static VALUE 1902each_with_object_i(VALUE i, VALUE memo, int argc, VALUE *argv) 1903{ 1904 ENUM_WANT_SVALUE(); 1905 return rb_yield_values(2, i, memo); 1906} 1907 1908/* 1909 * call-seq: 1910 * enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj 1911 * enum.each_with_object(obj) -> an_enumerator 1912 * 1913 * Iterates the given block for each element with an arbitrary 1914 * object given, and returns the initially given object. 1915 * 1916 * If no block is given, returns an enumerator. 1917 * 1918 * evens = (1..10).each_with_object([]) { |i, a| a << i*2 } 1919 * #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 1920 * 1921 */ 1922static VALUE 1923enum_each_with_object(VALUE obj, VALUE memo) 1924{ 1925 RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size); 1926 1927 rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo); 1928 1929 return memo; 1930} 1931 1932static VALUE 1933zip_ary(VALUE val, NODE *memo, int argc, VALUE *argv) 1934{ 1935 volatile VALUE result = memo->u1.value; 1936 volatile VALUE args = memo->u2.value; 1937 long n = memo->u3.cnt++; 1938 volatile VALUE tmp; 1939 int i; 1940 1941 tmp = rb_ary_new2(RARRAY_LEN(args) + 1); 1942 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv)); 1943 for (i=0; i<RARRAY_LEN(args); i++) { 1944 VALUE e = RARRAY_PTR(args)[i]; 1945 1946 if (RARRAY_LEN(e) <= n) { 1947 rb_ary_push(tmp, Qnil); 1948 } 1949 else { 1950 rb_ary_push(tmp, RARRAY_PTR(e)[n]); 1951 } 1952 } 1953 if (NIL_P(result)) { 1954 rb_yield(tmp); 1955 } 1956 else { 1957 rb_ary_push(result, tmp); 1958 } 1959 return Qnil; 1960} 1961 1962static VALUE 1963call_next(VALUE *v) 1964{ 1965 return v[0] = rb_funcall(v[1], id_next, 0, 0); 1966} 1967 1968static VALUE 1969call_stop(VALUE *v) 1970{ 1971 return v[0] = Qundef; 1972} 1973 1974static VALUE 1975zip_i(VALUE val, NODE *memo, int argc, VALUE *argv) 1976{ 1977 volatile VALUE result = memo->u1.value; 1978 volatile VALUE args = memo->u2.value; 1979 volatile VALUE tmp; 1980 int i; 1981 1982 tmp = rb_ary_new2(RARRAY_LEN(args) + 1); 1983 rb_ary_store(tmp, 0, rb_enum_values_pack(argc, argv)); 1984 for (i=0; i<RARRAY_LEN(args); i++) { 1985 if (NIL_P(RARRAY_PTR(args)[i])) { 1986 rb_ary_push(tmp, Qnil); 1987 } 1988 else { 1989 VALUE v[2]; 1990 1991 v[1] = RARRAY_PTR(args)[i]; 1992 rb_rescue2(call_next, (VALUE)v, call_stop, (VALUE)v, rb_eStopIteration, (VALUE)0); 1993 if (v[0] == Qundef) { 1994 RARRAY_PTR(args)[i] = Qnil; 1995 v[0] = Qnil; 1996 } 1997 rb_ary_push(tmp, v[0]); 1998 } 1999 } 2000 if (NIL_P(result)) { 2001 rb_yield(tmp); 2002 } 2003 else { 2004 rb_ary_push(result, tmp); 2005 } 2006 return Qnil; 2007} 2008 2009/* 2010 * call-seq: 2011 * enum.zip(arg, ...) -> an_array_of_array 2012 * enum.zip(arg, ...) { |arr| block } -> nil 2013 * 2014 * Takes one element from <i>enum</i> and merges corresponding 2015 * elements from each <i>args</i>. This generates a sequence of 2016 * <em>n</em>-element arrays, where <em>n</em> is one more than the 2017 * count of arguments. The length of the resulting sequence will be 2018 * <code>enum#size</code>. If the size of any argument is less than 2019 * <code>enum#size</code>, <code>nil</code> values are supplied. If 2020 * a block is given, it is invoked for each output array, otherwise 2021 * an array of arrays is returned. 2022 * 2023 * a = [ 4, 5, 6 ] 2024 * b = [ 7, 8, 9 ] 2025 * 2026 * [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 2027 * [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]] 2028 * a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]] 2029 * 2030 */ 2031 2032static VALUE 2033enum_zip(int argc, VALUE *argv, VALUE obj) 2034{ 2035 int i; 2036 ID conv; 2037 NODE *memo; 2038 VALUE result = Qnil; 2039 VALUE args = rb_ary_new4(argc, argv); 2040 int allary = TRUE; 2041 2042 argv = RARRAY_PTR(args); 2043 for (i=0; i<argc; i++) { 2044 VALUE ary = rb_check_array_type(argv[i]); 2045 if (NIL_P(ary)) { 2046 allary = FALSE; 2047 break; 2048 } 2049 argv[i] = ary; 2050 } 2051 if (!allary) { 2052 CONST_ID(conv, "to_enum"); 2053 for (i=0; i<argc; i++) { 2054 if (!rb_respond_to(argv[i], id_each)) { 2055 rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)", 2056 rb_obj_classname(argv[i])); 2057 } 2058 argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each)); 2059 } 2060 } 2061 if (!rb_block_given_p()) { 2062 result = rb_ary_new(); 2063 } 2064 /* use NODE_DOT2 as memo(v, v, -) */ 2065 memo = rb_node_newnode(NODE_DOT2, result, args, 0); 2066 rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo); 2067 2068 return result; 2069} 2070 2071static VALUE 2072take_i(VALUE i, VALUE args, int argc, VALUE *argv) 2073{ 2074 NODE *memo = RNODE(args); 2075 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv)); 2076 if (--memo->u3.cnt == 0) rb_iter_break(); 2077 return Qnil; 2078} 2079 2080/* 2081 * call-seq: 2082 * enum.take(n) -> array 2083 * 2084 * Returns first n elements from <i>enum</i>. 2085 * 2086 * a = [1, 2, 3, 4, 5, 0] 2087 * a.take(3) #=> [1, 2, 3] 2088 * 2089 */ 2090 2091static VALUE 2092enum_take(VALUE obj, VALUE n) 2093{ 2094 NODE *memo; 2095 VALUE result; 2096 long len = NUM2LONG(n); 2097 2098 if (len < 0) { 2099 rb_raise(rb_eArgError, "attempt to take negative size"); 2100 } 2101 2102 if (len == 0) return rb_ary_new2(0); 2103 result = rb_ary_new2(len); 2104 memo = NEW_MEMO(result, 0, len); 2105 rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo); 2106 return result; 2107} 2108 2109 2110static VALUE 2111take_while_i(VALUE i, VALUE ary, int argc, VALUE *argv) 2112{ 2113 if (!RTEST(enum_yield(argc, argv))) rb_iter_break(); 2114 rb_ary_push(ary, rb_enum_values_pack(argc, argv)); 2115 return Qnil; 2116} 2117 2118/* 2119 * call-seq: 2120 * enum.take_while { |arr| block } -> array 2121 * enum.take_while -> an_enumerator 2122 * 2123 * Passes elements to the block until the block returns +nil+ or +false+, 2124 * then stops iterating and returns an array of all prior elements. 2125 * 2126 * If no block is given, an enumerator is returned instead. 2127 * 2128 * a = [1, 2, 3, 4, 5, 0] 2129 * a.take_while { |i| i < 3 } #=> [1, 2] 2130 * 2131 */ 2132 2133static VALUE 2134enum_take_while(VALUE obj) 2135{ 2136 VALUE ary; 2137 2138 RETURN_ENUMERATOR(obj, 0, 0); 2139 ary = rb_ary_new(); 2140 rb_block_call(obj, id_each, 0, 0, take_while_i, ary); 2141 return ary; 2142} 2143 2144static VALUE 2145drop_i(VALUE i, VALUE args, int argc, VALUE *argv) 2146{ 2147 NODE *memo = RNODE(args); 2148 if (memo->u3.cnt == 0) { 2149 rb_ary_push(memo->u1.value, rb_enum_values_pack(argc, argv)); 2150 } 2151 else { 2152 memo->u3.cnt--; 2153 } 2154 return Qnil; 2155} 2156 2157/* 2158 * call-seq: 2159 * enum.drop(n) -> array 2160 * 2161 * Drops first n elements from <i>enum</i>, and returns rest elements 2162 * in an array. 2163 * 2164 * a = [1, 2, 3, 4, 5, 0] 2165 * a.drop(3) #=> [4, 5, 0] 2166 * 2167 */ 2168 2169static VALUE 2170enum_drop(VALUE obj, VALUE n) 2171{ 2172 VALUE result; 2173 NODE *memo; 2174 long len = NUM2LONG(n); 2175 2176 if (len < 0) { 2177 rb_raise(rb_eArgError, "attempt to drop negative size"); 2178 } 2179 2180 result = rb_ary_new(); 2181 memo = NEW_MEMO(result, 0, len); 2182 rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo); 2183 return result; 2184} 2185 2186 2187static VALUE 2188drop_while_i(VALUE i, VALUE args, int argc, VALUE *argv) 2189{ 2190 NODE *memo = RNODE(args); 2191 ENUM_WANT_SVALUE(); 2192 2193 if (!memo->u3.state && !RTEST(rb_yield(i))) { 2194 memo->u3.state = TRUE; 2195 } 2196 if (memo->u3.state) { 2197 rb_ary_push(memo->u1.value, i); 2198 } 2199 return Qnil; 2200} 2201 2202/* 2203 * call-seq: 2204 * enum.drop_while { |arr| block } -> array 2205 * enum.drop_while -> an_enumerator 2206 * 2207 * Drops elements up to, but not including, the first element for 2208 * which the block returns +nil+ or +false+ and returns an array 2209 * containing the remaining elements. 2210 * 2211 * If no block is given, an enumerator is returned instead. 2212 * 2213 * a = [1, 2, 3, 4, 5, 0] 2214 * a.drop_while { |i| i < 3 } #=> [3, 4, 5, 0] 2215 * 2216 */ 2217 2218static VALUE 2219enum_drop_while(VALUE obj) 2220{ 2221 VALUE result; 2222 NODE *memo; 2223 2224 RETURN_ENUMERATOR(obj, 0, 0); 2225 result = rb_ary_new(); 2226 memo = NEW_MEMO(result, 0, FALSE); 2227 rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo); 2228 return result; 2229} 2230 2231static VALUE 2232cycle_i(VALUE i, VALUE ary, int argc, VALUE *argv) 2233{ 2234 ENUM_WANT_SVALUE(); 2235 2236 rb_ary_push(ary, i); 2237 rb_yield(i); 2238 return Qnil; 2239} 2240 2241static VALUE 2242enum_cycle_size(VALUE self, VALUE args) 2243{ 2244 long mul; 2245 VALUE n = Qnil; 2246 VALUE size = enum_size(self, args); 2247 2248 if (size == Qnil) return Qnil; 2249 2250 if (args && (RARRAY_LEN(args) > 0)) { 2251 n = RARRAY_PTR(args)[0]; 2252 } 2253 if (n == Qnil) return DBL2NUM(INFINITY); 2254 mul = NUM2LONG(n); 2255 if (mul <= 0) return INT2FIX(0); 2256 return rb_funcall(size, '*', 1, LONG2FIX(mul)); 2257} 2258 2259/* 2260 * call-seq: 2261 * enum.cycle(n=nil) { |obj| block } -> nil 2262 * enum.cycle(n=nil) -> an_enumerator 2263 * 2264 * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_ 2265 * times or forever if none or +nil+ is given. If a non-positive 2266 * number is given or the collection is empty, does nothing. Returns 2267 * +nil+ if the loop has finished without getting interrupted. 2268 * 2269 * Enumerable#cycle saves elements in an internal array so changes 2270 * to <i>enum</i> after the first pass have no effect. 2271 * 2272 * If no block is given, an enumerator is returned instead. 2273 * 2274 * a = ["a", "b", "c"] 2275 * a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever. 2276 * a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c. 2277 * 2278 */ 2279 2280static VALUE 2281enum_cycle(int argc, VALUE *argv, VALUE obj) 2282{ 2283 VALUE ary; 2284 VALUE nv = Qnil; 2285 long n, i, len; 2286 2287 rb_scan_args(argc, argv, "01", &nv); 2288 2289 RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size); 2290 if (NIL_P(nv)) { 2291 n = -1; 2292 } 2293 else { 2294 n = NUM2LONG(nv); 2295 if (n <= 0) return Qnil; 2296 } 2297 ary = rb_ary_new(); 2298 RBASIC(ary)->klass = 0; 2299 rb_block_call(obj, id_each, 0, 0, cycle_i, ary); 2300 len = RARRAY_LEN(ary); 2301 if (len == 0) return Qnil; 2302 while (n < 0 || 0 < --n) { 2303 for (i=0; i<len; i++) { 2304 rb_yield(RARRAY_PTR(ary)[i]); 2305 } 2306 } 2307 return Qnil; 2308} 2309 2310struct chunk_arg { 2311 VALUE categorize; 2312 VALUE state; 2313 VALUE prev_value; 2314 VALUE prev_elts; 2315 VALUE yielder; 2316}; 2317 2318static VALUE 2319chunk_ii(VALUE i, VALUE _argp, int argc, VALUE *argv) 2320{ 2321 struct chunk_arg *argp = MEMO_FOR(struct chunk_arg, _argp); 2322 VALUE v; 2323 VALUE alone = ID2SYM(rb_intern("_alone")); 2324 VALUE separator = ID2SYM(rb_intern("_separator")); 2325 2326 ENUM_WANT_SVALUE(); 2327 2328 if (NIL_P(argp->state)) 2329 v = rb_funcall(argp->categorize, id_call, 1, i); 2330 else 2331 v = rb_funcall(argp->categorize, id_call, 2, i, argp->state); 2332 2333 if (v == alone) { 2334 if (!NIL_P(argp->prev_value)) { 2335 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts)); 2336 argp->prev_value = argp->prev_elts = Qnil; 2337 } 2338 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(v, rb_ary_new3(1, i))); 2339 } 2340 else if (NIL_P(v) || v == separator) { 2341 if (!NIL_P(argp->prev_value)) { 2342 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts)); 2343 argp->prev_value = argp->prev_elts = Qnil; 2344 } 2345 } 2346 else if (SYMBOL_P(v) && rb_id2name(SYM2ID(v))[0] == '_') { 2347 rb_raise(rb_eRuntimeError, "symbol begins with an underscore is reserved"); 2348 } 2349 else { 2350 if (NIL_P(argp->prev_value)) { 2351 argp->prev_value = v; 2352 argp->prev_elts = rb_ary_new3(1, i); 2353 } 2354 else { 2355 if (rb_equal(argp->prev_value, v)) { 2356 rb_ary_push(argp->prev_elts, i); 2357 } 2358 else { 2359 rb_funcall(argp->yielder, id_lshift, 1, rb_assoc_new(argp->prev_value, argp->prev_elts)); 2360 argp->prev_value = v; 2361 argp->prev_elts = rb_ary_new3(1, i); 2362 } 2363 } 2364 } 2365 return Qnil; 2366} 2367 2368static VALUE 2369chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv) 2370{ 2371 VALUE enumerable; 2372 VALUE arg; 2373 struct chunk_arg *memo = NEW_MEMO_FOR(struct chunk_arg, arg); 2374 2375 enumerable = rb_ivar_get(enumerator, rb_intern("chunk_enumerable")); 2376 memo->categorize = rb_ivar_get(enumerator, rb_intern("chunk_categorize")); 2377 memo->state = rb_ivar_get(enumerator, rb_intern("chunk_initial_state")); 2378 memo->prev_value = Qnil; 2379 memo->prev_elts = Qnil; 2380 memo->yielder = yielder; 2381 2382 if (!NIL_P(memo->state)) 2383 memo->state = rb_obj_dup(memo->state); 2384 2385 rb_block_call(enumerable, id_each, 0, 0, chunk_ii, arg); 2386 memo = MEMO_FOR(struct chunk_arg, arg); 2387 if (!NIL_P(memo->prev_elts)) 2388 rb_funcall(memo->yielder, id_lshift, 1, rb_assoc_new(memo->prev_value, memo->prev_elts)); 2389 return Qnil; 2390} 2391 2392/* 2393 * call-seq: 2394 * enum.chunk { |elt| ... } -> an_enumerator 2395 * enum.chunk(initial_state) { |elt, state| ... } -> an_enumerator 2396 * 2397 * Enumerates over the items, chunking them together based on the return 2398 * value of the block. 2399 * 2400 * Consecutive elements which return the same block value are chunked together. 2401 * 2402 * For example, consecutive even numbers and odd numbers can be 2403 * chunked as follows. 2404 * 2405 * [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n| 2406 * n.even? 2407 * }.each { |even, ary| 2408 * p [even, ary] 2409 * } 2410 * #=> [false, [3, 1]] 2411 * # [true, [4]] 2412 * # [false, [1, 5, 9]] 2413 * # [true, [2, 6]] 2414 * # [false, [5, 3, 5]] 2415 * 2416 * This method is especially useful for sorted series of elements. 2417 * The following example counts words for each initial letter. 2418 * 2419 * open("/usr/share/dict/words", "r:iso-8859-1") { |f| 2420 * f.chunk { |line| line.ord }.each { |ch, lines| p [ch.chr, lines.length] } 2421 * } 2422 * #=> ["\n", 1] 2423 * # ["A", 1327] 2424 * # ["B", 1372] 2425 * # ["C", 1507] 2426 * # ["D", 791] 2427 * # ... 2428 * 2429 * The following key values have special meaning: 2430 * - +nil+ and +:_separator+ specifies that the elements should be dropped. 2431 * - +:_alone+ specifies that the element should be chunked by itself. 2432 * 2433 * Any other symbols that begin with an underscore will raise an error: 2434 * 2435 * items.chunk { |item| :_underscore } 2436 * #=> RuntimeError: symbol begins with an underscore is reserved 2437 * 2438 * +nil+ and +:_separator+ can be used to ignore some elements. 2439 * 2440 * For example, the sequence of hyphens in svn log can be eliminated as follows: 2441 * 2442 * sep = "-"*72 + "\n" 2443 * IO.popen("svn log README") { |f| 2444 * f.chunk { |line| 2445 * line != sep || nil 2446 * }.each { |_, lines| 2447 * pp lines 2448 * } 2449 * } 2450 * #=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n", 2451 * # "\n", 2452 * # "* README, README.ja: Update the portability section.\n", 2453 * # "\n"] 2454 * # ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n", 2455 * # "\n", 2456 * # "* README, README.ja: Add a note about default C flags.\n", 2457 * # "\n"] 2458 * # ... 2459 * 2460 * Paragraphs separated by empty lines can be parsed as follows: 2461 * 2462 * File.foreach("README").chunk { |line| 2463 * /\A\s*\z/ !~ line || nil 2464 * }.each { |_, lines| 2465 * pp lines 2466 * } 2467 * 2468 * +:_alone+ can be used to force items into their own chunk. 2469 * For example, you can put lines that contain a URL by themselves, 2470 * and chunk the rest of the lines together, like this: 2471 * 2472 * pattern = /http/ 2473 * open(filename) { |f| 2474 * f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines| 2475 * pp lines 2476 * } 2477 * } 2478 * 2479 * If the block needs to maintain state over multiple elements, 2480 * an +initial_state+ argument can be used. 2481 * If a non-nil value is given, 2482 * a reference to it is passed as the 2nd argument of the block for the 2483 * +chunk+ method, so state-changes to it persist across block calls. 2484 * 2485 */ 2486static VALUE 2487enum_chunk(int argc, VALUE *argv, VALUE enumerable) 2488{ 2489 VALUE initial_state; 2490 VALUE enumerator; 2491 2492 if (!rb_block_given_p()) 2493 rb_raise(rb_eArgError, "no block given"); 2494 rb_scan_args(argc, argv, "01", &initial_state); 2495 2496 enumerator = rb_obj_alloc(rb_cEnumerator); 2497 rb_ivar_set(enumerator, rb_intern("chunk_enumerable"), enumerable); 2498 rb_ivar_set(enumerator, rb_intern("chunk_categorize"), rb_block_proc()); 2499 rb_ivar_set(enumerator, rb_intern("chunk_initial_state"), initial_state); 2500 rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator); 2501 return enumerator; 2502} 2503 2504 2505struct slicebefore_arg { 2506 VALUE sep_pred; 2507 VALUE sep_pat; 2508 VALUE state; 2509 VALUE prev_elts; 2510 VALUE yielder; 2511}; 2512 2513static VALUE 2514slicebefore_ii(VALUE i, VALUE _argp, int argc, VALUE *argv) 2515{ 2516 struct slicebefore_arg *argp = MEMO_FOR(struct slicebefore_arg, _argp); 2517 VALUE header_p; 2518 2519 ENUM_WANT_SVALUE(); 2520 2521 if (!NIL_P(argp->sep_pat)) 2522 header_p = rb_funcall(argp->sep_pat, id_eqq, 1, i); 2523 else if (NIL_P(argp->state)) 2524 header_p = rb_funcall(argp->sep_pred, id_call, 1, i); 2525 else 2526 header_p = rb_funcall(argp->sep_pred, id_call, 2, i, argp->state); 2527 if (RTEST(header_p)) { 2528 if (!NIL_P(argp->prev_elts)) 2529 rb_funcall(argp->yielder, id_lshift, 1, argp->prev_elts); 2530 argp->prev_elts = rb_ary_new3(1, i); 2531 } 2532 else { 2533 if (NIL_P(argp->prev_elts)) 2534 argp->prev_elts = rb_ary_new3(1, i); 2535 else 2536 rb_ary_push(argp->prev_elts, i); 2537 } 2538 2539 return Qnil; 2540} 2541 2542static VALUE 2543slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv) 2544{ 2545 VALUE enumerable; 2546 VALUE arg; 2547 struct slicebefore_arg *memo = NEW_MEMO_FOR(struct slicebefore_arg, arg); 2548 2549 enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable")); 2550 memo->sep_pred = rb_attr_get(enumerator, rb_intern("slicebefore_sep_pred")); 2551 memo->sep_pat = NIL_P(memo->sep_pred) ? rb_ivar_get(enumerator, rb_intern("slicebefore_sep_pat")) : Qnil; 2552 memo->state = rb_attr_get(enumerator, rb_intern("slicebefore_initial_state")); 2553 memo->prev_elts = Qnil; 2554 memo->yielder = yielder; 2555 2556 if (!NIL_P(memo->state)) 2557 memo->state = rb_obj_dup(memo->state); 2558 2559 rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, arg); 2560 memo = MEMO_FOR(struct slicebefore_arg, arg); 2561 if (!NIL_P(memo->prev_elts)) 2562 rb_funcall(memo->yielder, id_lshift, 1, memo->prev_elts); 2563 return Qnil; 2564} 2565 2566/* 2567 * call-seq: 2568 * enum.slice_before(pattern) -> an_enumerator 2569 * enum.slice_before { |elt| bool } -> an_enumerator 2570 * enum.slice_before(initial_state) { |elt, state| bool } -> an_enumerator 2571 * 2572 * Creates an enumerator for each chunked elements. 2573 * The beginnings of chunks are defined by _pattern_ and the block. 2574 2575 * If <code>_pattern_ === _elt_</code> returns <code>true</code> or the block 2576 * returns <code>true</code> for the element, the element is beginning of a 2577 * chunk. 2578 2579 * The <code>===</code> and _block_ is called from the first element to the last 2580 * element of _enum_. The result for the first element is ignored. 2581 2582 * The result enumerator yields the chunked elements as an array. 2583 * So +each+ method can be called as follows: 2584 * 2585 * enum.slice_before(pattern).each { |ary| ... } 2586 * enum.slice_before { |elt| bool }.each { |ary| ... } 2587 * enum.slice_before(initial_state) { |elt, state| bool }.each { |ary| ... } 2588 * 2589 * Other methods of the Enumerator class and Enumerable module, 2590 * such as map, etc., are also usable. 2591 * 2592 * For example, iteration over ChangeLog entries can be implemented as 2593 * follows: 2594 * 2595 * # iterate over ChangeLog entries. 2596 * open("ChangeLog") { |f| 2597 * f.slice_before(/\A\S/).each { |e| pp e } 2598 * } 2599 * 2600 * # same as above. block is used instead of pattern argument. 2601 * open("ChangeLog") { |f| 2602 * f.slice_before { |line| /\A\S/ === line }.each { |e| pp e } 2603 * } 2604 * 2605 * 2606 * "svn proplist -R" produces multiline output for each file. 2607 * They can be chunked as follows: 2608 * 2609 * IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f| 2610 * f.lines.slice_before(/\AProp/).each { |lines| p lines } 2611 * } 2612 * #=> ["Properties on '.':\n", " svn:ignore\n", " svk:merge\n"] 2613 * # ["Properties on 'goruby.c':\n", " svn:eol-style\n"] 2614 * # ["Properties on 'complex.c':\n", " svn:mime-type\n", " svn:eol-style\n"] 2615 * # ["Properties on 'regparse.c':\n", " svn:eol-style\n"] 2616 * # ... 2617 * 2618 * If the block needs to maintain state over multiple elements, 2619 * local variables can be used. 2620 * For example, three or more consecutive increasing numbers can be squashed 2621 * as follows: 2622 * 2623 * a = [0, 2, 3, 4, 6, 7, 9] 2624 * prev = a[0] 2625 * p a.slice_before { |e| 2626 * prev, prev2 = e, prev 2627 * prev2 + 1 != e 2628 * }.map { |es| 2629 * es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}" 2630 * }.join(",") 2631 * #=> "0,2-4,6,7,9" 2632 * 2633 * However local variables are not appropriate to maintain state 2634 * if the result enumerator is used twice or more. 2635 * In such a case, the last state of the 1st +each+ is used in the 2nd +each+. 2636 * The _initial_state_ argument can be used to avoid this problem. 2637 * If non-nil value is given as _initial_state_, 2638 * it is duplicated for each +each+ method invocation of the enumerator. 2639 * The duplicated object is passed to 2nd argument of the block for 2640 * +slice_before+ method. 2641 * 2642 * # Word wrapping. This assumes all characters have same width. 2643 * def wordwrap(words, maxwidth) 2644 * # if cols is a local variable, 2nd "each" may start with non-zero cols. 2645 * words.slice_before(cols: 0) { |w, h| 2646 * h[:cols] += 1 if h[:cols] != 0 2647 * h[:cols] += w.length 2648 * if maxwidth < h[:cols] 2649 * h[:cols] = w.length 2650 * true 2651 * else 2652 * false 2653 * end 2654 * } 2655 * end 2656 * text = (1..20).to_a.join(" ") 2657 * enum = wordwrap(text.split(/\s+/), 10) 2658 * puts "-"*10 2659 * enum.each { |ws| puts ws.join(" ") } 2660 * puts "-"*10 2661 * #=> ---------- 2662 * # 1 2 3 4 5 2663 * # 6 7 8 9 10 2664 * # 11 12 13 2665 * # 14 15 16 2666 * # 17 18 19 2667 * # 20 2668 * # ---------- 2669 * 2670 * mbox contains series of mails which start with Unix From line. 2671 * So each mail can be extracted by slice before Unix From line. 2672 * 2673 * # parse mbox 2674 * open("mbox") { |f| 2675 * f.slice_before { |line| 2676 * line.start_with? "From " 2677 * }.each { |mail| 2678 * unix_from = mail.shift 2679 * i = mail.index("\n") 2680 * header = mail[0...i] 2681 * body = mail[(i+1)..-1] 2682 * body.pop if body.last == "\n" 2683 * fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a 2684 * p unix_from 2685 * pp fields 2686 * pp body 2687 * } 2688 * } 2689 * 2690 * # split mails in mbox (slice before Unix From line after an empty line) 2691 * open("mbox") { |f| 2692 * f.slice_before(emp: true) { |line, h| 2693 * prevemp = h[:emp] 2694 * h[:emp] = line == "\n" 2695 * prevemp && line.start_with?("From ") 2696 * }.each { |mail| 2697 * mail.pop if mail.last == "\n" 2698 * pp mail 2699 * } 2700 * } 2701 * 2702 */ 2703static VALUE 2704enum_slice_before(int argc, VALUE *argv, VALUE enumerable) 2705{ 2706 VALUE enumerator; 2707 2708 if (rb_block_given_p()) { 2709 VALUE initial_state; 2710 rb_scan_args(argc, argv, "01", &initial_state); 2711 enumerator = rb_obj_alloc(rb_cEnumerator); 2712 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc()); 2713 rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state); 2714 } 2715 else { 2716 VALUE sep_pat; 2717 rb_scan_args(argc, argv, "1", &sep_pat); 2718 enumerator = rb_obj_alloc(rb_cEnumerator); 2719 rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat); 2720 } 2721 rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable); 2722 rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator); 2723 return enumerator; 2724} 2725 2726/* 2727 * The <code>Enumerable</code> mixin provides collection classes with 2728 * several traversal and searching methods, and with the ability to 2729 * sort. The class must provide a method <code>each</code>, which 2730 * yields successive members of the collection. If 2731 * <code>Enumerable#max</code>, <code>#min</code>, or 2732 * <code>#sort</code> is used, the objects in the collection must also 2733 * implement a meaningful <code><=></code> operator, as these methods 2734 * rely on an ordering between members of the collection. 2735 */ 2736 2737void 2738Init_Enumerable(void) 2739{ 2740#undef rb_intern 2741#define rb_intern(str) rb_intern_const(str) 2742 2743 rb_mEnumerable = rb_define_module("Enumerable"); 2744 2745 rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1); 2746 rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1); 2747 2748 rb_define_method(rb_mEnumerable, "sort", enum_sort, 0); 2749 rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0); 2750 rb_define_method(rb_mEnumerable, "grep", enum_grep, 1); 2751 rb_define_method(rb_mEnumerable, "count", enum_count, -1); 2752 rb_define_method(rb_mEnumerable, "find", enum_find, -1); 2753 rb_define_method(rb_mEnumerable, "detect", enum_find, -1); 2754 rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1); 2755 rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0); 2756 rb_define_method(rb_mEnumerable, "select", enum_find_all, 0); 2757 rb_define_method(rb_mEnumerable, "reject", enum_reject, 0); 2758 rb_define_method(rb_mEnumerable, "collect", enum_collect, 0); 2759 rb_define_method(rb_mEnumerable, "map", enum_collect, 0); 2760 rb_define_method(rb_mEnumerable, "flat_map", enum_flat_map, 0); 2761 rb_define_method(rb_mEnumerable, "collect_concat", enum_flat_map, 0); 2762 rb_define_method(rb_mEnumerable, "inject", enum_inject, -1); 2763 rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1); 2764 rb_define_method(rb_mEnumerable, "partition", enum_partition, 0); 2765 rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0); 2766 rb_define_method(rb_mEnumerable, "first", enum_first, -1); 2767 rb_define_method(rb_mEnumerable, "all?", enum_all, 0); 2768 rb_define_method(rb_mEnumerable, "any?", enum_any, 0); 2769 rb_define_method(rb_mEnumerable, "one?", enum_one, 0); 2770 rb_define_method(rb_mEnumerable, "none?", enum_none, 0); 2771 rb_define_method(rb_mEnumerable, "min", enum_min, 0); 2772 rb_define_method(rb_mEnumerable, "max", enum_max, 0); 2773 rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0); 2774 rb_define_method(rb_mEnumerable, "min_by", enum_min_by, 0); 2775 rb_define_method(rb_mEnumerable, "max_by", enum_max_by, 0); 2776 rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0); 2777 rb_define_method(rb_mEnumerable, "member?", enum_member, 1); 2778 rb_define_method(rb_mEnumerable, "include?", enum_member, 1); 2779 rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, -1); 2780 rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1); 2781 rb_define_method(rb_mEnumerable, "each_entry", enum_each_entry, -1); 2782 rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1); 2783 rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1); 2784 rb_define_method(rb_mEnumerable, "each_with_object", enum_each_with_object, 1); 2785 rb_define_method(rb_mEnumerable, "zip", enum_zip, -1); 2786 rb_define_method(rb_mEnumerable, "take", enum_take, 1); 2787 rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0); 2788 rb_define_method(rb_mEnumerable, "drop", enum_drop, 1); 2789 rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0); 2790 rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1); 2791 rb_define_method(rb_mEnumerable, "chunk", enum_chunk, -1); 2792 rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, -1); 2793 2794 id_next = rb_intern("next"); 2795 id_call = rb_intern("call"); 2796 id_size = rb_intern("size"); 2797 id_div = rb_intern("div"); 2798} 2799