mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/bigdecimal] Refactor to decompose VpNewVarArg into small functions
7504871c48
This commit is contained in:
parent
d11b78f9c4
commit
512e08895f
1 changed files with 138 additions and 96 deletions
|
@ -2725,108 +2725,138 @@ opts_exception_p(VALUE opts)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Real *
|
static VALUE
|
||||||
VpNewVarArg(int argc, VALUE *argv)
|
check_exception(VALUE bd)
|
||||||
{
|
{
|
||||||
size_t mf;
|
assert(is_kind_of_BigDecimal(bd));
|
||||||
VALUE opts = Qnil;
|
|
||||||
VALUE nFig;
|
|
||||||
VALUE iniValue;
|
|
||||||
double d;
|
|
||||||
int exc;
|
|
||||||
|
|
||||||
argc = rb_scan_args(argc, argv, "11:", &iniValue, &nFig, &opts);
|
Real *vp;
|
||||||
exc = opts_exception_p(opts);
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
||||||
|
ToValue(vp); /* ToValue performs exception check */
|
||||||
|
|
||||||
if (argc == 1) {
|
return bd;
|
||||||
mf = 0;
|
}
|
||||||
}
|
|
||||||
else {
|
static VALUE
|
||||||
/* expand GetPrecisionInt for exception suppression */
|
rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
|
||||||
ssize_t n = NUM2INT(nFig);
|
{
|
||||||
if (n < 0) {
|
Real *vp = GetVpValue(val, 1);
|
||||||
if (!exc) {
|
return check_exception(vp->obj);
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
rb_raise(rb_eArgError, "negative precision");
|
static VALUE
|
||||||
}
|
rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
||||||
mf = (size_t)n;
|
{
|
||||||
|
double d = RFLOAT_VALUE(val);
|
||||||
|
if (!isfinite(d)) {
|
||||||
|
Real *vp = VpCreateRbObject(1, NULL); /* vp->obj is allocated */
|
||||||
|
VpDtoV(vp, d);
|
||||||
|
return check_exception(vp->obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (iniValue) {
|
if (digs == SIZE_MAX) {
|
||||||
|
if (!raise_exception)
|
||||||
|
return Qnil;
|
||||||
|
rb_raise(rb_eArgError,
|
||||||
|
"can't omit precision for a %"PRIsVALUE".",
|
||||||
|
CLASS_OF(val));
|
||||||
|
}
|
||||||
|
else if (digs > DBLE_FIG) {
|
||||||
|
if (!raise_exception)
|
||||||
|
return Qnil;
|
||||||
|
rb_raise(rb_eArgError, "precision too large.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Real *vp = GetVpValueWithPrec(val, digs, 1);
|
||||||
|
return check_exception(vp->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
||||||
|
{
|
||||||
|
if (digs == SIZE_MAX) {
|
||||||
|
if (!raise_exception)
|
||||||
|
return Qnil;
|
||||||
|
rb_raise(rb_eArgError,
|
||||||
|
"can't omit precision for a %"PRIsVALUE".",
|
||||||
|
CLASS_OF(val));
|
||||||
|
}
|
||||||
|
Real *vp = GetVpValueWithPrec(val, digs, 1);
|
||||||
|
return check_exception(vp->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
||||||
|
{
|
||||||
|
if (digs == SIZE_MAX)
|
||||||
|
digs = 0;
|
||||||
|
|
||||||
|
const char *c_str = StringValueCStr(val);
|
||||||
|
Real *vp = VpAlloc(digs, c_str, 1, raise_exception);
|
||||||
|
if (!vp)
|
||||||
|
return Qnil;
|
||||||
|
vp->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, vp);
|
||||||
|
RB_OBJ_FREEZE(vp->obj);
|
||||||
|
return check_exception(vp->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
||||||
|
{
|
||||||
|
switch (val) {
|
||||||
case Qnil:
|
case Qnil:
|
||||||
case Qtrue:
|
case Qtrue:
|
||||||
case Qfalse:
|
case Qfalse:
|
||||||
if (!exc) return NULL;
|
if (!raise_exception)
|
||||||
|
return Qnil;
|
||||||
rb_raise(rb_eTypeError,
|
rb_raise(rb_eTypeError,
|
||||||
"can't convert %"PRIsVALUE" into BigDecimal", iniValue);
|
"can't convert %"PRIsVALUE" into BigDecimal", val);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
retry:
|
if (is_kind_of_BigDecimal(val)) {
|
||||||
switch (TYPE(iniValue)) {
|
if (digs == SIZE_MAX)
|
||||||
case T_DATA:
|
return check_exception(val);
|
||||||
if (is_kind_of_BigDecimal(iniValue)) {
|
|
||||||
return DATA_PTR(iniValue);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_FIXNUM:
|
Real *vp;
|
||||||
/* fall through */
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
||||||
case T_BIGNUM:
|
vp = VpCopy(NULL, vp);
|
||||||
return GetVpValue(iniValue, 1);
|
vp->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, vp);
|
||||||
|
RB_OBJ_FREEZE(vp->obj);
|
||||||
case T_FLOAT:
|
return check_exception(vp->obj);
|
||||||
d = RFLOAT_VALUE(iniValue);
|
|
||||||
if (!isfinite(d)) {
|
|
||||||
Real *pv = VpCreateRbObject(1, NULL);
|
|
||||||
VpDtoV(pv, d);
|
|
||||||
return pv;
|
|
||||||
}
|
|
||||||
if (mf > DBLE_FIG) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
return GetVpValueWithPrec(iniValue, mf, 1);
|
|
||||||
|
|
||||||
case T_COMPLEX:
|
|
||||||
{
|
|
||||||
VALUE im;
|
|
||||||
im = rb_complex_imag(iniValue);
|
|
||||||
if (!is_zero(im)) {
|
|
||||||
rb_raise(rb_eArgError,
|
|
||||||
"Unable to make a BigDecimal from non-zero imaginary number");
|
|
||||||
}
|
|
||||||
iniValue = rb_complex_real(iniValue);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
case T_STRING:
|
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
/* TODO: support to_d */
|
else if (RB_INTEGER_TYPE_P(val)) {
|
||||||
if (!exc) {
|
return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
|
||||||
iniValue = rb_check_convert_type(iniValue, T_STRING, "String", "to_str");
|
|
||||||
if (NIL_P(iniValue)) return NULL;
|
|
||||||
}
|
}
|
||||||
StringValueCStr(iniValue);
|
else if (RB_FLOAT_TYPE_P(val)) {
|
||||||
return VpAlloc(mf, RSTRING_PTR(iniValue), 1, exc);
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(val, T_RATIONAL)) {
|
||||||
|
return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(val, T_COMPLEX)) {
|
||||||
|
VALUE im = rb_complex_imag(val);
|
||||||
|
if (!is_zero(im)) {
|
||||||
|
/* TODO: handle raise_exception */
|
||||||
|
rb_raise(rb_eArgError,
|
||||||
|
"Unable to make a BigDecimal from non-zero imaginary number");
|
||||||
|
}
|
||||||
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(val, T_STRING)) {
|
||||||
|
return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
|
||||||
|
}
|
||||||
|
/* TODO: chheck to_d */
|
||||||
|
/* TODO: chheck to_int */
|
||||||
|
if (!raise_exception) {
|
||||||
|
VALUE str = rb_check_convert_type(val, T_STRING, "String", "to_str");
|
||||||
|
if (NIL_P(str))
|
||||||
|
return Qnil;
|
||||||
|
val = str;
|
||||||
|
}
|
||||||
|
return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call-seq:
|
/* call-seq:
|
||||||
|
@ -2868,19 +2898,31 @@ VpNewVarArg(int argc, VALUE *argv)
|
||||||
static VALUE
|
static VALUE
|
||||||
f_BigDecimal(int argc, VALUE *argv, VALUE self)
|
f_BigDecimal(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
ENTER(1);
|
VALUE val, digs_v, opts = Qnil;
|
||||||
Real *pv;
|
argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts);
|
||||||
|
int exception = opts_exception_p(opts);
|
||||||
|
|
||||||
if (argc > 0 && CLASS_OF(argv[0]) == rb_cBigDecimal) {
|
size_t digs = SIZE_MAX; /* this means digs is omitted */
|
||||||
if (argc == 1 || (argc == 2 && RB_TYPE_P(argv[1], T_HASH))) return argv[0];
|
if (argc > 1) {
|
||||||
|
digs_v = rb_to_int(digs_v);
|
||||||
|
if (FIXNUM_P(digs_v)) {
|
||||||
|
long n = FIX2LONG(digs_v);
|
||||||
|
if (n < 0)
|
||||||
|
goto negative_digs;
|
||||||
|
digs = (size_t)n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (RBIGNUM_NEGATIVE_P(digs_v)) {
|
||||||
|
negative_digs:
|
||||||
|
if (!exception)
|
||||||
|
return Qnil;
|
||||||
|
rb_raise(rb_eArgError, "negative precision");
|
||||||
|
}
|
||||||
|
digs = NUM2SIZET(digs_v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pv = VpNewVarArg(argc, argv);
|
|
||||||
if (pv == NULL) return Qnil;
|
return rb_convert_to_BigDecimal(val, digs, exception);
|
||||||
SAVE(pv);
|
|
||||||
if (ToValue(pv)) pv = VpCopy(NULL, pv);
|
|
||||||
pv->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv);
|
|
||||||
RB_OBJ_FREEZE(pv->obj);
|
|
||||||
return pv->obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue