From 8ca8703de2a124e11bd87abe84c41553b0daed54 Mon Sep 17 00:00:00 2001 From: knu Date: Mon, 14 Apr 2008 07:04:30 +0000 Subject: * enum.c (enum_count, enum_find_index): New methods: Enumerable#count and #find_index; backported from 1.9. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@16004 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++ NEWS | 2 + array.c | 3 ++ enum.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6bf7dc6bea..d38a88ba77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Mon Apr 14 15:49:05 2008 Akinori MUSHA + + * enum.c (enum_count, enum_find_index): New methods: + Enumerable#count and #find_index; backported from 1.9. + Mon Apr 14 14:16:08 2008 NAKAMURA Usaku * enumerator.c (enumerator_mark, enumerator_iter_i, enumerator_each_i, diff --git a/NEWS b/NEWS index 0059fde9c8..aeb1bcdf22 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ with all sufficient information, see the ChangeLog file. New methods for various enumeration defined by the enumerator library. + * Enumerator#count + * Enumerable#find_index * Enumerable#first * Enumerable#group_by diff --git a/array.c b/array.c index 203a1a52d3..37bc123f47 100644 --- a/array.c +++ b/array.c @@ -945,6 +945,8 @@ rb_ary_fetch(argc, argv, ary) * a.index("b") #=> 1 * a.index("z") #=> nil * a.index{|x|x=="b"} #=> 1 + * + * This is an alias of #find_index. */ static VALUE @@ -3157,6 +3159,7 @@ Init_Array() rb_define_method(rb_cArray, "length", rb_ary_length, 0); rb_define_alias(rb_cArray, "size", "length"); rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0); + rb_define_method(rb_cArray, "find_index", rb_ary_index, -1); rb_define_method(rb_cArray, "index", rb_ary_index, -1); rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1); rb_define_method(rb_cArray, "indexes", rb_ary_indexes, -1); diff --git a/enum.c b/enum.c index a22cb4c639..ff3c09be90 100644 --- a/enum.c +++ b/enum.c @@ -113,6 +113,75 @@ enum_grep(obj, pat) return ary; } +static VALUE +count_i(i, arg) + VALUE i; + VALUE *arg; +{ + if (rb_equal(i, arg[0])) { + arg[1]++; + } + return Qnil; +} + +static VALUE +count_iter_i(i, n) + VALUE i; + long *n; +{ + if (RTEST(rb_yield(i))) { + (*n)++; + } + return Qnil; +} + +/* + * call-seq: + * enum.count(item) => int + * enum.count {| obj | block } => int + * + * Returns the number of items in enum for which equals to item. + * If a block is given, counts the number of elements yielding a true value. + * + * ary = [1, 2, 4, 2] + * ary.count(2) # => 2 + * ary.count{|x|x%2==0} # => 3 + * + */ + +static VALUE +enum_count(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + if (argc == 1) { + VALUE item, args[2]; + + if (rb_block_given_p()) { + rb_warn("given block not used"); + } + rb_scan_args(argc, argv, "1", &item); + args[0] = item; + args[1] = 0; + rb_block_call(obj, id_each, 0, 0, count_i, (VALUE)&args); + return INT2NUM(args[1]); + } + else if (argc == 0) { + long n; + + RETURN_ENUMERATOR(obj, 0, 0); + n = 0; + rb_block_call(obj, id_each, 0, 0, count_iter_i, (VALUE)&n); + return INT2NUM(n); + } + else { + VALUE v; + rb_scan_args(argc, argv, "1", &v); + return Qnil; /* not reached */ + } +} + static VALUE find_i(i, memo) VALUE i; @@ -160,6 +229,79 @@ enum_find(argc, argv, obj) return Qnil; } +static VALUE +find_index_i(i, memop) + VALUE i; + VALUE memop; +{ + VALUE *memo = (VALUE*)memop; + + if (rb_equal(i, memo[2])) { + memo[0] = UINT2NUM(memo[1]); + rb_iter_break(); + } + memo[1]++; + return Qnil; +} + +static VALUE +find_index_iter_i(i, memop) + VALUE i; + VALUE memop; +{ + VALUE *memo = (VALUE*)memop; + + if (RTEST(rb_yield(i))) { + memo[0] = UINT2NUM(memo[1]); + rb_iter_break(); + } + memo[1]++; + return Qnil; +} + +/* + * call-seq: + * enum.find_index(value) => int or nil + * enum.find_index {| obj | block } => int or nil + * + * Compares each entry in enum with value or passes + * to block. Returns the index for the first for which the + * evaluated value is non-false. If no object matches, returns + * nil + * + * (1..10).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> nil + * (1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> 34 + * (1..100).find_index(50) #=> 49 + * + */ + +static VALUE +enum_find_index(argc, argc, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + VALUE memo[3]; /* [return value, current index, condition value] */ + rb_block_call_func *func; + + if (argc == 0) { + RETURN_ENUMERATOR(obj, 0, 0); + func = find_index_iter_i; + } + else { + rb_scan_args(argc, argv, "1", &memo[2]); + if (rb_block_given_p()) { + rb_warn("given block not used"); + } + func = find_index_i; + } + + memo[0] = Qnil; + memo[1] = 0; + rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo); + return memo[0]; +} + static VALUE find_all_i(i, ary) VALUE i, ary; @@ -1050,8 +1192,10 @@ Init_Enumerable() rb_define_method(rb_mEnumerable,"sort", enum_sort, 0); rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0); rb_define_method(rb_mEnumerable,"grep", enum_grep, 1); + rb_define_method(rb_mEnumerable,"count", enum_count, -1); rb_define_method(rb_mEnumerable,"find", enum_find, -1); rb_define_method(rb_mEnumerable,"detect", enum_find, -1); + rb_define_method(rb_mEnumerable,"find_index", enum_find_index, 0); rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0); rb_define_method(rb_mEnumerable,"select", enum_find_all, 0); rb_define_method(rb_mEnumerable,"reject", enum_reject, 0); -- cgit v1.2.3