emacs-diffs
[Top][All Lists]
Advanced

[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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]