Skip to content

Commit 7504871

Browse files
committed
Refactor to decompose VpNewVarArg into small functions
1 parent 5c808ee commit 7504871

File tree

1 file changed

+137
-95
lines changed

1 file changed

+137
-95
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 137 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,108 +2725,138 @@ opts_exception_p(VALUE opts)
27252725
}
27262726
#endif
27272727

2728-
static Real *
2729-
VpNewVarArg(int argc, VALUE *argv)
2728+
static VALUE
2729+
check_exception(VALUE bd)
27302730
{
2731-
size_t mf;
2732-
VALUE opts = Qnil;
2733-
VALUE nFig;
2734-
VALUE iniValue;
2735-
double d;
2736-
int exc;
2731+
assert(is_kind_of_BigDecimal(bd));
2732+
2733+
Real *vp;
2734+
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2735+
ToValue(vp); /* ToValue performs exception check */
2736+
2737+
return bd;
2738+
}
2739+
2740+
static VALUE
2741+
rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2742+
{
2743+
Real *vp = GetVpValue(val, 1);
2744+
return check_exception(vp->obj);
2745+
}
27372746

2738-
argc = rb_scan_args(argc, argv, "11:", &iniValue, &nFig, &opts);
2739-
exc = opts_exception_p(opts);
2747+
static VALUE
2748+
rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2749+
{
2750+
double d = RFLOAT_VALUE(val);
2751+
if (!isfinite(d)) {
2752+
Real *vp = VpCreateRbObject(1, NULL); /* vp->obj is allocated */
2753+
VpDtoV(vp, d);
2754+
return check_exception(vp->obj);
2755+
}
27402756

2741-
if (argc == 1) {
2742-
mf = 0;
2757+
if (digs == SIZE_MAX) {
2758+
if (!raise_exception)
2759+
return Qnil;
2760+
rb_raise(rb_eArgError,
2761+
"can't omit precision for a %"PRIsVALUE".",
2762+
CLASS_OF(val));
27432763
}
2744-
else {
2745-
/* expand GetPrecisionInt for exception suppression */
2746-
ssize_t n = NUM2INT(nFig);
2747-
if (n < 0) {
2748-
if (!exc) {
2749-
return NULL;
2750-
}
2751-
rb_raise(rb_eArgError, "negative precision");
2752-
}
2753-
mf = (size_t)n;
2764+
else if (digs > DBLE_FIG) {
2765+
if (!raise_exception)
2766+
return Qnil;
2767+
rb_raise(rb_eArgError, "precision too large.");
27542768
}
27552769

2756-
switch (iniValue) {
2770+
Real *vp = GetVpValueWithPrec(val, digs, 1);
2771+
return check_exception(vp->obj);
2772+
}
2773+
2774+
static VALUE
2775+
rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2776+
{
2777+
if (digs == SIZE_MAX) {
2778+
if (!raise_exception)
2779+
return Qnil;
2780+
rb_raise(rb_eArgError,
2781+
"can't omit precision for a %"PRIsVALUE".",
2782+
CLASS_OF(val));
2783+
}
2784+
Real *vp = GetVpValueWithPrec(val, digs, 1);
2785+
return check_exception(vp->obj);
2786+
}
2787+
2788+
static VALUE
2789+
rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2790+
{
2791+
if (digs == SIZE_MAX)
2792+
digs = 0;
2793+
2794+
const char *c_str = StringValueCStr(val);
2795+
Real *vp = VpAlloc(digs, c_str, 1, raise_exception);
2796+
if (!vp)
2797+
return Qnil;
2798+
vp->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, vp);
2799+
RB_OBJ_FREEZE(vp->obj);
2800+
return check_exception(vp->obj);
2801+
}
2802+
2803+
static VALUE
2804+
rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2805+
{
2806+
switch (val) {
27572807
case Qnil:
27582808
case Qtrue:
27592809
case Qfalse:
2760-
if (!exc) return NULL;
2810+
if (!raise_exception)
2811+
return Qnil;
27612812
rb_raise(rb_eTypeError,
2762-
"can't convert %"PRIsVALUE" into BigDecimal", iniValue);
2813+
"can't convert %"PRIsVALUE" into BigDecimal", val);
27632814

27642815
default:
27652816
break;
27662817
}
27672818

2768-
retry:
2769-
switch (TYPE(iniValue)) {
2770-
case T_DATA:
2771-
if (is_kind_of_BigDecimal(iniValue)) {
2772-
return DATA_PTR(iniValue);
2773-
}
2774-
break;
2775-
2776-
case T_FIXNUM:
2777-
/* fall through */
2778-
case T_BIGNUM:
2779-
return GetVpValue(iniValue, 1);
2780-
2781-
case T_FLOAT:
2782-
d = RFLOAT_VALUE(iniValue);
2783-
if (!isfinite(d)) {
2784-
Real *pv = VpCreateRbObject(1, NULL);
2785-
VpDtoV(pv, d);
2786-
return pv;
2787-
}
2788-
if (mf > DBLE_FIG) {
2789-
if (!exc) {
2790-
return NULL;
2791-
}
2792-
rb_raise(rb_eArgError, "precision too large.");
2793-
}
2794-
/* fall through */
2795-
case T_RATIONAL:
2796-
if (NIL_P(nFig)) {
2797-
if (!exc) {
2798-
return NULL;
2799-
}
2800-
rb_raise(rb_eArgError,
2801-
"can't omit precision for a %"PRIsVALUE".",
2802-
RB_OBJ_CLASSNAME(iniValue));
2803-
}
2804-
return GetVpValueWithPrec(iniValue, mf, 1);
2819+
if (is_kind_of_BigDecimal(val)) {
2820+
if (digs == SIZE_MAX)
2821+
return check_exception(val);
28052822

2806-
case T_COMPLEX:
2807-
{
2808-
VALUE im;
2809-
im = rb_complex_imag(iniValue);
2810-
if (!is_zero(im)) {
2811-
rb_raise(rb_eArgError,
2812-
"Unable to make a BigDecimal from non-zero imaginary number");
2813-
}
2814-
iniValue = rb_complex_real(iniValue);
2815-
goto retry;
2823+
Real *vp;
2824+
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
2825+
vp = VpCopy(NULL, vp);
2826+
vp->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, vp);
2827+
RB_OBJ_FREEZE(vp->obj);
2828+
return check_exception(vp->obj);
2829+
}
2830+
else if (RB_INTEGER_TYPE_P(val)) {
2831+
return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2832+
}
2833+
else if (RB_FLOAT_TYPE_P(val)) {
2834+
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
2835+
}
2836+
else if (RB_TYPE_P(val, T_RATIONAL)) {
2837+
return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
2838+
}
2839+
else if (RB_TYPE_P(val, T_COMPLEX)) {
2840+
VALUE im = rb_complex_imag(val);
2841+
if (!is_zero(im)) {
2842+
/* TODO: handle raise_exception */
2843+
rb_raise(rb_eArgError,
2844+
"Unable to make a BigDecimal from non-zero imaginary number");
28162845
}
2817-
2818-
case T_STRING:
2819-
/* fall through */
2820-
default:
2821-
break;
2846+
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
28222847
}
2823-
/* TODO: support to_d */
2824-
if (!exc) {
2825-
iniValue = rb_check_convert_type(iniValue, T_STRING, "String", "to_str");
2826-
if (NIL_P(iniValue)) return NULL;
2848+
else if (RB_TYPE_P(val, T_STRING)) {
2849+
return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
28272850
}
2828-
StringValueCStr(iniValue);
2829-
return VpAlloc(mf, RSTRING_PTR(iniValue), 1, exc);
2851+
/* TODO: chheck to_d */
2852+
/* TODO: chheck to_int */
2853+
if (!raise_exception) {
2854+
VALUE str = rb_check_convert_type(val, T_STRING, "String", "to_str");
2855+
if (NIL_P(str))
2856+
return Qnil;
2857+
val = str;
2858+
}
2859+
return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
28302860
}
28312861

28322862
/* call-seq:
@@ -2868,19 +2898,31 @@ VpNewVarArg(int argc, VALUE *argv)
28682898
static VALUE
28692899
f_BigDecimal(int argc, VALUE *argv, VALUE self)
28702900
{
2871-
ENTER(1);
2872-
Real *pv;
2873-
2874-
if (argc > 0 && CLASS_OF(argv[0]) == rb_cBigDecimal) {
2875-
if (argc == 1 || (argc == 2 && RB_TYPE_P(argv[1], T_HASH))) return argv[0];
2901+
VALUE val, digs_v, opts = Qnil;
2902+
argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts);
2903+
int exception = opts_exception_p(opts);
2904+
2905+
size_t digs = SIZE_MAX; /* this means digs is omitted */
2906+
if (argc > 1) {
2907+
digs_v = rb_to_int(digs_v);
2908+
if (FIXNUM_P(digs_v)) {
2909+
long n = FIX2LONG(digs_v);
2910+
if (n < 0)
2911+
goto negative_digs;
2912+
digs = (size_t)n;
2913+
}
2914+
else {
2915+
if (RBIGNUM_NEGATIVE_P(digs_v)) {
2916+
negative_digs:
2917+
if (!exception)
2918+
return Qnil;
2919+
rb_raise(rb_eArgError, "negative precision");
2920+
}
2921+
digs = NUM2SIZET(digs_v);
2922+
}
28762923
}
2877-
pv = VpNewVarArg(argc, argv);
2878-
if (pv == NULL) return Qnil;
2879-
SAVE(pv);
2880-
if (ToValue(pv)) pv = VpCopy(NULL, pv);
2881-
pv->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv);
2882-
RB_OBJ_FREEZE(pv->obj);
2883-
return pv->obj;
2924+
2925+
return rb_convert_to_BigDecimal(val, digs, exception);
28842926
}
28852927

28862928
static VALUE

0 commit comments

Comments
 (0)