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