commit 935eed72abb82a58c4ffe60c7746e7d0ec1a610c
parent bbd5e8ed9ef5381ed98a3660df03c2c5e0f24b44
Author: Andres Navarro <canavarro82@gmail.com>
Date: Tue, 12 Apr 2011 17:11:02 -0300
Bugfix: Added code to kbigint_plus to check if the result could fit in a fixint.
Diffstat:
2 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/src/kinteger.c b/src/kinteger.c
@@ -14,6 +14,23 @@
#include "kstate.h"
#include "kmem.h"
+/* This tries to convert a bigint to a fixint */
+inline TValue kbigint_try_fixint(klisp_State *K, TValue n)
+{
+ Bigint *b = tv2bigint(n);
+ if (MP_USED(b) != 1)
+ return n;
+
+ int64_t digit = (int64_t) MP_SINGLE(b);
+ if (MP_SIGN(b) == MP_NEG) digit = -digit;
+ if (kfit_int32_t(digit)) {
+ /* n shouln't be reachable but the let the gc do its job */
+ return i2tv((int32_t) digit);
+ } else {
+ return n;
+ }
+}
+
/* for now used only for reading */
/* NOTE: is uint to allow INT32_MIN as positive argument in read */
TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit)
@@ -78,8 +95,8 @@ bool kbigint_has_digits(klisp_State *K, TValue tv_bigint)
return (mp_int_compare_zero(tv2bigint(tv_bigint)) != 0);
}
-/* Mutate the bigint to have the opposite sign, used in read,
- write and abs */
+/* Mutate the bigint to have the opposite sign, used in read
+ and write*/
void kbigint_invert_sign(klisp_State *K, TValue tv_bigint)
{
Bigint *bigint = tv2bigint(tv_bigint);
@@ -128,7 +145,7 @@ TValue kbigint_plus(klisp_State *K, TValue n1, TValue n2)
{
TValue res = kbigint_new(K, false, 0);
UNUSED(mp_int_add(K, tv2bigint(n1), tv2bigint(n2), tv2bigint(res)));
- return res;
+ return kbigint_try_fixint(K, res);
}
bool kbigint_negativep(TValue tv_bigint)
@@ -156,6 +173,7 @@ TValue kbigint_abs(klisp_State *K, TValue tv_bigint)
if (kbigint_negativep(tv_bigint)) {
TValue copy = kbigint_new(K, false, 0);
UNUSED(mp_int_abs(K, tv2bigint(tv_bigint), tv2bigint(copy)));
+ /* NOTE: this can never be a fixint if the parameter was a bigint */
return copy;
} else {
return tv_bigint;
diff --git a/src/kinteger.h b/src/kinteger.h
@@ -22,6 +22,11 @@ TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit);
/* used in write to destructively get the digits */
TValue kbigint_copy(klisp_State *K, TValue src);
+/* Check to see if an int64_t fits in a int32_t */
+inline bool kfit_int32_t(int64_t n) {
+ return (n >= (int64_t) INT32_MIN && n <= (int64_t) INT32_MAX);
+}
+
/* Create a stack allocated bigints from a fixint,
useful for mixed operations, relatively light weight compared
to creating it in the heap and burdening the gc */