diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2012-10-01 17:35:10 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2012-10-01 17:35:10 -0700 |
commit | 40bae281a56c9e305852905dcbd29125de388b25 (patch) | |
tree | e2f1675ca58161fb791e179acf31c744b64deb63 | |
parent | baf80248032cdb8856d9e3217d48e9fd5e9e49c5 (diff) | |
download | txr-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-- | ChangeLog | 11 | ||||
-rw-r--r-- | arith.c | 11 | ||||
-rw-r--r-- | arith.h | 1 | ||||
-rw-r--r-- | lib.c | 17 |
4 files changed, 34 insertions, 6 deletions
@@ -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, @@ -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) @@ -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); @@ -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) |