From 3a3e250975d0ce34b0e5628a2fc2a3bfa7722188 Mon Sep 17 00:00:00 2001 From: knu Date: Thu, 29 May 2008 19:18:54 +0000 Subject: [PATCH] * enum.c (enum_count, count_all_i, Init_Enumerable), array.c (rb_ary_count): If no argument or block is given, count the number of all elements. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16693 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ array.c | 10 +++++++--- enum.c | 32 +++++++++++++++++++++++++++----- test/ruby/test_array.rb | 1 + test/ruby/test_enum.rb | 1 + 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3c893d01b6..a829aee36f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Fri May 30 04:17:13 2008 Akinori MUSHA + + * enum.c (enum_count, count_all_i, Init_Enumerable), + array.c (rb_ary_count): If no argument or block is given, count + the number of all elements. + Fri May 30 03:12:18 2008 Akinori MUSHA * ext/openssl/ossl_bn.c (ossl_bn_s_rand, ossl_bn_s_pseudo_rand): diff --git a/array.c b/array.c index d452eade3a..787c27b983 100644 --- a/array.c +++ b/array.c @@ -2747,13 +2747,16 @@ rb_ary_compact(VALUE ary) /* * call-seq: + * array.count -> int * array.count(obj) -> int * array.count { |item| block } -> int * - * Returns the number of elements which equals to obj. - * If a block is given, counts the number of elements yielding a true value. + * Returns the number of elements. If an argument is given, counts + * the number of elements which equals to obj. If a block is + * given, counts the number of elements yielding a true value. * * ary = [1, 2, 4, 2] + * ary.count # => 4 * ary.count(2) # => 2 * ary.count{|x|x%2==0} # => 3 * @@ -2767,7 +2770,8 @@ rb_ary_count(int argc, VALUE *argv, VALUE ary) if (argc == 0) { VALUE *p, *pend; - RETURN_ENUMERATOR(ary, 0, 0); + if (!rb_block_given_p()) + return LONG2NUM(RARRAY_LEN(ary)); for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (RTEST(rb_yield(*p))) n++; diff --git a/enum.c b/enum.c index 1f0c588ce2..7a7f180161 100644 --- a/enum.c +++ b/enum.c @@ -14,7 +14,7 @@ #include "ruby/util.h" VALUE rb_mEnumerable; -static ID id_each, id_eqq, id_cmp, id_next; +static ID id_each, id_eqq, id_cmp, id_next, id_size; static VALUE enum_values_pack(int argc, VALUE *argv) @@ -108,15 +108,29 @@ count_iter_i(VALUE i, VALUE memop, int argc, VALUE *argv) return Qnil; } +static VALUE +count_all_i(VALUE i, VALUE memop, int argc, VALUE *argv) +{ + VALUE *memo = (VALUE*)memop; + + memo[0]++; + return Qnil; +} + /* * call-seq: + * enum.count => int * 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. + * Returns the number of items in enum, where #size is called + * if it responds to it, otherwise the items are counted through + * enumeration. If an argument is given, counts 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 # => 4 * ary.count(2) # => 2 * ary.count{|x|x%2==0} # => 3 * @@ -129,8 +143,15 @@ enum_count(int argc, VALUE *argv, VALUE obj) rb_block_call_func *func; if (argc == 0) { - RETURN_ENUMERATOR(obj, 0, 0); - func = count_iter_i; + if (rb_block_given_p()) { + func = count_iter_i; + } + else { + if (rb_respond_to(obj, id_size)) { + return rb_funcall(obj, id_size, 0, 0); + } + func = count_all_i; + } } else { rb_scan_args(argc, argv, "1", &memo[1]); @@ -1826,5 +1847,6 @@ Init_Enumerable(void) id_each = rb_intern("each"); id_cmp = rb_intern("<=>"); id_next = rb_intern("next"); + id_size = rb_intern("size"); } diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 035b70ad2a..877df749f8 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -539,6 +539,7 @@ class TestArray < Test::Unit::TestCase def test_count a = @cls[1, 2, 3, 1, 2] + assert_equal(5, a.count) assert_equal(2, a.count(1)) assert_equal(3, a.count {|x| x % 2 == 1 }) assert_equal(2, a.count(1) {|x| x % 2 == 1 }) diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb index 97b4ec468b..a739982963 100644 --- a/test/ruby/test_enum.rb +++ b/test/ruby/test_enum.rb @@ -30,6 +30,7 @@ class TestEnumerable < Test::Unit::TestCase end def test_count + assert_equal(5, @obj.count) assert_equal(2, @obj.count(1)) assert_equal(3, @obj.count {|x| x % 2 == 1 }) assert_equal(2, @obj.count(1) {|x| x % 2 == 1 })