summaryrefslogtreecommitdiff
path: root/src/bignum.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2018-10-03 09:10:01 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2018-10-06 23:31:04 -0700
commit84f39d3389209e566dde9acbdd78f5572f0c6751 (patch)
treead9788f26ffd9e9ceb7a520ed863833a5b60db8b /src/bignum.c
parent0faad0a0025cb4c6cbdba44e5b259690fae27b1a (diff)
downloademacs-84f39d3389209e566dde9acbdd78f5572f0c6751.tar.gz
Export converting mpz to [u]intmax
This refactoring will help improve timestamp handling later (Bug#32902). * src/bignum.c (mpz_set_uintmax): Move to bignum.h, and make inline. (mpz_set_uintmax_slow): Now extern. (mpz_to_intmax, mpz_to_uintmax): New functions, with implementation taken from the old bignum_to_intmax and bignum_to_uintmax. (bignum_to_intmax, bignum_to_uintmax): Use them.
Diffstat (limited to 'src/bignum.c')
-rw-r--r--src/bignum.c91
1 files changed, 50 insertions, 41 deletions
diff --git a/src/bignum.c b/src/bignum.c
index 1e78d981b7d..5d8ab670f24 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -101,18 +101,6 @@ make_bignum (void)
return make_bignum_bits (mpz_sizeinbase (mpz[0], 2));
}
-static void mpz_set_uintmax_slow (mpz_t, uintmax_t);
-
-/* Set RESULT to V. */
-static void
-mpz_set_uintmax (mpz_t result, uintmax_t v)
-{
- if (v <= ULONG_MAX)
- mpz_set_ui (result, v);
- else
- mpz_set_uintmax_slow (result, v);
-}
-
/* Return a Lisp integer equal to N, which must not be in fixnum range. */
Lisp_Object
make_bigint (intmax_t n)
@@ -183,7 +171,7 @@ mpz_set_intmax_slow (mpz_t result, intmax_t v)
mpz_limbs_finish (result, negative ? -n : n);
}
-static void
+void
mpz_set_uintmax_slow (mpz_t result, uintmax_t v)
{
int maxlimbs = (UINTMAX_WIDTH + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
@@ -200,13 +188,13 @@ mpz_set_uintmax_slow (mpz_t result, uintmax_t v)
mpz_limbs_finish (result, n);
}
-/* Return the value of the bignum X if it fits, 0 otherwise.
- A bignum cannot be zero, so 0 indicates failure reliably. */
-intmax_t
-bignum_to_intmax (Lisp_Object x)
+/* If Z fits into *PI, store its value there and return true.
+ Return false otherwise. */
+bool
+mpz_to_intmax (mpz_t const z, intmax_t *pi)
{
- ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2);
- bool negative = mpz_sgn (XBIGNUM (x)->value) < 0;
+ ptrdiff_t bits = mpz_sizeinbase (z, 2);
+ bool negative = mpz_sgn (z) < 0;
if (bits < INTMAX_WIDTH)
{
@@ -215,39 +203,60 @@ bignum_to_intmax (Lisp_Object x)
do
{
- intmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++);
+ intmax_t limb = mpz_getlimbn (z, i++);
v += limb << shift;
shift += GMP_NUMB_BITS;
}
while (shift < bits);
- return negative ? -v : v;
+ *pi = negative ? -v : v;
+ return true;
+ }
+ if (bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative
+ && mpz_scan1 (z, 0) == INTMAX_WIDTH - 1)
+ {
+ *pi = INTMAX_MIN;
+ return true;
}
- return ((bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative
- && mpz_scan1 (XBIGNUM (x)->value, 0) == INTMAX_WIDTH - 1)
- ? INTMAX_MIN : 0);
+ return false;
}
-uintmax_t
-bignum_to_uintmax (Lisp_Object x)
+bool
+mpz_to_uintmax (mpz_t const z, uintmax_t *pi)
{
+ if (mpz_sgn (z) < 0)
+ return false;
+ ptrdiff_t bits = mpz_sizeinbase (z, 2);
+ if (UINTMAX_WIDTH < bits)
+ return false;
+
uintmax_t v = 0;
- if (0 <= mpz_sgn (XBIGNUM (x)->value))
+ int i = 0, shift = 0;
+
+ do
{
- ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2);
- if (bits <= UINTMAX_WIDTH)
- {
- int i = 0, shift = 0;
-
- do
- {
- uintmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++);
- v += limb << shift;
- shift += GMP_NUMB_BITS;
- }
- while (shift < bits);
- }
+ uintmax_t limb = mpz_getlimbn (z, i++);
+ v += limb << shift;
+ shift += GMP_NUMB_BITS;
}
- return v;
+ while (shift < bits);
+
+ *pi = v;
+ return true;
+}
+
+/* Return the value of the bignum X if it fits, 0 otherwise.
+ A bignum cannot be zero, so 0 indicates failure reliably. */
+intmax_t
+bignum_to_intmax (Lisp_Object x)
+{
+ intmax_t i;
+ return mpz_to_intmax (XBIGNUM (x)->value, &i) ? i : 0;
+}
+uintmax_t
+bignum_to_uintmax (Lisp_Object x)
+{
+ uintmax_t i;
+ return mpz_to_uintmax (XBIGNUM (x)->value, &i) ? i : 0;
}
/* Yield an upper bound on the buffer size needed to contain a C