summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-10-01 17:35:10 -0700
committerKaz Kylheku <kaz@kylheku.com>2012-10-01 17:35:10 -0700
commit40bae281a56c9e305852905dcbd29125de388b25 (patch)
treee2f1675ca58161fb791e179acf31c744b64deb63
parentbaf80248032cdb8856d9e3217d48e9fd5e9e49c5 (diff)
downloadtxr-40bae281a56c9e305852905dcbd29125de388b25.tar.gz
txr-40bae281a56c9e305852905dcbd29125de388b25.tar.bz2
txr-40bae281a56c9e305852905dcbd29125de388b25.zip
* arith.c (bignum_from_long): New function.
* arith.h (bignum_from_long): Declared. * lib.c (int_str): Streamlined. Only use mp_read_radix in the case when wcstol fails, because now we have bignum_from_long to handle all values of long. Ensure that the bignum is normalized, in case it falls in the fixnum range (does not happen on our usual platforms).
-rw-r--r--ChangeLog11
-rw-r--r--arith.c11
-rw-r--r--arith.h1
-rw-r--r--lib.c17
4 files changed, 34 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 8015cdd2..389134a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-10-01 Kaz Kylheku <kaz@kylheku.com>
+
+ * arith.c (bignum_from_long): New function.
+
+ * arith.h (bignum_from_long): Declared.
+
+ * lib.c (int_str): Streamlined. Only use mp_read_radix in the case when
+ wcstol fails, because now we have bignum_from_long to handle all values
+ of long. Ensure that the bignum is normalized, in case it falls in the
+ fixnum range (does not happen on our usual platforms).
+
2012-09-25 Kaz Kylheku <kaz@kylheku.com>
* eval.c: Allow the test form of a for loop to be omitted,
diff --git a/arith.c b/arith.c
index 8e245e71..b1ae1677 100644
--- a/arith.c
+++ b/arith.c
@@ -68,6 +68,17 @@ val bignum(cnum cn)
return n;
}
+val bignum_from_long(long l)
+{
+#if SIZEOF_LONG <= SIZEOF_PTR
+ return bignum(l);
+#else
+ val n = make_bignum();
+ mp_set_int(mp(n), l);
+ return n;
+#endif
+}
+
#if HAVE_DOUBLE_INTPTR_T
static val bignum_dbl_ipt(double_intptr_t di)
diff --git a/arith.h b/arith.h
index 52aad603..8a97dd87 100644
--- a/arith.h
+++ b/arith.h
@@ -26,6 +26,7 @@
val make_bignum(void);
val bignum(cnum cn);
+val bignum_from_long(long l);
int highest_bit(int_ptr_t n);
val normalize(val bignum);
val in_int_ptr_range(val bignum);
diff --git a/lib.c b/lib.c
index 89a38496..fcbcae15 100644
--- a/lib.c
+++ b/lib.c
@@ -2104,11 +2104,11 @@ val int_str(val str, val base)
/* TODO: detect if we have wcstoll */
long value = wcstol(wcs, &ptr, b ? b : 10);
+
if (value == 0 && ptr == wcs)
return nil;
- if (((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE) ||
- (value < NUM_MIN || value > NUM_MAX))
- {
+
+ if ((value == LONG_MAX || value == LONG_MIN) && errno == ERANGE) {
val bignum = make_bignum();
unsigned char *ucs = utf8_dup_to_uc(wcs);
mp_err err = mp_read_radix(mp(bignum), ucs, b);
@@ -2118,10 +2118,15 @@ val int_str(val str, val base)
if (err != MP_OKAY)
return nil;
- return bignum;
- }
+ /* If wcstol overflowed, but the range of long is smaller than
+ that of fixnums, that means that the value might not
+ actually be a bignum, and so we must normalize.
+ We do not need this on our usual target platforms, where NUM_MAX is
+ never larger than LONG_MAX. */
+ return (LONG_MAX < NUM_MAX) ? normalize(bignum) : bignum;
+ }
- return num(value);
+ return bignum_from_long(value);
}
val flo_str(val str)