Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

enum.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   enum.c -
00004 
00005   $Author: nobu $
00006   $Date: 2005/06/30 16:46:13 $
00007   created at: Fri Oct  1 15:15:19 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010 
00011 **********************************************************************/
00012 
00013 #include "ruby.h"
00014 #include "node.h"
00015 #include "util.h"
00016 
00017 VALUE rb_mEnumerable;
00018 static ID id_each, id_eqq, id_cmp;
00019 
00020 VALUE
00021 rb_each(obj)
00022     VALUE obj;
00023 {
00024     return rb_funcall(obj, id_each, 0, 0);
00025 }
00026 
00027 static VALUE
00028 grep_i(i, arg)
00029     VALUE i, *arg;
00030 {
00031     if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
00032         rb_ary_push(arg[1], i);
00033     }
00034     return Qnil;
00035 }
00036 
00037 static VALUE
00038 grep_iter_i(i, arg)
00039     VALUE i, *arg;
00040 {
00041     if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) {
00042         rb_ary_push(arg[1], rb_yield(i));
00043     }
00044     return Qnil;
00045 }
00046 
00047 /*
00048  *  call-seq:
00049  *     enum.grep(pattern)                   => array
00050  *     enum.grep(pattern) {| obj | block }  => array
00051  *  
00052  *  Returns an array of every element in <i>enum</i> for which
00053  *  <code>Pattern === element</code>. If the optional <em>block</em> is
00054  *  supplied, each matching element is passed to it, and the block's
00055  *  result is stored in the output array.
00056  *     
00057  *     (1..100).grep 38..44   #=> [38, 39, 40, 41, 42, 43, 44]
00058  *     c = IO.constants
00059  *     c.grep(/SEEK/)         #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"]
00060  *     res = c.grep(/SEEK/) {|v| IO.const_get(v) }
00061  *     res                    #=> [2, 0, 1]
00062  *     
00063  */
00064 
00065 static VALUE
00066 enum_grep(obj, pat)
00067     VALUE obj, pat;
00068 {
00069     VALUE ary = rb_ary_new();
00070     VALUE arg[2];
00071 
00072     arg[0] = pat;
00073     arg[1] = ary;
00074 
00075     rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
00076     
00077     return ary;
00078 }
00079 
00080 static VALUE
00081 find_i(i, memo)
00082     VALUE i;
00083     VALUE *memo;
00084 {
00085     if (RTEST(rb_yield(i))) {
00086         *memo = i;
00087         rb_iter_break();
00088     }
00089     return Qnil;
00090 }
00091 
00092 /*
00093  *  call-seq:
00094  *     enum.detect(ifnone = nil) {| obj | block }  => obj or nil
00095  *     enum.find(ifnone = nil)   {| obj | block }  => obj or nil
00096  *  
00097  *  Passes each entry in <i>enum</i> to <em>block</em>. Returns the
00098  *  first for which <em>block</em> is not <code>false</code>.  If no
00099  *  object matches, calls <i>ifnone</i> and returns its result when it
00100  *  is specified, or returns <code>nil</code>
00101  *     
00102  *     (1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
00103  *     (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35
00104  *     
00105  */
00106 
00107 static VALUE
00108 enum_find(argc, argv, obj)
00109     int argc;
00110     VALUE* argv;
00111     VALUE obj;
00112 {
00113     VALUE memo = Qundef;
00114     VALUE if_none;
00115 
00116     rb_scan_args(argc, argv, "01", &if_none);
00117     rb_iterate(rb_each, obj, find_i, (VALUE)&memo);
00118     if (memo != Qundef) {
00119         return memo;
00120     }
00121     if (!NIL_P(if_none)) {
00122         return rb_funcall(if_none, rb_intern("call"), 0, 0);
00123     }
00124     return Qnil;
00125 }
00126 
00127 static VALUE
00128 find_all_i(i, ary)
00129     VALUE i, ary;
00130 {
00131     if (RTEST(rb_yield(i))) {
00132         rb_ary_push(ary, i);
00133     }
00134     return Qnil;
00135 }
00136 
00137 /*
00138  *  call-seq:
00139  *     enum.find_all {| obj | block }  => array
00140  *     enum.select   {| obj | block }  => array
00141  *  
00142  *  Returns an array containing all elements of <i>enum</i> for which
00143  *  <em>block</em> is not <code>false</code> (see also
00144  *  <code>Enumerable#reject</code>).
00145  *     
00146  *     (1..10).find_all {|i|  i % 3 == 0 }   #=> [3, 6, 9]
00147  *     
00148  */
00149 
00150 static VALUE
00151 enum_find_all(obj)
00152     VALUE obj;
00153 {
00154     VALUE ary = rb_ary_new();
00155     
00156     rb_iterate(rb_each, obj, find_all_i, ary);
00157 
00158     return ary;
00159 }
00160 
00161 static VALUE
00162 reject_i(i, ary)
00163     VALUE i, ary;
00164 {
00165     if (!RTEST(rb_yield(i))) {
00166         rb_ary_push(ary, i);
00167     }
00168     return Qnil;
00169 }
00170 
00171 /*
00172  *  call-seq:
00173  *     enum.reject {| obj | block }  => array
00174  *  
00175  *  Returns an array for all elements of <i>enum</i> for which
00176  *  <em>block</em> is false (see also <code>Enumerable#find_all</code>).
00177  *     
00178  *     (1..10).reject {|i|  i % 3 == 0 }   #=> [1, 2, 4, 5, 7, 8, 10]
00179  *     
00180  */
00181 
00182 static VALUE
00183 enum_reject(obj)
00184     VALUE obj;
00185 {
00186     VALUE ary = rb_ary_new();
00187     
00188     rb_iterate(rb_each, obj, reject_i, ary);
00189 
00190     return ary;
00191 }
00192 
00193 static VALUE
00194 collect_i(i, ary)
00195     VALUE i, ary;
00196 {
00197     rb_ary_push(ary, rb_yield(i));
00198 
00199     return Qnil;
00200 }
00201 
00202 static VALUE
00203 collect_all(i, ary)
00204     VALUE i, ary;
00205 {
00206     rb_ary_push(ary, i);
00207 
00208     return Qnil;
00209 }
00210 
00211 /*
00212  *  call-seq:
00213  *     enum.collect {| obj | block }  => array
00214  *     enum.map     {| obj | block }  => array
00215  *  
00216  *  Returns a new array with the results of running <em>block</em> once
00217  *  for every element in <i>enum</i>.
00218  *     
00219  *     (1..4).collect {|i| i*i }   #=> [1, 4, 9, 16]
00220  *     (1..4).collect { "cat"  }   #=> ["cat", "cat", "cat", "cat"]
00221  *     
00222  */
00223 
00224 static VALUE
00225 enum_collect(obj)
00226     VALUE obj;
00227 {
00228     VALUE ary = rb_ary_new();
00229 
00230     rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary);
00231 
00232     return ary;
00233 }
00234 
00235 /*
00236  *  call-seq:
00237  *     enum.to_a      =>    array
00238  *     enum.entries   =>    array
00239  *  
00240  *  Returns an array containing the items in <i>enum</i>.
00241  *     
00242  *     (1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
00243  *     { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]
00244  */
00245 static VALUE
00246 enum_to_a(obj)
00247     VALUE obj;
00248 {
00249     VALUE ary = rb_ary_new();
00250 
00251     rb_iterate(rb_each, obj, collect_all, ary);
00252 
00253     return ary;
00254 }
00255 
00256 static VALUE
00257 inject_i(i, memo)
00258     VALUE i;
00259     VALUE *memo;
00260 {
00261     if (*memo == Qundef) {
00262         *memo = i;
00263     }
00264     else {
00265         *memo = rb_yield_values(2, *memo, i);
00266     }
00267     return Qnil;
00268 }
00269 
00270 /*
00271  *  call-seq:
00272  *     enum.inject(initial) {| memo, obj | block }  => obj
00273  *     enum.inject          {| memo, obj | block }  => obj
00274  *  
00275  *  Combines the elements of <i>enum</i> by applying the block to an
00276  *  accumulator value (<i>memo</i>) and each element in turn. At each
00277  *  step, <i>memo</i> is set to the value returned by the block. The
00278  *  first form lets you supply an initial value for <i>memo</i>. The
00279  *  second form uses the first element of the collection as a the
00280  *  initial value (and skips that element while iterating).
00281  *     
00282  *     # Sum some numbers
00283  *     (5..10).inject {|sum, n| sum + n }              #=> 45
00284  *     # Multiply some numbers
00285  *     (5..10).inject(1) {|product, n| product * n }   #=> 151200
00286  *     
00287  *     # find the longest word
00288  *     longest = %w{ cat sheep bear }.inject do |memo,word|
00289  *        memo.length > word.length ? memo : word
00290  *     end
00291  *     longest                                         #=> "sheep"
00292  *     
00293  *     # find the length of the longest word
00294  *     longest = %w{ cat sheep bear }.inject(0) do |memo,word|
00295  *        memo >= word.length ? memo : word.length
00296  *     end
00297  *     longest                                         #=> 5
00298  *     
00299  */
00300 
00301 static VALUE
00302 enum_inject(argc, argv, obj)
00303     int argc;
00304     VALUE *argv, obj;
00305 {
00306     VALUE memo = Qundef;
00307 
00308     if (rb_scan_args(argc, argv, "01", &memo) == 0)
00309         memo = Qundef;
00310     rb_iterate(rb_each, obj, inject_i, (VALUE)&memo);
00311     if (memo == Qundef) return Qnil;
00312     return memo;
00313 }
00314 
00315 static VALUE
00316 partition_i(i, ary)
00317     VALUE i, *ary;
00318 {
00319     if (RTEST(rb_yield(i))) {
00320         rb_ary_push(ary[0], i);
00321     }
00322     else {
00323         rb_ary_push(ary[1], i);
00324     }
00325     return Qnil;
00326 }
00327 
00328 /*
00329  *  call-seq:
00330  *     enum.partition {| obj | block }  => [ true_array, false_array ]
00331  *  
00332  *  Returns two arrays, the first containing the elements of
00333  *  <i>enum</i> for which the block evaluates to true, the second
00334  *  containing the rest.
00335  *     
00336  *     (1..6).partition {|i| (i&1).zero?}   #=> [[2, 4, 6], [1, 3, 5]]
00337  *     
00338  */
00339 
00340 static VALUE
00341 enum_partition(obj)
00342     VALUE obj;
00343 {
00344     VALUE ary[2];
00345 
00346     ary[0] = rb_ary_new();
00347     ary[1] = rb_ary_new();
00348     rb_iterate(rb_each, obj, partition_i, (VALUE)ary);
00349 
00350     return rb_assoc_new(ary[0], ary[1]);
00351 }
00352 
00353 /*
00354  *  call-seq:
00355  *     enum.sort                     => array
00356  *     enum.sort {| a, b | block }   => array
00357  *  
00358  *  Returns an array containing the items in <i>enum</i> sorted,
00359  *  either according to their own <code><=></code> method, or by using
00360  *  the results of the supplied block. The block should return -1, 0, or
00361  *  +1 depending on the comparison between <i>a</i> and <i>b</i>. As of
00362  *  Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a
00363  *  built-in Schwartzian Transform, useful when key computation or
00364  *  comparison is expensive..
00365  *     
00366  *     %w(rhea kea flea).sort         #=> ["flea", "kea", "rhea"]
00367  *     (1..10).sort {|a,b| b <=> a}   #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
00368  */
00369 
00370 static VALUE
00371 enum_sort(obj)
00372     VALUE obj;
00373 {
00374     return rb_ary_sort(enum_to_a(obj));
00375 }
00376 
00377 static VALUE
00378 sort_by_i(i, ary)
00379     VALUE i, ary;
00380 {
00381     VALUE v;
00382     NODE *memo;
00383 
00384     v = rb_yield(i);
00385     if (RBASIC(ary)->klass) {
00386         rb_raise(rb_eRuntimeError, "sort_by reentered");
00387     }
00388     memo = rb_node_newnode(NODE_MEMO, v, i, 0);
00389     rb_ary_push(ary, (VALUE)memo);
00390     return Qnil;
00391 }
00392 
00393 static int
00394 sort_by_cmp(aa, bb)
00395     NODE **aa, **bb;
00396 {
00397     VALUE a = aa[0]->u1.value;
00398     VALUE b = bb[0]->u1.value;
00399 
00400     return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
00401 }
00402 
00403 /*
00404  *  call-seq:
00405  *     enum.sort_by {| obj | block }    => array
00406  *  
00407  *  Sorts <i>enum</i> using a set of keys generated by mapping the
00408  *  values in <i>enum</i> through the given block.
00409  *     
00410  *     %w{ apple pear fig }.sort_by {|word| word.length}
00411                     #=> ["fig", "pear", "apple"]
00412  *     
00413  *  The current implementation of <code>sort_by</code> generates an
00414  *  array of tuples containing the original collection element and the
00415  *  mapped value. This makes <code>sort_by</code> fairly expensive when
00416  *  the keysets are simple
00417  *     
00418  *     require 'benchmark'
00419  *     include Benchmark
00420  *     
00421  *     a = (1..100000).map {rand(100000)}
00422  *     
00423  *     bm(10) do |b|
00424  *       b.report("Sort")    { a.sort }
00425  *       b.report("Sort by") { a.sort_by {|a| a} }
00426  *     end
00427  *     
00428  *  <em>produces:</em>
00429  *     
00430  *     user     system      total        real
00431  *     Sort        0.180000   0.000000   0.180000 (  0.175469)
00432  *     Sort by     1.980000   0.040000   2.020000 (  2.013586)
00433  *     
00434  *  However, consider the case where comparing the keys is a non-trivial
00435  *  operation. The following code sorts some files on modification time
00436  *  using the basic <code>sort</code> method.
00437  *     
00438  *     files = Dir["*"]
00439  *     sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}
00440  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
00441  *     
00442  *  This sort is inefficient: it generates two new <code>File</code>
00443  *  objects during every comparison. A slightly better technique is to
00444  *  use the <code>Kernel#test</code> method to generate the modification
00445  *  times directly.
00446  *     
00447  *     files = Dir["*"]
00448  *     sorted = files.sort { |a,b|
00449  *       test(?M, a) <=> test(?M, b)
00450  *     }
00451  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
00452  *     
00453  *  This still generates many unnecessary <code>Time</code> objects. A
00454  *  more efficient technique is to cache the sort keys (modification
00455  *  times in this case) before the sort. Perl users often call this
00456  *  approach a Schwartzian Transform, after Randal Schwartz. We
00457  *  construct a temporary array, where each element is an array
00458  *  containing our sort key along with the filename. We sort this array,
00459  *  and then extract the filename from the result.
00460  *     
00461  *     sorted = Dir["*"].collect { |f|
00462  *        [test(?M, f), f]
00463  *     }.sort.collect { |f| f[1] }
00464  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
00465  *     
00466  *  This is exactly what <code>sort_by</code> does internally.
00467  *     
00468  *     sorted = Dir["*"].sort_by {|f| test(?M, f)}
00469  *     sorted   #=> ["mon", "tues", "wed", "thurs"]
00470  */
00471 
00472 static VALUE
00473 enum_sort_by(obj)
00474     VALUE obj;
00475 {
00476     VALUE ary;
00477     long i;
00478 
00479     if (TYPE(obj) == T_ARRAY) {
00480         ary  = rb_ary_new2(RARRAY(obj)->len);
00481     }
00482     else {
00483         ary = rb_ary_new();
00484     }
00485     RBASIC(ary)->klass = 0;
00486     rb_iterate(rb_each, obj, sort_by_i, ary);
00487     if (RARRAY(ary)->len > 1) {
00488         qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp, 0);
00489     }
00490     if (RBASIC(ary)->klass) {
00491         rb_raise(rb_eRuntimeError, "sort_by reentered");
00492     }
00493     for (i=0; i<RARRAY(ary)->len; i++) {
00494         RARRAY(ary)->ptr[i] = RNODE(RARRAY(ary)->ptr[i])->u2.value;
00495     }
00496     RBASIC(ary)->klass = rb_cArray;
00497     return ary;
00498 }
00499 
00500 static VALUE
00501 all_iter_i(i, memo)
00502     VALUE i;
00503     VALUE *memo;
00504 {
00505     if (!RTEST(rb_yield(i))) {
00506         *memo = Qfalse;
00507         rb_iter_break();
00508     }
00509     return Qnil;
00510 }
00511 
00512 static VALUE
00513 all_i(i, memo)
00514     VALUE i;
00515     VALUE *memo;
00516 {
00517     if (!RTEST(i)) {
00518         *memo = Qfalse;
00519         rb_iter_break();
00520     }
00521     return Qnil;
00522 }
00523 
00524 /*
00525  *  call-seq:
00526  *     enum.all? [{|obj| block } ]   => true or false
00527  *  
00528  *  Passes each element of the collection to the given block. The method
00529  *  returns <code>true</code> if the block never returns
00530  *  <code>false</code> or <code>nil</code>. If the block is not given,
00531  *  Ruby adds an implicit block of <code>{|obj| obj}</code> (that is
00532  *  <code>all?</code> will return <code>true</code> only if none of the
00533  *  collection members are <code>false</code> or <code>nil</code>.)
00534  *     
00535  *     %w{ ant bear cat}.all? {|word| word.length >= 3}   #=> true
00536  *     %w{ ant bear cat}.all? {|word| word.length >= 4}   #=> false
00537  *     [ nil, true, 99 ].all?                             #=> false
00538  *     
00539  */
00540 
00541 static VALUE
00542 enum_all(obj)
00543     VALUE obj;
00544 {
00545     VALUE result = Qtrue;
00546 
00547     rb_iterate(rb_each, obj, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result);
00548     return result;
00549 }
00550 
00551 static VALUE
00552 any_iter_i(i, memo)
00553     VALUE i;
00554     VALUE *memo;
00555 {
00556     if (RTEST(rb_yield(i))) {
00557         *memo = Qtrue;
00558         rb_iter_break();
00559     }
00560     return Qnil;
00561 }
00562 
00563 static VALUE
00564 any_i(i, memo)
00565     VALUE i;
00566     VALUE *memo;
00567 {
00568     if (RTEST(i)) {
00569         *memo = Qtrue;
00570         rb_iter_break();
00571     }
00572     return Qnil;
00573 }
00574 
00575 /*
00576  *  call-seq:
00577  *     enum.any? [{|obj| block } ]   => true or false
00578  *  
00579  *  Passes each element of the collection to the given block. The method
00580  *  returns <code>true</code> if the block ever returns a value other
00581  *  that <code>false</code> or <code>nil</code>. If the block is not
00582  *  given, Ruby adds an implicit block of <code>{|obj| obj}</code> (that
00583  *  is <code>any?</code> will return <code>true</code> if at least one
00584  *  of the collection members is not <code>false</code> or
00585  *  <code>nil</code>.
00586  *     
00587  *     %w{ ant bear cat}.any? {|word| word.length >= 3}   #=> true
00588  *     %w{ ant bear cat}.any? {|word| word.length >= 4}   #=> true
00589  *     [ nil, true, 99 ].any?                             #=> true
00590  *     
00591  */
00592 
00593 static VALUE
00594 enum_any(obj)
00595     VALUE obj;
00596 {
00597     VALUE result = Qfalse;
00598 
00599     rb_iterate(rb_each, obj, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result);
00600     return result;
00601 }
00602 
00603 static VALUE
00604 min_i(i, memo)
00605     VALUE i;
00606     VALUE *memo;
00607 {
00608     VALUE cmp;
00609 
00610     if (*memo == Qundef) {
00611         *memo = i;
00612     }
00613     else {
00614         cmp = rb_funcall(i, id_cmp, 1, *memo);
00615         if (rb_cmpint(cmp, i, *memo) < 0) {
00616             *memo = i;
00617         }
00618     }
00619     return Qnil;
00620 }
00621 
00622 static VALUE
00623 min_ii(i, memo)
00624     VALUE i;
00625     VALUE *memo;
00626 {
00627     VALUE cmp;
00628 
00629     if (*memo == Qundef) {
00630         *memo = i;
00631     }
00632     else {
00633         cmp = rb_yield_values(2, i, *memo);
00634         if (rb_cmpint(cmp, i, *memo) < 0) {
00635             *memo = i;
00636         }
00637     }
00638     return Qnil;
00639 }
00640 
00641 
00642 /*
00643  *  call-seq:
00644  *     enum.min                    => obj
00645  *     enum.min {| a,b | block }   => obj
00646  *  
00647  *  Returns the object in <i>enum</i> with the minimum value. The
00648  *  first form assumes all objects implement <code>Comparable</code>;
00649  *  the second uses the block to return <em>a <=> b</em>.
00650  *     
00651  *     a = %w(albatross dog horse)
00652  *     a.min                                  #=> "albatross"
00653  *     a.min {|a,b| a.length <=> b.length }   #=> "dog"
00654  */
00655 
00656 static VALUE
00657 enum_min(obj)
00658     VALUE obj;
00659 {
00660     VALUE result = Qundef;
00661 
00662     rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)&result);
00663     if (result == Qundef) return Qnil;
00664     return result;
00665 }
00666 
00667 /*
00668  *  call-seq:
00669  *     enum.max                    => obj
00670  *     enum.max {| a,b | block }   => obj
00671  *  
00672  *  Returns the object in <i>enum</i> with the maximum value. The
00673  *  first form assumes all objects implement <code>Comparable</code>;
00674  *  the second uses the block to return <em>a <=> b</em>.
00675  *     
00676  *     a = %w(albatross dog horse)
00677  *     a.max                                  #=> "horse"
00678  *     a.max {|a,b| a.length <=> b.length }   #=> "albatross"
00679  */
00680 
00681 static VALUE
00682 max_i(i, memo)
00683     VALUE i;
00684     VALUE *memo;
00685 {
00686     VALUE cmp;
00687 
00688     if (*memo == Qundef) {
00689         *memo = i;
00690     }
00691     else {
00692         cmp = rb_funcall(i, id_cmp, 1, *memo);
00693         if (rb_cmpint(cmp, i, *memo) > 0) {
00694             *memo = i;
00695         }
00696     }
00697     return Qnil;
00698 }
00699 
00700 static VALUE
00701 max_ii(i, memo)
00702     VALUE i;
00703     VALUE *memo;
00704 {
00705     VALUE cmp;
00706 
00707     if (*memo == Qundef) {
00708         *memo = i;
00709     }
00710     else {
00711         cmp = rb_yield_values(2, i, *memo);
00712         if (rb_cmpint(cmp, i, *memo) > 0) {
00713             *memo = i;
00714         }
00715     }
00716     return Qnil;
00717 }
00718 
00719 /*
00720  *  call-seq:
00721  *     enum.max                   => obj
00722  *     enum.max {|a,b| block }    => obj
00723  *  
00724  *  Returns the object in _enum_ with the maximum value. The
00725  *  first form assumes all objects implement <code>Comparable</code>;
00726  *  the second uses the block to return <em>a <=> b</em>.
00727  *     
00728  *     a = %w(albatross dog horse)
00729  *     a.max                                  #=> "horse"
00730  *     a.max {|a,b| a.length <=> b.length }   #=> "albatross"
00731  */  
00732 
00733 static VALUE
00734 enum_max(obj)
00735     VALUE obj;
00736 {
00737     VALUE result = Qundef;
00738 
00739     rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)&result);
00740     if (result == Qundef) return Qnil;
00741     return result;
00742 }
00743 
00744 static VALUE
00745 member_i(item, memo)
00746     VALUE item;
00747     VALUE *memo;
00748 {
00749     if (rb_equal(item, memo[0])) {
00750         memo[1] = Qtrue;
00751         rb_iter_break();
00752     }
00753     return Qnil;
00754 }
00755 
00756 /*
00757  *  call-seq:
00758  *     enum.include?(obj)     => true or false
00759  *     enum.member?(obj)      => true or false
00760  *  
00761  *  Returns <code>true</code> if any member of <i>enum</i> equals
00762  *  <i>obj</i>. Equality is tested using <code>==</code>.
00763  *     
00764  *     IO.constants.include? "SEEK_SET"          #=> true
00765  *     IO.constants.include? "SEEK_NO_FURTHER"   #=> false
00766  *     
00767  */
00768 
00769 static VALUE
00770 enum_member(obj, val)
00771     VALUE obj, val;
00772 {
00773     VALUE memo[2];
00774 
00775     memo[0] = val;
00776     memo[1] = Qfalse;
00777     rb_iterate(rb_each, obj, member_i, (VALUE)memo);
00778     return memo[1];
00779 }
00780 
00781 static VALUE
00782 each_with_index_i(val, memo)
00783     VALUE val;
00784     VALUE *memo;
00785 {
00786     rb_yield_values(2, val, INT2FIX(*memo));
00787     ++*memo;
00788     return Qnil;
00789 }
00790 
00791 /*
00792  *  call-seq:
00793  *     enum.each_with_index {|obj, i| block }  -> enum
00794  *  
00795  *  Calls <em>block</em> with two arguments, the item and its index, for
00796  *  each item in <i>enum</i>.
00797  *     
00798  *     hash = Hash.new
00799  *     %w(cat dog wombat).each_with_index {|item, index|
00800  *       hash[item] = index
00801  *     }
00802  *     hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
00803  *     
00804  */
00805 
00806 static VALUE
00807 enum_each_with_index(obj)
00808     VALUE obj;
00809 {
00810     VALUE memo = 0;
00811 
00812     rb_need_block();
00813     rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
00814     return obj;
00815 }
00816 
00817 static VALUE
00818 zip_i(val, memo)
00819     VALUE val;
00820     VALUE *memo;
00821 {
00822     VALUE result = memo[0];
00823     VALUE args = memo[1];
00824     int idx = memo[2]++;
00825     VALUE tmp;
00826     int i;
00827 
00828     tmp = rb_ary_new2(RARRAY(args)->len + 1);
00829     rb_ary_store(tmp, 0, val);
00830     for (i=0; i<RARRAY(args)->len; i++) {
00831         rb_ary_push(tmp, rb_ary_entry(RARRAY(args)->ptr[i], idx));
00832     }
00833     if (rb_block_given_p()) {
00834         rb_yield(tmp);
00835     }
00836     else {
00837         rb_ary_push(result, tmp);
00838     }
00839     return Qnil;
00840 }
00841 
00842 /*
00843  *  call-seq:
00844  *     enum.zip(arg, ...)                   => array
00845  *     enum.zip(arg, ...) {|arr| block }    => nil
00846  *  
00847  *  Converts any arguments to arrays, then merges elements of
00848  *  <i>enum</i> with corresponding elements from each argument. This
00849  *  generates a sequence of <code>enum#size</code> <em>n</em>-element
00850  *  arrays, where <em>n</em> is one more that the count of arguments. If
00851  *  the size of any argument is less than <code>enum#size</code>,
00852  *  <code>nil</code> values are supplied. If a block given, it is
00853  *  invoked for each output array, otherwise an array of arrays is
00854  *  returned.
00855  *     
00856  *     a = [ 4, 5, 6 ]
00857  *     b = [ 7, 8, 9 ]
00858  *     
00859  *     (1..3).zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
00860  *     "cat\ndog".zip([1])   #=> [["cat\n", 1], ["dog", nil]]
00861  *     (1..3).zip            #=> [[1], [2], [3]]
00862  *     
00863  */
00864 
00865 static VALUE
00866 enum_zip(argc, argv, obj)
00867     int argc;
00868     VALUE *argv;
00869     VALUE obj;
00870 {
00871     int i;
00872     VALUE result;
00873     VALUE memo[3];
00874 
00875     for (i=0; i<argc; i++) {
00876         argv[i] = rb_convert_type(argv[i], T_ARRAY, "Array", "to_a");
00877     }
00878     result = rb_block_given_p() ? Qnil : rb_ary_new();
00879     memo[0] = result;
00880     memo[1] = rb_ary_new4(argc, argv);
00881     memo[2] = 0;
00882     rb_iterate(rb_each, obj, zip_i, (VALUE)memo);
00883 
00884     return result;
00885 }
00886 
00887 /*
00888  *  The <code>Enumerable</code> mixin provides collection classes with
00889  *  several traversal and searching methods, and with the ability to
00890  *  sort. The class must provide a method <code>each</code>, which
00891  *  yields successive members of the collection. If
00892  *  <code>Enumerable#max</code>, <code>#min</code>, or
00893  *  <code>#sort</code> is used, the objects in the collection must also
00894  *  implement a meaningful <code><=></code> operator, as these methods
00895  *  rely on an ordering between members of the collection.
00896  */
00897 
00898 void
00899 Init_Enumerable()
00900 {
00901     rb_mEnumerable = rb_define_module("Enumerable");
00902 
00903     rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0);
00904     rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0);
00905 
00906     rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
00907     rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
00908     rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
00909     rb_define_method(rb_mEnumerable,"find", enum_find, -1);
00910     rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
00911     rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
00912     rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
00913     rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
00914     rb_define_method(rb_mEnumerable,"collect", enum_collect, 0);
00915     rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
00916     rb_define_method(rb_mEnumerable,"inject", enum_inject, -1);
00917     rb_define_method(rb_mEnumerable,"partition", enum_partition, 0);
00918     rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
00919     rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
00920     rb_define_method(rb_mEnumerable,"min", enum_min, 0);
00921     rb_define_method(rb_mEnumerable,"max", enum_max, 0);
00922     rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
00923     rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
00924     rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
00925     rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
00926 
00927     id_eqq  = rb_intern("===");
00928     id_each = rb_intern("each");
00929     id_cmp  = rb_intern("<=>");
00930 }
00931 
00932 

Generated on Wed Jan 18 23:31:59 2006 for Ruby by doxygen 1.3.5