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