[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] master 84f39d3 3/5: Export converting mpz to [u]intmax
From: |
Paul Eggert |
Subject: |
[Emacs-diffs] master 84f39d3 3/5: Export converting mpz to [u]intmax |
Date: |
Sun, 7 Oct 2018 02:31:13 -0400 (EDT) |
branch: master
commit 84f39d3389209e566dde9acbdd78f5572f0c6751
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>
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.
---
src/bignum.c | 91 +++++++++++++++++++++++++++++++++---------------------------
src/bignum.h | 11 ++++++++
2 files changed, 61 insertions(+), 41 deletions(-)
diff --git a/src/bignum.c b/src/bignum.c
index 1e78d98..5d8ab67 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
diff --git a/src/bignum.h b/src/bignum.h
index e9cd5c0..fd035e6 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -45,7 +45,10 @@ extern mpz_t mpz[4];
extern void init_bignum (void);
extern Lisp_Object make_integer_mpz (void);
+extern bool mpz_to_intmax (mpz_t const, intmax_t *) ARG_NONNULL ((1, 2));
+extern bool mpz_to_uintmax (mpz_t const, uintmax_t *) ARG_NONNULL ((1, 2));
extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1));
+extern void mpz_set_uintmax_slow (mpz_t, uintmax_t) ARG_NONNULL ((1));
extern double mpz_get_d_rounded (mpz_t const);
INLINE_HEADER_BEGIN
@@ -68,6 +71,14 @@ mpz_set_intmax (mpz_t result, intmax_t v)
else
mpz_set_intmax_slow (result, v);
}
+INLINE void ARG_NONNULL ((1))
+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 pointer to an mpz_t that is equal to the Lisp integer I.
If I is a bignum this returns a pointer to I's representation;