forked from Shopify/mruby
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnumeric.h
More file actions
196 lines (167 loc) · 5.64 KB
/
numeric.h
File metadata and controls
196 lines (167 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/**
** @file mruby/numeric.h - Numeric, Integer, Float, Fixnum class
**
** See Copyright Notice in mruby.h
*/
#ifndef MRUBY_NUMERIC_H
#define MRUBY_NUMERIC_H
#include "common.h"
/**
* Numeric class and it's sub-classes.
*
* Integer, Float and Fixnum
*/
MRB_BEGIN_DECL
#define TYPED_POSFIXABLE(f,t) ((f) <= (t)MRB_INT_MAX)
#define TYPED_NEGFIXABLE(f,t) ((f) >= (t)MRB_INT_MIN)
#define TYPED_FIXABLE(f,t) (TYPED_POSFIXABLE(f,t) && TYPED_NEGFIXABLE(f,t))
#define POSFIXABLE(f) TYPED_POSFIXABLE(f,mrb_int)
#define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int)
#define FIXABLE(f) TYPED_FIXABLE(f,mrb_int)
#ifndef MRB_WITHOUT_FLOAT
#ifdef MRB_INT64
#define FIXABLE_FLOAT(f) ((f)>=-9223372036854775808.0 && (f)<9223372036854775808.0)
#else
#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,mrb_float)
#endif
#endif
#ifndef MRB_WITHOUT_FLOAT
MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val);
#endif
MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base);
/* ArgumentError if format string doesn't match /%(\.[0-9]+)?[aAeEfFgG]/ */
#ifndef MRB_WITHOUT_FLOAT
MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt);
MRB_API int mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float f);
MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x);
MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f);
#endif
MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y);
MRB_API mrb_value mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y);
MRB_API mrb_value mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y);
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
(__has_builtin(__builtin_add_overflow) && \
__has_builtin(__builtin_sub_overflow) && \
__has_builtin(__builtin_mul_overflow))
# define MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#endif
/*
// Clang 3.8 and 3.9 have problem compiling mruby in 32-bit mode, when MRB_INT64 is set
// because of missing __mulodi4 and similar functions in its runtime. We need to use custom
// implementation for them.
*/
#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#if defined(__clang__) && (__clang_major__ == 3) && (__clang_minor__ >= 8) && \
defined(MRB_32BIT) && defined(MRB_INT64)
#undef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#endif
#endif
#ifdef MRB_HAVE_TYPE_GENERIC_CHECKED_ARITHMETIC_BUILTINS
#ifndef MRB_WORD_BOXING
# define WBCHK(x) 0
#else
# define WBCHK(x) !FIXABLE(x)
#endif
static inline mrb_bool
mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum)
{
return __builtin_add_overflow(augend, addend, sum) || WBCHK(*sum);
}
static inline mrb_bool
mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
{
return __builtin_sub_overflow(minuend, subtrahend, difference) || WBCHK(*difference);
}
static inline mrb_bool
mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product)
{
return __builtin_mul_overflow(multiplier, multiplicand, product) || WBCHK(*product);
}
#undef WBCHK
#else
#define MRB_UINT_MAKE2(n) uint ## n ## _t
#define MRB_UINT_MAKE(n) MRB_UINT_MAKE2(n)
#define mrb_uint MRB_UINT_MAKE(MRB_INT_BIT)
#define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1 - MRB_FIXNUM_SHIFT))
static inline mrb_bool
mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum)
{
mrb_uint x = (mrb_uint)augend;
mrb_uint y = (mrb_uint)addend;
mrb_uint z = (mrb_uint)(x + y);
*sum = (mrb_int)z;
return !!(((x ^ z) & (y ^ z)) & MRB_INT_OVERFLOW_MASK);
}
static inline mrb_bool
mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference)
{
mrb_uint x = (mrb_uint)minuend;
mrb_uint y = (mrb_uint)subtrahend;
mrb_uint z = (mrb_uint)(x - y);
*difference = (mrb_int)z;
return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK);
}
static inline mrb_bool
mrb_int_mul_overflow(mrb_int multiplier, mrb_int multiplicand, mrb_int *product)
{
#if MRB_INT_BIT == 32
int64_t n = (int64_t)multiplier * multiplicand;
*product = (mrb_int)n;
return !FIXABLE(n);
#else
if (multiplier > 0) {
if (multiplicand > 0) {
if (multiplier > MRB_INT_MAX / multiplicand) return TRUE;
}
else {
if (multiplicand < MRB_INT_MAX / multiplier) return TRUE;
}
}
else {
if (multiplicand > 0) {
if (multiplier < MRB_INT_MAX / multiplicand) return TRUE;
}
else {
if (multiplier != 0 && multiplicand < MRB_INT_MAX / multiplier) return TRUE;
}
}
*product = multiplier * multiplicand;
return FALSE;
#endif
}
#undef MRB_INT_OVERFLOW_MASK
#undef mrb_uint
#undef MRB_UINT_MAKE
#undef MRB_UINT_MAKE2
#endif
#ifndef MRB_WITHOUT_FLOAT
# include <stdint.h>
# include <float.h>
# define MRB_FLT_RADIX FLT_RADIX
# ifdef MRB_USE_FLOAT
# define MRB_FLT_MANT_DIG FLT_MANT_DIG
# define MRB_FLT_EPSILON FLT_EPSILON
# define MRB_FLT_DIG FLT_DIG
# define MRB_FLT_MIN_EXP FLT_MIN_EXP
# define MRB_FLT_MIN FLT_MIN
# define MRB_FLT_MIN_10_EXP FLT_MIN_10_EXP
# define MRB_FLT_MAX_EXP FLT_MAX_EXP
# define MRB_FLT_MAX FLT_MAX
# define MRB_FLT_MAX_10_EXP FLT_MAX_10_EXP
# else /* not MRB_USE_FLOAT */
# define MRB_FLT_MANT_DIG DBL_MANT_DIG
# define MRB_FLT_EPSILON DBL_EPSILON
# define MRB_FLT_DIG DBL_DIG
# define MRB_FLT_MIN_EXP DBL_MIN_EXP
# define MRB_FLT_MIN DBL_MIN
# define MRB_FLT_MIN_10_EXP DBL_MIN_10_EXP
# define MRB_FLT_MAX_EXP DBL_MAX_EXP
# define MRB_FLT_MAX DBL_MAX
# define MRB_FLT_MAX_10_EXP DBL_MAX_10_EXP
# endif /* MRB_USE_FLOAT */
#endif /* MRB_WITHOUT_FLOAT */
MRB_END_DECL
#endif /* MRUBY_NUMERIC_H */