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.
This commit is contained in:
parent
0faad0a002
commit
84f39d3389
2 changed files with 62 additions and 42 deletions
93
src/bignum.c
93
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;
|
||||
}
|
||||
return ((bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative
|
||||
&& mpz_scan1 (XBIGNUM (x)->value, 0) == INTMAX_WIDTH - 1)
|
||||
? INTMAX_MIN : 0);
|
||||
if (bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative
|
||||
&& mpz_scan1 (z, 0) == INTMAX_WIDTH - 1)
|
||||
{
|
||||
*pi = INTMAX_MIN;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
int i = 0, shift = 0;
|
||||
|
||||
do
|
||||
{
|
||||
uintmax_t limb = mpz_getlimbn (z, i++);
|
||||
v += limb << shift;
|
||||
shift += GMP_NUMB_BITS;
|
||||
}
|
||||
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 v = 0;
|
||||
if (0 <= mpz_sgn (XBIGNUM (x)->value))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
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
|
||||
|
|
11
src/bignum.h
11
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue