[前][次][番号順一覧][スレッド一覧]

ruby-changes:42073

From: akr <ko1@a...>
Date: Thu, 17 Mar 2016 18:50:25 +0900 (JST)
Subject: [ruby-changes:42073] akr:r54147 (trunk): * enum.c (enum_inject): Implement the specialized code for sum of

akr	2016-03-17 18:50:19 +0900 (Thu, 17 Mar 2016)

  New Revision: 54147

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=54147

  Log:
    * enum.c (enum_inject): Implement the specialized code for sum of
      integers including Bignums.
    
    * internal.h (rb_fix_plus): Declared to be usable from enum_inject.
    
    * numeric.c (rb_fix_plus): Defined.

  Modified files:
    trunk/ChangeLog
    trunk/enum.c
    trunk/internal.h
    trunk/numeric.c
    trunk/test/ruby/test_enum.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 54146)
+++ ChangeLog	(revision 54147)
@@ -1,3 +1,12 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Mar 17 18:39:04 2016  Tanaka Akira  <akr@f...>
+
+	* enum.c (enum_inject): Implement the specialized code for sum of
+	  integers including Bignums.
+
+	* internal.h (rb_fix_plus): Declared to be usable from enum_inject.
+
+	* numeric.c (rb_fix_plus): Defined.
+
 Thu Mar 17 17:20:28 2016  Anton Davydov  <antondavydov.o@g...>
 
 	* thread_sync.c: [DOC] Update documentation for Queue class
Index: internal.h
===================================================================
--- internal.h	(revision 54146)
+++ internal.h	(revision 54147)
@@ -958,6 +958,7 @@ int rb_num_negative_p(VALUE); https://github.com/ruby/ruby/blob/trunk/internal.h#L958
 VALUE rb_int_succ(VALUE num);
 VALUE rb_int_pred(VALUE num);
 VALUE rb_dbl_hash(double d);
+VALUE rb_fix_plus(VALUE x, VALUE y);
 
 #if USE_FLONUM
 #define RUBY_BIT_ROTL(v, n) (((v) << (n)) | ((v) >> ((sizeof(v) * 8) - n)))
Index: enum.c
===================================================================
--- enum.c	(revision 54146)
+++ enum.c	(revision 54147)
@@ -719,17 +719,45 @@ enum_inject(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/enum.c#L719
             i = 0;
         }
         id = SYM2ID(op);
-        if (id == idPLUS && FIXNUM_P(v) &&
-            rb_method_basic_definition_p(rb_cFixnum, idPLUS)) {
-            long n = FIX2LONG(v);
-            while (i < RARRAY_LEN(obj)) {
-                VALUE e = RARRAY_AREF(obj, i);
-                if (!FIXNUM_P(e)) break;
-                n += FIX2LONG(e); /* should not overflow long type */
-                i++;
-                if (!FIXABLE(n)) break;
+        if (id == idPLUS) {
+            if (FIXNUM_P(v) &&
+                rb_method_basic_definition_p(rb_cFixnum, idPLUS)) {
+                long n = FIX2LONG(v);
+                while (i < RARRAY_LEN(obj)) {
+                    VALUE e = RARRAY_AREF(obj, i);
+                    if (!FIXNUM_P(e)) break;
+                    n += FIX2LONG(e); /* should not overflow long type */
+                    i++;
+                    if (!FIXABLE(n)) break;
+                }
+                v = LONG2NUM(n);
+            }
+            if (i < RARRAY_LEN(obj) && (FIXNUM_P(v) || RB_TYPE_P(v, T_BIGNUM)) &&
+                rb_method_basic_definition_p(rb_cFixnum, idPLUS) &&
+                rb_method_basic_definition_p(rb_cBignum, idPLUS)) {
+                long n = 0;
+                while (i < RARRAY_LEN(obj)) {
+                    VALUE e = RARRAY_AREF(obj, i);
+                    if (FIXNUM_P(e)) {
+                        n += FIX2LONG(e); /* should not overflow long type */
+                        i++;
+                        if (!FIXABLE(n)) {
+                            v = rb_big_plus(LONG2NUM(n), v);
+                            n = 0;
+                        }
+                    }
+                    else if (RB_TYPE_P(e, T_BIGNUM)) {
+                        v = rb_big_plus(e, v);
+                        i++;
+                    }
+                    else {
+                        break;
+                    }
+                }
+                if (n != 0) {
+                    v = rb_fix_plus(LONG2FIX(n), v);
+                }
             }
-            v = LONG2NUM(n);
         }
         for (; i<RARRAY_LEN(obj); i++) {
             v = rb_funcall(v, id, 1, RARRAY_AREF(obj, i));
Index: numeric.c
===================================================================
--- numeric.c	(revision 54146)
+++ numeric.c	(revision 54147)
@@ -2990,6 +2990,12 @@ fix_plus(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L2990
     }
 }
 
+VALUE
+rb_fix_plus(VALUE x, VALUE y)
+{
+    return fix_plus(x, y);
+}
+
 /*
  * call-seq:
  *   fix - numeric  ->  numeric_result
Index: test/ruby/test_enum.rb
===================================================================
--- test/ruby/test_enum.rb	(revision 54146)
+++ test/ruby/test_enum.rb	(revision 54147)
@@ -2,6 +2,7 @@ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L2
 require 'test/unit'
 EnvUtil.suppress_warning {require 'continuation'}
 require 'stringio'
+require "rbconfig/sizeof"
 
 class TestEnumerable < Test::Unit::TestCase
   def setup
@@ -184,7 +185,33 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L185
     assert_equal(nil, @empty.inject() {9})
   end
 
+  FIXNUM_MIN = -(1 << (8 * RbConfig::SIZEOF['long'] - 2))
+  FIXNUM_MAX = (1 << (8 * RbConfig::SIZEOF['long'] - 2)) - 1
+
+  def test_inject_array_mul
+    assert_equal(nil, [].inject(:*))
+    assert_equal(5, [5].inject(:*))
+    assert_equal(35, [5, 7].inject(:*))
+    assert_equal(3, [].inject(3, :*))
+    assert_equal(15, [5].inject(3, :*))
+    assert_equal(105, [5, 7].inject(3, :*))
+  end
+
   def test_inject_array_plus
+    assert_equal(3, [3].inject(:+))
+    assert_equal(8, [3, 5].inject(:+))
+    assert_equal(15, [3, 5, 7].inject(:+))
+    assert_equal(15.0, [3, 5, 7.0].inject(:+))
+    assert_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).inject(:+))
+    assert_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).inject(:+))
+    assert_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).inject(:+))
+    assert_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).inject(:+))
+    assert_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).inject(:+))
+    assert_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).inject(:+))
+    assert_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].inject(:+))
+  end
+
+  def test_inject_array_plus_redefined
     assert_separately([], <<-"end;")
       class Fixnum
         undef :+
@@ -194,6 +221,15 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L221
       end
       assert_equal(0, [1,2,3].inject(:+), "[ruby-dev:49510] [Bug#12178]")
     end;
+    assert_separately([], <<-"end;")
+      class Bignum
+        undef :+
+        def +(x)
+          0
+        end
+      end
+      assert_equal(0, [#{FIXNUM_MAX},1,1].inject(:+))
+    end;
   end
 
   def test_partition

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]