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