ruby-changes:53963
From: mrkn <ko1@a...>
Date: Tue, 4 Dec 2018 13:22:13 +0900 (JST)
Subject: [ruby-changes:53963] mrkn:r66183 (trunk): Import bigdecimal-1.4.0.pre-20181204a
mrkn 2018-12-04 13:22:09 +0900 (Tue, 04 Dec 2018) New Revision: 66183 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66183 Log: Import bigdecimal-1.4.0.pre-20181204a * https://github.com/ruby/bigdecimal/compare/v1.4.0.pre.20181130a..v1.4.0.pre.20181204a Modified files: trunk/ext/bigdecimal/bigdecimal.c trunk/ext/bigdecimal/bigdecimal.gemspec trunk/ext/bigdecimal/bigdecimal.h trunk/test/bigdecimal/test_bigdecimal.rb Index: test/bigdecimal/test_bigdecimal.rb =================================================================== --- test/bigdecimal/test_bigdecimal.rb (revision 66182) +++ test/bigdecimal/test_bigdecimal.rb (revision 66183) @@ -151,6 +151,63 @@ class TestBigDecimal < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/bigdecimal/test_bigdecimal.rb#L151 $SAFE = 0 end + def test_BigDecimal_with_exception_keyword + assert_raise(ArgumentError) { + BigDecimal('.', exception: true) + } + assert_nothing_raised(ArgumentError) { + assert_equal(nil, BigDecimal(".", exception: false)) + } + assert_raise(ArgumentError) { + BigDecimal("1", -1, exception: true) + } + assert_nothing_raised(ArgumentError) { + assert_equal(nil, BigDecimal("1", -1, exception: false)) + } + assert_raise(ArgumentError) { + BigDecimal(42.quo(7), exception: true) + } + assert_nothing_raised(ArgumentError) { + assert_equal(nil, BigDecimal(42.quo(7), exception: false)) + } + assert_raise(ArgumentError) { + BigDecimal(4.2, exception: true) + } + assert_nothing_raised(ArgumentError) { + assert_equal(nil, BigDecimal(4.2, exception: false)) + } + # TODO: support conversion from complex + # assert_raise(RangeError) { + # BigDecimal(1i, exception: true) + # } + # assert_nothing_raised(RangeError) { + # assert_equal(nil, BigDecimal(1i, exception: false)) + # } + assert_raise(TypeError) { + BigDecimal(nil, exception: true) + } + assert_nothing_raised(TypeError) { + assert_equal(nil, BigDecimal(nil, exception: false)) + } + assert_nothing_raised(TypeError) { + assert_equal(nil, BigDecimal(:test, exception: false)) + } + assert_nothing_raised(TypeError) { + assert_equal(nil, BigDecimal(Object.new, exception: false)) + } + # TODO: support to_d + # assert_nothing_raised(TypeError) { + # o = Object.new + # def o.to_d; 3.14; end + # assert_equal(3.14, BigDecimal(o, exception: false)) + # } + # assert_nothing_raised(RuntimeError) { + # o = Object.new + # def o.to_d; raise; end + # assert_equal(nil, BigDecimal(o, exception: false)) + # } + end + def test_s_ver assert_raise(NoMethodError, /undefined method `ver`/) { BigDecimal.ver } end Index: ext/bigdecimal/bigdecimal.c =================================================================== --- ext/bigdecimal/bigdecimal.c (revision 66182) +++ ext/bigdecimal/bigdecimal.c (revision 66183) @@ -646,7 +646,7 @@ VP_EXPORT Real * https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L646 VpNewRbClass(size_t mx, const char *str, VALUE klass) { VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0); - Real *pv = VpAlloc(mx, str, 1); + Real *pv = VpAlloc(mx, str, 1, 1); RTYPEDDATA_DATA(obj) = pv; pv->obj = obj; RB_OBJ_FREEZE(obj); @@ -2313,7 +2313,7 @@ BigDecimal_power(int argc, VALUE*argv, V https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2313 n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec); if (VpIsNaN(x)) { - y = VpCreateRbObject(n, "0"); + y = VpCreateRbObject(n, "0"); RB_GC_GUARD(y->obj); VpSetNaN(y); return ToValue(y); @@ -2437,7 +2437,7 @@ BigDecimal_power(int argc, VALUE*argv, V https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2437 } } else { - y = VpCreateRbObject(n, "0"); + y = VpCreateRbObject(n, "0"); if (BIGDECIMAL_NEGATIVE_P(x)) { if (is_integer(vexp)) { if (is_even(vexp)) { @@ -2470,7 +2470,7 @@ BigDecimal_power(int argc, VALUE*argv, V https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2470 } else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) { if (is_negative(vexp)) { - y = VpCreateRbObject(n, "0"); + y = VpCreateRbObject(n, "0"); if (is_even(vexp)) { VpSetInf(y, VpGetSign(x)); } @@ -2488,7 +2488,7 @@ BigDecimal_power(int argc, VALUE*argv, V https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2488 } else { if (is_positive(vexp)) { - y = VpCreateRbObject(n, "0"); + y = VpCreateRbObject(n, "0"); if (is_even(vexp)) { VpSetInf(y, VpGetSign(x)); } @@ -2538,28 +2538,6 @@ BigDecimal_power_op(VALUE self, VALUE ex https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2538 return BigDecimal_power(1, &exp, self); } -static Real *BigDecimal_new(int argc, VALUE *argv); - -static VALUE -BigDecimal_initialize(int argc, VALUE *argv, VALUE self) -{ - ENTER(1); - Real *pv = rb_check_typeddata(self, &BigDecimal_data_type); - Real *x; - - GUARD_OBJ(x, BigDecimal_new(argc, argv)); - if (ToValue(x)) { - pv = VpCopy(pv, x); - } - else { - VpFree(pv); - pv = x; - } - DATA_PTR(self) = pv; - pv->obj = self; - return self; -} - /* :nodoc: * * private method for dup and clone the provided BigDecimal +other+ @@ -2582,19 +2560,60 @@ BigDecimal_clone(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2560 return self; } +static int +opts_exception_p(VALUE opts) +{ + static ID kwds[1]; + VALUE exception; + if (!kwds[0]) { + kwds[0] = rb_intern_const("exception"); + } + rb_get_kwargs(opts, kwds, 0, 1, &exception); + return exception != Qfalse; +} + static Real * BigDecimal_new(int argc, VALUE *argv) { size_t mf; + VALUE opts = Qnil; VALUE nFig; VALUE iniValue; double d; + int exc; - if (rb_scan_args(argc, argv, "11", &iniValue, &nFig) == 1) { + argc = rb_scan_args(argc, argv, "11:", &iniValue, &nFig, &opts); + exc = opts_exception_p(opts); + + if (argc == 1) { mf = 0; } else { - mf = GetPrecisionInt(nFig); + /* expand GetPrecisionInt for exception suppression */ + ssize_t n = NUM2INT(nFig); + if (n < 0) { + if (!exc) { + return NULL; + } + rb_raise(rb_eArgError, "negative precision"); + } + mf = (size_t)n; + } + + if (SPECIAL_CONST_P(iniValue)) { + switch (iniValue) { + case Qnil: + if (!exc) return NULL; + rb_raise(rb_eTypeError, "can't convert nil into BigDecimal"); + case Qtrue: + if (!exc) return NULL; + rb_raise(rb_eTypeError, "can't convert true into BigDecimal"); + case Qfalse: + if (!exc) return NULL; + rb_raise(rb_eTypeError, "can't convert false into BigDecimal"); + default: + break; + } } switch (TYPE(iniValue)) { @@ -2617,11 +2636,17 @@ BigDecimal_new(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2636 return pv; } if (mf > DBL_DIG+1) { + if (!exc) { + return NULL; + } rb_raise(rb_eArgError, "precision too large."); } /* fall through */ case T_RATIONAL: if (NIL_P(nFig)) { + if (!exc) { + return NULL; + } rb_raise(rb_eArgError, "can't omit precision for a %"PRIsVALUE".", RB_OBJ_CLASSNAME(iniValue)); @@ -2633,8 +2658,13 @@ BigDecimal_new(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2658 default: break; } + /* TODO: support to_d */ + if (!exc) { + iniValue = rb_check_convert_type(iniValue, T_STRING, "String", "to_str"); + if (NIL_P(iniValue)) return NULL; + } StringValueCStr(iniValue); - return VpAlloc(mf, RSTRING_PTR(iniValue), 1); + return VpAlloc(mf, RSTRING_PTR(iniValue), 1, exc); } /* call-seq: @@ -2669,14 +2699,16 @@ BigDecimal_new(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2699 * value is omitted, this exception is raised. */ static VALUE -BigDecimal_global_new(int argc, VALUE *argv, VALUE self) +f_BigDecimal(int argc, VALUE *argv, VALUE self) { ENTER(1); Real *pv; VALUE obj; obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0); - GUARD_OBJ(pv, BigDecimal_new(argc, argv)); + pv = BigDecimal_new(argc, argv); + if (pv == NULL) return Qnil; + SAVE(pv); if (ToValue(pv)) pv = VpCopy(NULL, pv); RTYPEDDATA_DATA(obj) = pv; RB_OBJ_FREEZE(obj); @@ -3112,7 +3144,7 @@ rmpd_util_str_to_d(VALUE str) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3144 VALUE obj; c_str = StringValueCStr(str); - GUARD_OBJ(pv, VpAlloc(0, c_str, 0)); + GUARD_OBJ(pv, VpAlloc(0, c_str, 0, 1)); obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv); RB_OBJ_FREEZE(obj); return obj; @@ -3259,7 +3291,7 @@ Init_bigdecimal(void) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3291 rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric); /* Global function */ - rb_define_global_function("BigDecimal", BigDecimal_global_new, -1); + rb_define_global_function("BigDecimal", f_BigDecimal, -1); /* Class methods */ rb_undef_method(CLASS_OF(rb_cBigDecimal), "allocate"); @@ -3387,14 +3419,13 @@ Init_bigdecimal(void) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3419 arg = rb_str_new2("+Infinity"); /* Positive infinity value. */ - rb_define_const(rb_cBigDecimal, "INFINITY", BigDecimal_global_new(1, &arg, rb_cBigDecimal)); + rb_define_const(rb_cBigDecimal, "INFINITY", f_BigDecimal(1, &arg, rb_cBigDecimal)); arg = rb_str_new2("NaN"); /* 'Not a Number' value. */ - rb_define_const(rb_cBigDecimal, "NAN", BigDecimal_global_new(1, &arg, rb_cBigDecimal)); + rb_define_const(rb_cBigDecimal, "NAN", f_BigDecimal(1, &arg, rb_cBigDecimal)); /* instance methods */ - rb_define_method(rb_cBigDecimal, "initialize", BigDecimal_initialize, -1); rb_define_method(rb_cBigDecimal, "initialize_copy", BigDecimal_initialize_copy, 1); rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0); @@ -3687,13 +3718,13 @@ VpSetRoundMode(unsigned short n) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3718 /* * 0.0 & 1.0 generator - * These gOne_..... can be any name - * referenced from nowhere except One(). - * gOne_..... must have global scope + * These gZero_..... and gOne_..... can be any name + * referenced from nowhere except Zero() and One(). + * gZero_..... and gOne_..... must have global scope * (to let the compiler know they may be changed in outside * (... but not actually..)). */ -volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0; +volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0; static double One(void) @@ -3931,8 +3962,8 @@ VpInit(BDIGIT BaseVal) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3962 VpGetDoubleNegZero(); /* Allocates Vp constants. */ - VpConstOne = VpAlloc(1UL, "1", 1); - VpPt5 = VpAlloc(1UL, ".5", 1); + VpConstOne = VpAlloc(1UL, "1", 1, 1); + VpPt5 = VpAlloc(1UL, ".5", 1, 1); #ifdef BIGDECIMAL_DEBUG gnAlloc = 0; @@ -4056,7 +4087,7 @@ rmpd_parse_special_string(const char *st https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4087 * NULL be returned if memory allocation is failed,or any error. */ VP_EXPORT Real * -VpAlloc(size_t mx, const char *szVal, int strict_p) +VpAlloc(size_t mx, const char *szVal, int strict_p, int exc) { const char *orig_szVal = szVal; size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc; @@ -4255,7 +4286,9 @@ VpAlloc(size_t mx, const char *szVal, in https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4286 if (!strict_p) { goto return_zero; } - + if (!exc) { + return NULL; + } str = rb_str_new2(orig_szVal); rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str); } @@ -4832,7 +4865,7 @@ VpMult(Real *c, Real *a, Real *b) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4865 if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */ w = c; - c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1); + c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1, 1); MxIndC = MxIndAB; } @@ -6000,8 +6033,8 @@ VpSqrt(Real *y, Real *x) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L6033 if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec; /* allocate temporally variables */ - f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1); - r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1); + f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1, 1); + r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1, 1); nr = 0; y_prec = y->MaxPrec; @@ -6453,8 +6486,8 @@ VpPower(Real *y, Real *x, SIGNED_VALUE n https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L6486 /* Allocate working variables */ - w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1); - w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1); + w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1); + w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1); /* calculation start */ VpAsgn(y, x, 1); Index: ext/bigdecimal/bigdecimal.gemspec =================================================================== --- ext/bigdecimal/bigdecimal.gemspec (revision 66182) +++ ext/bigdecimal/bigdecimal.gemspec (revision 66183) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.gemspec#L1 # coding: utf-8 -bigdecimal_version = '1.4.0.pre.20181121a' +bigdecimal_version = '1.4.0.pre.20181204a' Gem::Specification.new do |s| s.name = "bigdecimal" @@ -18,6 +18,7 @@ Gem::Specification.new do |s| https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.gemspec#L18 s.files = %w[ bigdecimal.gemspec ext/bigdecimal/bigdecimal.c + ext/bigdecimal/bigdecimal.def ext/bigdecimal/bigdecimal.h ext/bigdecimal/depend ext/bigdecimal/extconf.rb Index: ext/bigdecimal/bigdecimal.h =================================================================== --- ext/bigdecimal/bigdecimal.h (revision 66182) +++ ext/bigdecimal/bigdecimal.h (revision 66183) @@ -308,7 +308,7 @@ VP_EXPORT size_t VpInit(BDIGIT BaseVal); https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.h#L308 VP_EXPORT void *VpMemAlloc(size_t mb); VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb); VP_EXPORT void VpFree(Real *pv); -VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p); +VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p, int exc); VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw); VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation); VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/