ruby-changes:26509
From: mrkn <ko1@a...>
Date: Sun, 23 Dec 2012 00:08:34 +0900 (JST)
Subject: [ruby-changes:26509] mrkn:r38560 (trunk): * include/ruby/intern.h: add the prototype declaration of
mrkn 2012-12-23 00:06:22 +0900 (Sun, 23 Dec 2012) New Revision: 38560 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38560 Log: * include/ruby/intern.h: add the prototype declaration of rb_num_coerce_bit. * numeric.c (rb_num_coerce_bit): the new coerce function for bitwise binary operation. * bignum.c (rb_big_and): use coerce to convert the argument, which isn't a Fixnum nor a Bignum, to the corresponding Integer object so that bitwise operations can support Integer-mimic objects. [Bug #1792] [ruby-core:39491] * bignum.c (rb_big_or): ditto. * bignum.c (rb_big_xor): ditto. * numeric.c (bit_coerce): ditto. * numeric.c (fix_and): ditto. * numeric.c (fix_or): ditto. * numeric.c (fix_xor): ditto. * test/ruby/test_integer.rb: add tests for the above changes. * test/ruby/test_bignum.rb: ditto. Modified files: trunk/ChangeLog trunk/bignum.c trunk/include/ruby/intern.h trunk/numeric.c trunk/test/ruby/test_bignum.rb trunk/test/ruby/test_integer.rb Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 38559) +++ include/ruby/intern.h (revision 38560) @@ -519,6 +519,7 @@ NORETURN(void rb_num_zerodiv(void)); https://github.com/ruby/ruby/blob/trunk/include/ruby/intern.h#L519 VALUE rb_num_coerce_bin(VALUE, VALUE, ID); VALUE rb_num_coerce_cmp(VALUE, VALUE, ID); VALUE rb_num_coerce_relop(VALUE, VALUE, ID); +VALUE rb_num_coerce_bit(VALUE, VALUE, ID); VALUE rb_num2fix(VALUE); VALUE rb_fix2str(VALUE, int); VALUE rb_dbl_cmp(double, double); Index: ChangeLog =================================================================== --- ChangeLog (revision 38559) +++ ChangeLog (revision 38560) @@ -1,3 +1,32 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Dec 23 00:08:00 2012 Kenta Murata <mrkn@m...> + + * include/ruby/intern.h: add the prototype declaration of + rb_num_coerce_bit. + + * numeric.c (rb_num_coerce_bit): the new coerce function for bitwise + binary operation. + + * bignum.c (rb_big_and): use coerce to convert the argument, which isn't + a Fixnum nor a Bignum, to the corresponding Integer object so that + bitwise operations can support Integer-mimic objects. + [Bug #1792] [ruby-core:39491] + + * bignum.c (rb_big_or): ditto. + + * bignum.c (rb_big_xor): ditto. + + * numeric.c (bit_coerce): ditto. + + * numeric.c (fix_and): ditto. + + * numeric.c (fix_or): ditto. + + * numeric.c (fix_xor): ditto. + + * test/ruby/test_integer.rb: add tests for the above changes. + + * test/ruby/test_bignum.rb: ditto. + Sun Dec 23 00:04:54 2012 Nobuyoshi Nakada <nobu@r...> * internal.h (QUOTE, QUOTE_ID): quote unprintable chars in strings and Index: numeric.c =================================================================== --- numeric.c (revision 38559) +++ numeric.c (revision 38560) @@ -3165,15 +3165,29 @@ fix_rev(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3165 return ~num | FIXNUM_FLAG; } -static VALUE -bit_coerce(VALUE x) +static int +bit_coerce(VALUE *x, VALUE *y, int err) { - while (!FIXNUM_P(x) && !RB_TYPE_P(x, T_BIGNUM)) { - rb_raise(rb_eTypeError, - "can't convert %s into Integer for bitwise arithmetic", - rb_obj_classname(x)); + if (!FIXNUM_P(*y) && !RB_TYPE_P(*y, T_BIGNUM)) { + do_coerce(x, y, err); + if (!FIXNUM_P(*x) && !RB_TYPE_P(*x, T_BIGNUM) + && !FIXNUM_P(*y) && !RB_TYPE_P(*y, T_BIGNUM)) { + if (!err) return FALSE; + rb_raise(rb_eTypeError, + "%s can't be coerced into %s for bitwise arithmetic", + rb_special_const_p(*y) ? + RSTRING_PTR(rb_inspect(*y)) : rb_obj_classname(*y), + rb_obj_classname(*x)); + } } - return x; + return TRUE; +} + +VALUE +rb_num_coerce_bit(VALUE x, VALUE y, ID func) +{ + bit_coerce(&x, &y, TRUE); + return rb_funcall(x, func, 1, y); } /* @@ -3186,13 +3200,17 @@ bit_coerce(VALUE x) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3200 static VALUE fix_and(VALUE x, VALUE y) { - long val; + if (FIXNUM_P(y)) { + long val = FIX2LONG(x) & FIX2LONG(y); + return LONG2NUM(val); + } - if (!FIXNUM_P(y = bit_coerce(y))) { + if (RB_TYPE_P(y, T_BIGNUM)) { return rb_big_and(y, x); } - val = FIX2LONG(x) & FIX2LONG(y); - return LONG2NUM(val); + + bit_coerce(&x, &y, TRUE); + return rb_funcall(x, rb_intern("&"), 1, y); } /* @@ -3205,13 +3223,17 @@ fix_and(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3223 static VALUE fix_or(VALUE x, VALUE y) { - long val; + if (FIXNUM_P(y)) { + long val = FIX2LONG(x) | FIX2LONG(y); + return LONG2NUM(val); + } - if (!FIXNUM_P(y = bit_coerce(y))) { + if (RB_TYPE_P(y, T_BIGNUM)) { return rb_big_or(y, x); } - val = FIX2LONG(x) | FIX2LONG(y); - return LONG2NUM(val); + + bit_coerce(&x, &y, TRUE); + return rb_funcall(x, rb_intern("|"), 1, y); } /* @@ -3224,13 +3246,17 @@ fix_or(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3246 static VALUE fix_xor(VALUE x, VALUE y) { - long val; + if (FIXNUM_P(y)) { + long val = FIX2LONG(x) ^ FIX2LONG(y); + return LONG2NUM(val); + } - if (!FIXNUM_P(y = bit_coerce(y))) { + if (RB_TYPE_P(y, T_BIGNUM)) { return rb_big_xor(y, x); } - val = FIX2LONG(x) ^ FIX2LONG(y); - return LONG2NUM(val); + + bit_coerce(&x, &y, TRUE); + return rb_funcall(x, rb_intern("^"), 1, y); } static VALUE fix_lshift(long, unsigned long); Index: bignum.c =================================================================== --- bignum.c (revision 38559) +++ bignum.c (revision 38560) @@ -3201,18 +3201,6 @@ rb_big_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/bignum.c#L3201 return DBL2NUM(pow(rb_big2dbl(x), d)); } -static inline VALUE -bit_coerce(VALUE x) -{ - while (!FIXNUM_P(x) && !RB_TYPE_P(x, T_BIGNUM)) { - rb_raise(rb_eTypeError, - "can't convert %s into Integer for bitwise arithmetic", - rb_obj_classname(x)); - x = rb_to_int(x); - } - return x; -} - static VALUE bigand_int(VALUE x, long y) { @@ -3272,8 +3260,13 @@ rb_big_and(VALUE xx, VALUE yy) https://github.com/ruby/ruby/blob/trunk/bignum.c#L3260 long i, l1, l2; char sign; + if (!FIXNUM_P(yy) && !RB_TYPE_P(yy, T_BIGNUM)) { + return rb_num_coerce_bit(xx, yy, '&'); + } + x = xx; - y = bit_coerce(yy); + y = yy; + if (!RBIGNUM_SIGN(x)) { x = rb_big_clone(x); get2comp(x); @@ -3363,8 +3356,12 @@ rb_big_or(VALUE xx, VALUE yy) https://github.com/ruby/ruby/blob/trunk/bignum.c#L3356 long i, l1, l2; char sign; + if (!FIXNUM_P(yy) && !RB_TYPE_P(yy, T_BIGNUM)) { + return rb_num_coerce_bit(xx, yy, '|'); + } + x = xx; - y = bit_coerce(yy); + y = yy; if (!RBIGNUM_SIGN(x)) { x = rb_big_clone(x); @@ -3455,8 +3452,12 @@ rb_big_xor(VALUE xx, VALUE yy) https://github.com/ruby/ruby/blob/trunk/bignum.c#L3452 long i, l1, l2; char sign; + if (!FIXNUM_P(yy) && !RB_TYPE_P(yy, T_BIGNUM)) { + return rb_num_coerce_bit(xx, yy, '^'); + } + x = xx; - y = bit_coerce(yy); + y = yy; if (!RBIGNUM_SIGN(x)) { x = rb_big_clone(x); Index: test/ruby/test_bignum.rb =================================================================== --- test/ruby/test_bignum.rb (revision 38559) +++ test/ruby/test_bignum.rb (revision 38560) @@ -654,4 +654,40 @@ class TestBignum < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_bignum.rb#L654 def test_frozen assert_equal(true, (2**100).frozen?) end + + def test_bitwise_and_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 & obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 & 10, T1024 & obj) + end + + def test_bitwise_or_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 | obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 | 10, T1024 | obj) + end + + def test_bitwise_xor_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { T1024 ^ obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(T1024 ^ 10, T1024 ^ obj) + end end Index: test/ruby/test_integer.rb =================================================================== --- test/ruby/test_integer.rb (revision 38559) +++ test/ruby/test_integer.rb (revision 38560) @@ -205,4 +205,40 @@ class TestInteger < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_integer.rb#L205 assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1)) assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class) end + + def test_bitwise_and_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 & obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 & 10, 3 & obj) + end + + def test_bitwise_or_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 | obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 | 10, 3 | obj) + end + + def test_bitwise_xor_with_integer_mimic_object + def (obj = Object.new).to_int + 10 + end + assert_raise(TypeError, '[ruby-core:39491]') { 3 ^ obj } + + def obj.coerce(other) + [other, 10] + end + assert_equal(3 ^ 10, 3 ^ obj) + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/