@@ -2725,108 +2725,138 @@ opts_exception_p(VALUE opts)
2725
2725
}
2726
2726
#endif
2727
2727
2728
- static Real *
2729
- VpNewVarArg ( int argc , VALUE * argv )
2728
+ static VALUE
2729
+ check_exception ( VALUE bd )
2730
2730
{
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
+ }
2737
2746
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
+ }
2740
2756
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 ));
2743
2763
}
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." );
2754
2768
}
2755
2769
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 ) {
2757
2807
case Qnil :
2758
2808
case Qtrue :
2759
2809
case Qfalse :
2760
- if (!exc ) return NULL ;
2810
+ if (!raise_exception )
2811
+ return Qnil ;
2761
2812
rb_raise (rb_eTypeError ,
2762
- "can't convert %" PRIsVALUE " into BigDecimal" , iniValue );
2813
+ "can't convert %" PRIsVALUE " into BigDecimal" , val );
2763
2814
2764
2815
default :
2765
2816
break ;
2766
2817
}
2767
2818
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 );
2805
2822
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" );
2816
2845
}
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 );
2822
2847
}
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 );
2827
2850
}
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 );
2830
2860
}
2831
2861
2832
2862
/* call-seq:
@@ -2868,19 +2898,31 @@ VpNewVarArg(int argc, VALUE *argv)
2868
2898
static VALUE
2869
2899
f_BigDecimal (int argc , VALUE * argv , VALUE self )
2870
2900
{
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
+ }
2876
2923
}
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 );
2884
2926
}
2885
2927
2886
2928
static VALUE
0 commit comments