Added spec:commit task to commit changes to spec/ruby sources.
[rbx.git] / shotgun / lib / fixnum.h
blob074e4398d1aae3785fd2448f7dee1fcf77e3de4e
1 #ifndef RBS_FIXNUM_H
2 #define RBS_FIXNUM_H
4 /* Each of these operations intend to implement safe code according to
5 https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+integer+operations+do+not+result+in+an+overflow
6 Thanks defn52 for the link.
7 */
9 static inline OBJECT fixnum_add(STATE, OBJECT a, OBJECT b) {
10 native_int j, k, m;
12 // + will never overflow an int because of the size of a Fixnum
13 j = N2I(a);
14 k = N2I(b);
15 m = j + k;
16 if(m > FIXNUM_MAX || m < FIXNUM_MIN) {
17 return bignum_new(state, m);
18 } else {
19 return APPLY_TAG(m, TAG_FIXNUM);
23 static inline OBJECT fixnum_sub(STATE, OBJECT a, OBJECT b) {
24 OBJECT r;
25 native_int j, k, m;
27 // - will never overflow a signed int because of the size of a Fixnum
28 j = N2I(a);
29 k = N2I(b);
30 m = j - k;
31 r = I2N(m);
32 if(m != N2I(r)) {
33 r = bignum_sub(state, bignum_new(state, j), bignum_new(state, k));
36 return r;
39 static inline OBJECT fixnum_mul(STATE, OBJECT a, OBJECT b) {
40 native_int na = N2I(a);
41 native_int nb = N2I(b);
42 unsigned int overflow = FALSE;
44 /* There is no C type large enough to (always) hold the result of
45 * multiplying two native_ints together
48 if (na > 0) { /* a is positive */
49 if (nb > 0) { /* a and b are positive */
50 if (na > (FIXNUM_MAX / nb)) { overflow = TRUE; }
51 } else { /* a is positive, b is non-positive */
52 if (nb < (FIXNUM_MIN / na)) { overflow = TRUE; }
54 } else { /* a is non-positive */
55 if (nb > 0) { /* a is non-positive, b is positive */
56 if (na < (FIXNUM_MIN / nb)) { overflow = TRUE; }
57 } else { /* a and b are non-positive */
58 if ( (na != 0) && (nb < (FIXNUM_MAX / na))) { overflow = TRUE; }
61 if (overflow) {
62 return bignum_mul(state, bignum_new(state, na), b);
63 } else {
64 return I2N(na * nb);
68 static inline native_int fixnum_div(STATE, OBJECT a, OBJECT b, native_int *mod) {
69 native_int x, y;
70 native_int div;
72 x = N2I(a);
73 y = N2I(b);
75 // adapted from ruby 1.8.x
76 if (y < 0) {
77 if (x < 0)
78 div = -x / -y;
79 else
80 div = - (x / -y);
81 } else {
82 if (x < 0)
83 div = - (-x / y);
84 else
85 div = x / y;
88 *mod = x - div*y;
89 if ((*mod < 0 && y > 0) || (*mod > 0 && y < 0)) {
90 *mod += y;
91 div -= 1;
94 return div;
97 static inline OBJECT fixnum_divmod(STATE, OBJECT a, OBJECT b) {
98 OBJECT ary;
99 native_int div, mod;
101 div = fixnum_div(state, a, b, &mod);
103 ary = array_new(state, 2);
104 array_set(state, ary, 0, I2N(div));
105 array_set(state, ary, 1, I2N(mod));
106 return ary;
109 #endif