bigdecimal 3.0.2 → 3.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,62 +10,74 @@
10
10
  #define RUBY_BIG_DECIMAL_H 1
11
11
 
12
12
  #define RUBY_NO_OLD_COMPATIBILITY
13
-
14
13
  #include "ruby/ruby.h"
15
- #include <float.h>
14
+ #include "missing.h"
16
15
 
17
- #ifndef RB_UNUSED_VAR
18
- # ifdef __GNUC__
19
- # define RB_UNUSED_VAR(x) x __attribute__ ((unused))
20
- # else
21
- # define RB_UNUSED_VAR(x) x
22
- # endif
16
+ #ifdef HAVE_FLOAT_H
17
+ # include <float.h>
23
18
  #endif
24
19
 
25
- #ifndef UNREACHABLE
26
- # define UNREACHABLE /* unreachable */
27
- #endif
28
-
29
- #undef BDIGIT
30
- #undef SIZEOF_BDIGITS
31
- #undef BDIGIT_DBL
32
- #undef BDIGIT_DBL_SIGNED
33
- #undef PRI_BDIGIT_PREFIX
34
- #undef PRI_BDIGIT_DBL_PREFIX
35
-
36
20
  #ifdef HAVE_INT64_T
37
- # define BDIGIT uint32_t
38
- # define BDIGIT_DBL uint64_t
39
- # define BDIGIT_DBL_SIGNED int64_t
40
- # define SIZEOF_BDIGITS 4
41
- # define PRI_BDIGIT_PREFIX ""
21
+ # define DECDIG uint32_t
22
+ # define DECDIG_DBL uint64_t
23
+ # define DECDIG_DBL_SIGNED int64_t
24
+ # define SIZEOF_DECDIG 4
25
+ # define PRI_DECDIG_PREFIX ""
42
26
  # ifdef PRI_LL_PREFIX
43
- # define PRI_BDIGIT_DBL_PREFIX PRI_LL_PREFIX
27
+ # define PRI_DECDIG_DBL_PREFIX PRI_LL_PREFIX
44
28
  # else
45
- # define PRI_BDIGIT_DBL_PREFIX "l"
29
+ # define PRI_DECDIG_DBL_PREFIX "l"
46
30
  # endif
47
31
  #else
48
- # define BDIGIT uint16_t
49
- # define BDIGIT_DBL uint32_t
50
- # define BDIGIT_DBL_SIGNED int32_t
51
- # define SIZEOF_BDIGITS 2
52
- # define PRI_BDIGIT_PREFIX "h"
53
- # define PRI_BDIGIT_DBL_PREFIX ""
32
+ # define DECDIG uint16_t
33
+ # define DECDIG_DBL uint32_t
34
+ # define DECDIG_DBL_SIGNED int32_t
35
+ # define SIZEOF_DECDIG 2
36
+ # define PRI_DECDIG_PREFIX "h"
37
+ # define PRI_DECDIG_DBL_PREFIX ""
54
38
  #endif
55
39
 
56
- #define PRIdBDIGIT PRI_BDIGIT_PREFIX"d"
57
- #define PRIiBDIGIT PRI_BDIGIT_PREFIX"i"
58
- #define PRIoBDIGIT PRI_BDIGIT_PREFIX"o"
59
- #define PRIuBDIGIT PRI_BDIGIT_PREFIX"u"
60
- #define PRIxBDIGIT PRI_BDIGIT_PREFIX"x"
61
- #define PRIXBDIGIT PRI_BDIGIT_PREFIX"X"
40
+ #define PRIdDECDIG PRI_DECDIG_PREFIX"d"
41
+ #define PRIiDECDIG PRI_DECDIG_PREFIX"i"
42
+ #define PRIoDECDIG PRI_DECDIG_PREFIX"o"
43
+ #define PRIuDECDIG PRI_DECDIG_PREFIX"u"
44
+ #define PRIxDECDIG PRI_DECDIG_PREFIX"x"
45
+ #define PRIXDECDIG PRI_DECDIG_PREFIX"X"
46
+
47
+ #define PRIdDECDIG_DBL PRI_DECDIG_DBL_PREFIX"d"
48
+ #define PRIiDECDIG_DBL PRI_DECDIG_DBL_PREFIX"i"
49
+ #define PRIoDECDIG_DBL PRI_DECDIG_DBL_PREFIX"o"
50
+ #define PRIuDECDIG_DBL PRI_DECDIG_DBL_PREFIX"u"
51
+ #define PRIxDECDIG_DBL PRI_DECDIG_DBL_PREFIX"x"
52
+ #define PRIXDECDIG_DBL PRI_DECDIG_DBL_PREFIX"X"
53
+
54
+ #if SIZEOF_DECDIG == 4
55
+ # define BIGDECIMAL_BASE ((DECDIG)1000000000U)
56
+ # define BIGDECIMAL_COMPONENT_FIGURES 9
57
+ /*
58
+ * The number of components required for a 64-bit integer.
59
+ *
60
+ * INT64_MAX: 9_223372036_854775807
61
+ * UINT64_MAX: 18_446744073_709551615
62
+ */
63
+ # define BIGDECIMAL_INT64_MAX_LENGTH 3
62
64
 
63
- #define PRIdBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"d"
64
- #define PRIiBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"i"
65
- #define PRIoBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"o"
66
- #define PRIuBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"u"
67
- #define PRIxBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"x"
68
- #define PRIXBDIGIT_DBL PRI_BDIGIT_DBL_PREFIX"X"
65
+ #elif SIZEOF_DECDIG == 2
66
+ # define BIGDECIMAL_BASE ((DECDIG)10000U)
67
+ # define BIGDECIMAL_COMPONENT_FIGURES 4
68
+ /*
69
+ * The number of components required for a 64-bit integer.
70
+ *
71
+ * INT64_MAX: 922_3372_0368_5477_5807
72
+ * UINT64_MAX: 1844_6744_0737_0955_1615
73
+ */
74
+ # define BIGDECIMAL_INT64_MAX_LENGTH 5
75
+
76
+ #else
77
+ # error Unknown size of DECDIG
78
+ #endif
79
+
80
+ #define BIGDECIMAL_DOUBLE_FIGURES (1+DBL_DIG)
69
81
 
70
82
  #if defined(__cplusplus)
71
83
  extern "C" {
@@ -74,115 +86,8 @@ extern "C" {
74
86
  #endif
75
87
  #endif
76
88
 
77
- #ifndef HAVE_LABS
78
- static inline long
79
- labs(long const x)
80
- {
81
- if (x < 0) return -x;
82
- return x;
83
- }
84
- #endif
85
-
86
- #ifndef HAVE_LLABS
87
- static inline LONG_LONG
88
- llabs(LONG_LONG const x)
89
- {
90
- if (x < 0) return -x;
91
- return x;
92
- }
93
- #endif
94
-
95
- #ifndef HAVE_FINITE
96
- static int
97
- finite(double)
98
- {
99
- return !isnan(n) && !isinf(n);
100
- }
101
- #endif
102
-
103
- #ifndef isfinite
104
- # ifndef HAVE_ISFINITE
105
- # define HAVE_ISFINITE 1
106
- # define isfinite(x) finite(x)
107
- # endif
108
- #endif
109
-
110
- #ifndef FIX_CONST_VALUE_PTR
111
- # if defined(__fcc__) || defined(__fcc_version) || \
112
- defined(__FCC__) || defined(__FCC_VERSION)
113
- /* workaround for old version of Fujitsu C Compiler (fcc) */
114
- # define FIX_CONST_VALUE_PTR(x) ((const VALUE *)(x))
115
- # else
116
- # define FIX_CONST_VALUE_PTR(x) (x)
117
- # endif
118
- #endif
119
-
120
- #ifndef HAVE_RB_ARRAY_CONST_PTR
121
- static inline const VALUE *
122
- rb_array_const_ptr(VALUE a)
123
- {
124
- return FIX_CONST_VALUE_PTR((RBASIC(a)->flags & RARRAY_EMBED_FLAG) ?
125
- RARRAY(a)->as.ary : RARRAY(a)->as.heap.ptr);
126
- }
127
- #endif
128
-
129
- #ifndef RARRAY_CONST_PTR
130
- # define RARRAY_CONST_PTR(a) rb_array_const_ptr(a)
131
- #endif
132
-
133
- #ifndef RARRAY_AREF
134
- # define RARRAY_AREF(a, i) (RARRAY_CONST_PTR(a)[i])
135
- #endif
136
-
137
- #ifndef HAVE_RB_SYM2STR
138
- static inline VALUE
139
- rb_sym2str(VALUE sym)
140
- {
141
- return rb_id2str(SYM2ID(sym));
142
- }
143
- #endif
144
-
145
- #ifndef ST2FIX
146
- # undef RB_ST2FIX
147
- # define RB_ST2FIX(h) LONG2FIX((long)(h))
148
- # define ST2FIX(h) RB_ST2FIX(h)
149
- #endif
150
-
151
- #ifdef vabs
152
- # undef vabs
153
- #endif
154
- #if SIZEOF_VALUE <= SIZEOF_INT
155
- # define vabs abs
156
- #elif SIZEOF_VALUE <= SIZEOF_LONG
157
- # define vabs labs
158
- #elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
159
- # define vabs llabs
160
- #endif
161
-
162
- #if !defined(HAVE_RB_CATEGORY_WARN) || !defined(HAVE_CONST_RB_WARN_CATEGORY_DEPRECATED)
163
- # define rb_category_warn(category, ...) rb_warn(__VA_ARGS__)
164
- #endif
165
-
166
89
  extern VALUE rb_cBigDecimal;
167
90
 
168
- #if 0 || SIZEOF_BDIGITS >= 16
169
- # define RMPD_COMPONENT_FIGURES 38
170
- # define RMPD_BASE ((BDIGIT)100000000000000000000000000000000000000U)
171
- #elif SIZEOF_BDIGITS >= 8
172
- # define RMPD_COMPONENT_FIGURES 19
173
- # define RMPD_BASE ((BDIGIT)10000000000000000000U)
174
- #elif SIZEOF_BDIGITS >= 4
175
- # define RMPD_COMPONENT_FIGURES 9
176
- # define RMPD_BASE ((BDIGIT)1000000000U)
177
- #elif SIZEOF_BDIGITS >= 2
178
- # define RMPD_COMPONENT_FIGURES 4
179
- # define RMPD_BASE ((BDIGIT)10000U)
180
- #else
181
- # define RMPD_COMPONENT_FIGURES 2
182
- # define RMPD_BASE ((BDIGIT)100U)
183
- #endif
184
-
185
-
186
91
  /*
187
92
  * NaN & Infinity
188
93
  */
@@ -197,7 +102,7 @@ extern VALUE rb_cBigDecimal;
197
102
  */
198
103
  #define VP_EXPORT static
199
104
 
200
- /* Exception codes */
105
+ /* Exception mode */
201
106
  #define VP_EXCEPTION_ALL ((unsigned short)0x00FF)
202
107
  #define VP_EXCEPTION_INFINITY ((unsigned short)0x0001)
203
108
  #define VP_EXCEPTION_NaN ((unsigned short)0x0002)
@@ -207,22 +112,39 @@ extern VALUE rb_cBigDecimal;
207
112
 
208
113
  /* Following 2 exceptions can't controlled by user */
209
114
  #define VP_EXCEPTION_OP ((unsigned short)0x0020)
210
- #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)
211
115
 
212
- #define RMPD_EXCEPTION_MODE_DEFAULT 0U
116
+ #define BIGDECIMAL_EXCEPTION_MODE_DEFAULT 0U
213
117
 
214
- /* Computation mode */
118
+ /* This is used in BigDecimal#mode */
215
119
  #define VP_ROUND_MODE ((unsigned short)0x0100)
216
- #define VP_ROUND_UP 1
217
- #define VP_ROUND_DOWN 2
218
- #define VP_ROUND_HALF_UP 3
219
- #define VP_ROUND_HALF_DOWN 4
220
- #define VP_ROUND_CEIL 5
221
- #define VP_ROUND_FLOOR 6
222
- #define VP_ROUND_HALF_EVEN 7
223
-
224
- #define RMPD_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP
225
120
 
121
+ /* Rounding mode */
122
+ #define VP_ROUND_UP RBD_ROUND_UP
123
+ #define VP_ROUND_DOWN RBD_ROUND_DOWN
124
+ #define VP_ROUND_HALF_UP RBD_ROUND_HALF_UP
125
+ #define VP_ROUND_HALF_DOWN RBD_ROUND_HALF_DOWN
126
+ #define VP_ROUND_CEIL RBD_ROUND_CEIL
127
+ #define VP_ROUND_FLOOR RBD_ROUND_FLOOR
128
+ #define VP_ROUND_HALF_EVEN RBD_ROUND_HALF_EVEN
129
+
130
+ enum rbd_rounding_mode {
131
+ RBD_ROUND_UP = 1,
132
+ RBD_ROUND_DOWN = 2,
133
+ RBD_ROUND_HALF_UP = 3,
134
+ RBD_ROUND_HALF_DOWN = 4,
135
+ RBD_ROUND_CEIL = 5,
136
+ RBD_ROUND_FLOOR = 6,
137
+ RBD_ROUND_HALF_EVEN = 7,
138
+
139
+ RBD_ROUND_DEFAULT = RBD_ROUND_HALF_UP,
140
+ RBD_ROUND_TRUNCATE = RBD_ROUND_DOWN,
141
+ RBD_ROUND_BANKER = RBD_ROUND_HALF_EVEN,
142
+ RBD_ROUND_CEILING = RBD_ROUND_CEIL
143
+ };
144
+
145
+ #define BIGDECIMAL_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP
146
+
147
+ /* Sign flag */
226
148
  #define VP_SIGN_NaN 0 /* NaN */
227
149
  #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
228
150
  #define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
@@ -231,6 +153,7 @@ extern VALUE rb_cBigDecimal;
231
153
  #define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */
232
154
  #define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */
233
155
 
156
+ /* The size of fraction part array */
234
157
  #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
235
158
  #define FLEXIBLE_ARRAY_SIZE /* */
236
159
  #elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
@@ -263,7 +186,7 @@ typedef struct {
263
186
  * -3 : Negative infinite number
264
187
  */
265
188
  short flag; /* Not used in vp_routines,space for user. */
266
- BDIGIT frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */
189
+ DECDIG frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */
267
190
  } Real;
268
191
 
269
192
  /*
@@ -272,21 +195,13 @@ typedef struct {
272
195
  * ------------------
273
196
  */
274
197
 
275
- VP_EXPORT Real *
276
- VpNewRbClass(size_t mx, char const *str, VALUE klass);
277
-
278
- VP_EXPORT Real *VpCreateRbObject(size_t mx,const char *str);
198
+ VP_EXPORT Real *VpNewRbClass(size_t mx, char const *str, VALUE klass, bool strict_p, bool raise_exception);
279
199
 
280
- static inline BDIGIT
281
- rmpd_base_value(void) { return RMPD_BASE; }
282
- static inline size_t
283
- rmpd_component_figures(void) { return RMPD_COMPONENT_FIGURES; }
284
- static inline size_t
285
- rmpd_double_figures(void) { return 1+DBL_DIG; }
200
+ VP_EXPORT Real *VpCreateRbObject(size_t mx, const char *str, bool raise_exception);
286
201
 
287
- #define VpBaseFig() rmpd_component_figures()
288
- #define VpDblFig() rmpd_double_figures()
289
- #define VpBaseVal() rmpd_base_value()
202
+ #define VpBaseFig() BIGDECIMAL_COMPONENT_FIGURES
203
+ #define VpDblFig() BIGDECIMAL_DOUBLE_FIGURES
204
+ #define VpBaseVal() BIGDECIMAL_BASE
290
205
 
291
206
  /* Zero,Inf,NaN (isinf(),isnan() used to check) */
292
207
  VP_EXPORT double VpGetDoubleNaN(void);
@@ -308,10 +223,7 @@ VP_EXPORT int VpException(unsigned short f,const char *str,int always);
308
223
  VP_EXPORT int VpIsNegDoubleZero(double v);
309
224
  #endif
310
225
  VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
311
- VP_EXPORT size_t VpInit(BDIGIT BaseVal);
312
- VP_EXPORT void *VpMemAlloc(size_t mb);
313
- VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb);
314
- VP_EXPORT void VpFree(Real *pv);
226
+ VP_EXPORT size_t VpInit(DECDIG BaseVal);
315
227
  VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p, int exc);
316
228
  VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
317
229
  VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
@@ -319,10 +231,10 @@ VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
319
231
  VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
320
232
  VP_EXPORT int VpComp(Real *a,Real *b);
321
233
  VP_EXPORT ssize_t VpExponent10(Real *a);
322
- VP_EXPORT void VpSzMantissa(Real *a,char *psz);
323
- VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
324
- VP_EXPORT void VpToString(Real *a, char *psz, size_t fFmt, int fPlus);
325
- VP_EXPORT void VpToFString(Real *a, char *psz, size_t fFmt, int fPlus);
234
+ VP_EXPORT void VpSzMantissa(Real *a, char *buf, size_t bufsize);
235
+ VP_EXPORT int VpToSpecialString(Real *a, char *buf, size_t bufsize, int fPlus);
236
+ VP_EXPORT void VpToString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
237
+ VP_EXPORT void VpToFString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
326
238
  VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne);
327
239
  VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
328
240
  VP_EXPORT void VpDtoV(Real *m,double d);
@@ -334,7 +246,8 @@ VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
334
246
  VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
335
247
  VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
336
248
  VP_EXPORT void VpFrac(Real *y, Real *x);
337
- VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n);
249
+ VP_EXPORT int VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n);
250
+ #define VpPower VpPowerByInt
338
251
 
339
252
  /* VP constants */
340
253
  VP_EXPORT Real *VpOne(void);
@@ -0,0 +1,141 @@
1
+ #ifndef BIGDECIMAL_BITS_H
2
+ #define BIGDECIMAL_BITS_H
3
+
4
+ #include "feature.h"
5
+ #include "static_assert.h"
6
+
7
+ #if defined(__x86_64__) && defined(HAVE_X86INTRIN_H)
8
+ # include <x86intrin.h> /* for _lzcnt_u64, etc. */
9
+ #elif defined(_MSC_VER) && defined(HAVE_INTRIN_H)
10
+ # include <intrin.h> /* for the following intrinsics */
11
+ #endif
12
+
13
+ #if defined(_MSC_VER) && defined(__AVX2__)
14
+ # pragma intrinsic(__lzcnt)
15
+ # pragma intrinsic(__lzcnt64)
16
+ #endif
17
+
18
+ #define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
19
+ #define roomof(x, y) (((x) + (y) - 1) / (y))
20
+ #define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
21
+
22
+ #define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
23
+ (a) == 0 ? 0 : \
24
+ (a) == -1 ? (b) < -(max) : \
25
+ (a) > 0 ? \
26
+ ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
27
+ ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
28
+
29
+ #ifdef HAVE_UINT128_T
30
+ # define bit_length(x) \
31
+ (unsigned int) \
32
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
33
+ sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
34
+ 128 - nlz_int128((uint128_t)(x)))
35
+ #else
36
+ # define bit_length(x) \
37
+ (unsigned int) \
38
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
39
+ 64 - nlz_int64((uint64_t)(x)))
40
+ #endif
41
+
42
+ static inline unsigned nlz_int32(uint32_t x);
43
+ static inline unsigned nlz_int64(uint64_t x);
44
+ #ifdef HAVE_UINT128_T
45
+ static inline unsigned nlz_int128(uint128_t x);
46
+ #endif
47
+
48
+ static inline unsigned int
49
+ nlz_int32(uint32_t x)
50
+ {
51
+ #if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT)
52
+ /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
53
+ * AMD CPUs have had this instruction for decades (since K10) but for
54
+ * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
55
+ * safety. */
56
+ return (unsigned int)__lzcnt(x);
57
+
58
+ #elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U32)
59
+ return (unsigned int)_lzcnt_u32(x);
60
+
61
+ #elif defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE)
62
+ unsigned long r;
63
+ return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
64
+
65
+ #elif __has_builtin(__builtin_clz)
66
+ STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
67
+ return x ? (unsigned int)__builtin_clz(x) : 32;
68
+
69
+ #else
70
+ uint32_t y;
71
+ unsigned n = 32;
72
+ y = x >> 16; if (y) {n -= 16; x = y;}
73
+ y = x >> 8; if (y) {n -= 8; x = y;}
74
+ y = x >> 4; if (y) {n -= 4; x = y;}
75
+ y = x >> 2; if (y) {n -= 2; x = y;}
76
+ y = x >> 1; if (y) {return n - 2;}
77
+ return (unsigned int)(n - x);
78
+ #endif
79
+ }
80
+
81
+ static inline unsigned int
82
+ nlz_int64(uint64_t x)
83
+ {
84
+ #if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT64)
85
+ return (unsigned int)__lzcnt64(x);
86
+
87
+ #elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U64)
88
+ return (unsigned int)_lzcnt_u64(x);
89
+
90
+ #elif defined(_WIN64) && defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE64)
91
+ unsigned long r;
92
+ return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
93
+
94
+ #elif __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) && !(defined(__sun) && defined(__sparc))
95
+ if (x == 0) {
96
+ return 64;
97
+ }
98
+ else if (sizeof(long) * CHAR_BIT == 64) {
99
+ return (unsigned int)__builtin_clzl((unsigned long)x);
100
+ }
101
+ else if (sizeof(long long) * CHAR_BIT == 64) {
102
+ return (unsigned int)__builtin_clzll((unsigned long long)x);
103
+ }
104
+ else {
105
+ /* :FIXME: Is there a way to make this branch a compile-time error? */
106
+ __builtin_unreachable();
107
+ }
108
+
109
+ #else
110
+ uint64_t y;
111
+ unsigned int n = 64;
112
+ y = x >> 32; if (y) {n -= 32; x = y;}
113
+ y = x >> 16; if (y) {n -= 16; x = y;}
114
+ y = x >> 8; if (y) {n -= 8; x = y;}
115
+ y = x >> 4; if (y) {n -= 4; x = y;}
116
+ y = x >> 2; if (y) {n -= 2; x = y;}
117
+ y = x >> 1; if (y) {return n - 2;}
118
+ return (unsigned int)(n - x);
119
+
120
+ #endif
121
+ }
122
+
123
+ #ifdef HAVE_UINT128_T
124
+ static inline unsigned int
125
+ nlz_int128(uint128_t x)
126
+ {
127
+ uint64_t y = (uint64_t)(x >> 64);
128
+
129
+ if (x == 0) {
130
+ return 128;
131
+ }
132
+ else if (y == 0) {
133
+ return (unsigned int)nlz_int64(x) + 64;
134
+ }
135
+ else {
136
+ return (unsigned int)nlz_int64(y);
137
+ }
138
+ }
139
+ #endif
140
+
141
+ #endif /* BIGDECIMAL_BITS_H */
@@ -1,46 +1,52 @@
1
1
  # frozen_string_literal: false
2
2
  require 'mkmf'
3
3
 
4
- def check_bigdecimal_version(gemspec_path)
5
- message "checking RUBY_BIGDECIMAL_VERSION... "
4
+ def have_builtin_func(name, check_expr, opt = "", &b)
5
+ checking_for checking_message(name.funcall_style, nil, opt) do
6
+ if try_compile(<<SRC, opt, &b)
7
+ int foo;
8
+ int main() { #{check_expr}; return 0; }
9
+ SRC
10
+ $defs.push(format("-DHAVE_BUILTIN_%s", name.tr_cpp))
11
+ true
12
+ else
13
+ false
14
+ end
15
+ end
16
+ end
6
17
 
7
- bigdecimal_version =
8
- IO.readlines(gemspec_path)
9
- .grep(/\Abigdecimal_version\s+=\s+/)[0][/\'([^\']+)\'/, 1]
18
+ have_builtin_func("__builtin_clz", "__builtin_clz(0)")
19
+ have_builtin_func("__builtin_clzl", "__builtin_clzl(0)")
20
+ have_builtin_func("__builtin_clzll", "__builtin_clzll(0)")
10
21
 
11
- version_components = bigdecimal_version.split('.')
12
- bigdecimal_version = version_components[0, 3].join('.')
13
- bigdecimal_version << "-#{version_components[3]}" if version_components[3]
14
- $defs << %Q[-DRUBY_BIGDECIMAL_VERSION=\\"#{bigdecimal_version}\\"]
22
+ have_header("float.h")
23
+ have_header("math.h")
24
+ have_header("stdbool.h")
25
+ have_header("stdlib.h")
15
26
 
16
- message "#{bigdecimal_version}\n"
17
- end
27
+ have_header("x86intrin.h")
28
+ have_func("_lzcnt_u32", "x86intrin.h")
29
+ have_func("_lzcnt_u64", "x86intrin.h")
18
30
 
19
- gemspec_name = gemspec_path = nil
20
- unless ['', '../../'].any? {|dir|
21
- gemspec_name = "#{dir}bigdecimal.gemspec"
22
- gemspec_path = File.expand_path("../#{gemspec_name}", __FILE__)
23
- File.file?(gemspec_path)
24
- }
25
- $stderr.puts "Unable to find bigdecimal.gemspec"
26
- abort
27
- end
28
-
29
- check_bigdecimal_version(gemspec_path)
31
+ have_header("intrin.h")
32
+ have_func("__lzcnt", "intrin.h")
33
+ have_func("__lzcnt64", "intrin.h")
34
+ have_func("_BitScanReverse", "intrin.h")
35
+ have_func("_BitScanReverse64", "intrin.h")
30
36
 
31
37
  have_func("labs", "stdlib.h")
32
38
  have_func("llabs", "stdlib.h")
33
39
  have_func("finite", "math.h")
34
40
  have_func("isfinite", "math.h")
35
41
 
36
- have_type("struct RRational", "ruby.h")
42
+ have_header("ruby/atomic.h")
43
+ have_header("ruby/internal/has/builtin.h")
44
+ have_header("ruby/internal/static_assert.h")
45
+
37
46
  have_func("rb_rational_num", "ruby.h")
38
47
  have_func("rb_rational_den", "ruby.h")
39
- have_type("struct RComplex", "ruby.h")
40
48
  have_func("rb_complex_real", "ruby.h")
41
49
  have_func("rb_complex_imag", "ruby.h")
42
- have_func("rb_array_const_ptr", "ruby.h")
43
- have_func("rb_sym2str", "ruby.h")
44
50
  have_func("rb_opts_exception_p", "ruby.h")
45
51
  have_func("rb_category_warn", "ruby.h")
46
52
  have_const("RB_WARN_CATEGORY_DEPRECATED", "ruby.h")
@@ -52,6 +58,5 @@ else
52
58
  end
53
59
 
54
60
  create_makefile('bigdecimal') {|mf|
55
- mf << "GEMSPEC = #{gemspec_name}\n"
56
61
  mf << "BIGDECIMAL_RB = #{bigdecimal_rb}\n"
57
62
  }
@@ -0,0 +1,68 @@
1
+ #ifndef BIGDECIMAL_HAS_FEATURE_H
2
+ #define BIGDECIMAL_HAS_FEATURE_H
3
+
4
+ /* ======== __has_feature ======== */
5
+
6
+ #ifndef __has_feature
7
+ # define __has_feature(_) 0
8
+ #endif
9
+
10
+ /* ======== __has_extension ======== */
11
+
12
+ #ifndef __has_extension
13
+ # define __has_extension __has_feature
14
+ #endif
15
+
16
+ /* ======== __has_builtin ======== */
17
+
18
+ #ifdef HAVE_RUBY_INTERNAL_HAS_BUILTIN_H
19
+ # include <ruby/internal/has/builtin.h>
20
+ #endif
21
+
22
+ #ifdef RBIMPL_HAS_BUILTIN
23
+ # define BIGDECIMAL_HAS_BUILTIN(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__)
24
+
25
+ #else
26
+ # /* The following section is copied from CRuby's builtin.h */
27
+ #
28
+ # ifdef __has_builtin
29
+ # if defined(__INTEL_COMPILER)
30
+ # /* :TODO: Intel C Compiler has __has_builtin (since 19.1 maybe?), and is
31
+ # * reportedly broken. We have to skip them. However the situation can
32
+ # * change. They might improve someday. We need to revisit here later. */
33
+ # elif defined(__GNUC__) && ! __has_builtin(__builtin_alloca)
34
+ # /* FreeBSD's <sys/cdefs.h> defines its own *broken* version of
35
+ # * __has_builtin. Cygwin copied that content to be a victim of the
36
+ # * broken-ness. We don't take them into account. */
37
+ # else
38
+ # define HAVE___HAS_BUILTIN 1
39
+ # endif
40
+ # endif
41
+ #
42
+ # if defined(HAVE___HAS_BUILTIN)
43
+ # define BIGDECIMAL_HAS_BUILTIN(_) __has_builtin(_)
44
+ #
45
+ # elif defined(__GNUC__)
46
+ # define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
47
+ # if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 6))
48
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clz 1
49
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 1
50
+ # else
51
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clz 0
52
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 0
53
+ # endif
54
+ # elif defined(_MSC_VER)
55
+ # define BIGDECIMAL_HAS_BUILTIN(_) 0
56
+ #
57
+ # else
58
+ # define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
59
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clz HAVE_BUILTIN___BUILTIN_CLZ
60
+ # define BIGDECIMAL_HAS_BUILTIN___builtin_clzl HAVE_BUILTIN___BUILTIN_CLZL
61
+ # endif
62
+ #endif /* RBIMPL_HAS_BUILTIN */
63
+
64
+ #ifndef __has_builtin
65
+ # define __has_builtin(...) BIGDECIMAL_HAS_BUILTIN(__VA_ARGS__)
66
+ #endif
67
+
68
+ #endif /* BIGDECIMAL_HAS_FEATURE_H */