diff options
| author | Paul Eggert | 2018-10-03 09:10:01 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-10-06 23:31:04 -0700 |
| commit | 84f39d3389209e566dde9acbdd78f5572f0c6751 (patch) | |
| tree | ad9788f26ffd9e9ceb7a520ed863833a5b60db8b /src | |
| parent | 0faad0a0025cb4c6cbdba44e5b259690fae27b1a (diff) | |
| download | emacs-84f39d3389209e566dde9acbdd78f5572f0c6751.tar.gz emacs-84f39d3389209e566dde9acbdd78f5572f0c6751.zip | |
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')
| -rw-r--r-- | src/bignum.c | 91 | ||||
| -rw-r--r-- | src/bignum.h | 11 |
2 files changed, 61 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) | |||
| 101 | return make_bignum_bits (mpz_sizeinbase (mpz[0], 2)); | 101 | return make_bignum_bits (mpz_sizeinbase (mpz[0], 2)); |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static void mpz_set_uintmax_slow (mpz_t, uintmax_t); | ||
| 105 | |||
| 106 | /* Set RESULT to V. */ | ||
| 107 | static void | ||
| 108 | mpz_set_uintmax (mpz_t result, uintmax_t v) | ||
| 109 | { | ||
| 110 | if (v <= ULONG_MAX) | ||
| 111 | mpz_set_ui (result, v); | ||
| 112 | else | ||
| 113 | mpz_set_uintmax_slow (result, v); | ||
| 114 | } | ||
| 115 | |||
| 116 | /* Return a Lisp integer equal to N, which must not be in fixnum range. */ | 104 | /* Return a Lisp integer equal to N, which must not be in fixnum range. */ |
| 117 | Lisp_Object | 105 | Lisp_Object |
| 118 | make_bigint (intmax_t n) | 106 | make_bigint (intmax_t n) |
| @@ -183,7 +171,7 @@ mpz_set_intmax_slow (mpz_t result, intmax_t v) | |||
| 183 | 171 | ||
| 184 | mpz_limbs_finish (result, negative ? -n : n); | 172 | mpz_limbs_finish (result, negative ? -n : n); |
| 185 | } | 173 | } |
| 186 | static void | 174 | void |
| 187 | mpz_set_uintmax_slow (mpz_t result, uintmax_t v) | 175 | mpz_set_uintmax_slow (mpz_t result, uintmax_t v) |
| 188 | { | 176 | { |
| 189 | int maxlimbs = (UINTMAX_WIDTH + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS; | 177 | 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) | |||
| 200 | mpz_limbs_finish (result, n); | 188 | mpz_limbs_finish (result, n); |
| 201 | } | 189 | } |
| 202 | 190 | ||
| 203 | /* Return the value of the bignum X if it fits, 0 otherwise. | 191 | /* If Z fits into *PI, store its value there and return true. |
| 204 | A bignum cannot be zero, so 0 indicates failure reliably. */ | 192 | Return false otherwise. */ |
| 205 | intmax_t | 193 | bool |
| 206 | bignum_to_intmax (Lisp_Object x) | 194 | mpz_to_intmax (mpz_t const z, intmax_t *pi) |
| 207 | { | 195 | { |
| 208 | ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2); | 196 | ptrdiff_t bits = mpz_sizeinbase (z, 2); |
| 209 | bool negative = mpz_sgn (XBIGNUM (x)->value) < 0; | 197 | bool negative = mpz_sgn (z) < 0; |
| 210 | 198 | ||
| 211 | if (bits < INTMAX_WIDTH) | 199 | if (bits < INTMAX_WIDTH) |
| 212 | { | 200 | { |
| @@ -215,39 +203,60 @@ bignum_to_intmax (Lisp_Object x) | |||
| 215 | 203 | ||
| 216 | do | 204 | do |
| 217 | { | 205 | { |
| 218 | intmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++); | 206 | intmax_t limb = mpz_getlimbn (z, i++); |
| 219 | v += limb << shift; | 207 | v += limb << shift; |
| 220 | shift += GMP_NUMB_BITS; | 208 | shift += GMP_NUMB_BITS; |
| 221 | } | 209 | } |
| 222 | while (shift < bits); | 210 | while (shift < bits); |
| 223 | 211 | ||
| 224 | return negative ? -v : v; | 212 | *pi = negative ? -v : v; |
| 213 | return true; | ||
| 214 | } | ||
| 215 | if (bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative | ||
| 216 | && mpz_scan1 (z, 0) == INTMAX_WIDTH - 1) | ||
| 217 | { | ||
| 218 | *pi = INTMAX_MIN; | ||
| 219 | return true; | ||
| 225 | } | 220 | } |
| 226 | return ((bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative | 221 | return false; |
| 227 | && mpz_scan1 (XBIGNUM (x)->value, 0) == INTMAX_WIDTH - 1) | ||
| 228 | ? INTMAX_MIN : 0); | ||
| 229 | } | 222 | } |
| 230 | uintmax_t | 223 | bool |
| 231 | bignum_to_uintmax (Lisp_Object x) | 224 | mpz_to_uintmax (mpz_t const z, uintmax_t *pi) |
| 232 | { | 225 | { |
| 226 | if (mpz_sgn (z) < 0) | ||
| 227 | return false; | ||
| 228 | ptrdiff_t bits = mpz_sizeinbase (z, 2); | ||
| 229 | if (UINTMAX_WIDTH < bits) | ||
| 230 | return false; | ||
| 231 | |||
| 233 | uintmax_t v = 0; | 232 | uintmax_t v = 0; |
| 234 | if (0 <= mpz_sgn (XBIGNUM (x)->value)) | 233 | int i = 0, shift = 0; |
| 234 | |||
| 235 | do | ||
| 235 | { | 236 | { |
| 236 | ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2); | 237 | uintmax_t limb = mpz_getlimbn (z, i++); |
| 237 | if (bits <= UINTMAX_WIDTH) | 238 | v += limb << shift; |
| 238 | { | 239 | shift += GMP_NUMB_BITS; |
| 239 | int i = 0, shift = 0; | ||
| 240 | |||
| 241 | do | ||
| 242 | { | ||
| 243 | uintmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++); | ||
| 244 | v += limb << shift; | ||
| 245 | shift += GMP_NUMB_BITS; | ||
| 246 | } | ||
| 247 | while (shift < bits); | ||
| 248 | } | ||
| 249 | } | 240 | } |
| 250 | return v; | 241 | while (shift < bits); |
| 242 | |||
| 243 | *pi = v; | ||
| 244 | return true; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* Return the value of the bignum X if it fits, 0 otherwise. | ||
| 248 | A bignum cannot be zero, so 0 indicates failure reliably. */ | ||
| 249 | intmax_t | ||
| 250 | bignum_to_intmax (Lisp_Object x) | ||
| 251 | { | ||
| 252 | intmax_t i; | ||
| 253 | return mpz_to_intmax (XBIGNUM (x)->value, &i) ? i : 0; | ||
| 254 | } | ||
| 255 | uintmax_t | ||
| 256 | bignum_to_uintmax (Lisp_Object x) | ||
| 257 | { | ||
| 258 | uintmax_t i; | ||
| 259 | return mpz_to_uintmax (XBIGNUM (x)->value, &i) ? i : 0; | ||
| 251 | } | 260 | } |
| 252 | 261 | ||
| 253 | /* Yield an upper bound on the buffer size needed to contain a C | 262 | /* Yield an upper bound on the buffer size needed to contain a C |
diff --git a/src/bignum.h b/src/bignum.h index e9cd5c07635..fd035e6e14d 100644 --- a/src/bignum.h +++ b/src/bignum.h | |||
| @@ -45,7 +45,10 @@ extern mpz_t mpz[4]; | |||
| 45 | 45 | ||
| 46 | extern void init_bignum (void); | 46 | extern void init_bignum (void); |
| 47 | extern Lisp_Object make_integer_mpz (void); | 47 | extern Lisp_Object make_integer_mpz (void); |
| 48 | extern bool mpz_to_intmax (mpz_t const, intmax_t *) ARG_NONNULL ((1, 2)); | ||
| 49 | extern bool mpz_to_uintmax (mpz_t const, uintmax_t *) ARG_NONNULL ((1, 2)); | ||
| 48 | extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1)); | 50 | extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1)); |
| 51 | extern void mpz_set_uintmax_slow (mpz_t, uintmax_t) ARG_NONNULL ((1)); | ||
| 49 | extern double mpz_get_d_rounded (mpz_t const); | 52 | extern double mpz_get_d_rounded (mpz_t const); |
| 50 | 53 | ||
| 51 | INLINE_HEADER_BEGIN | 54 | INLINE_HEADER_BEGIN |
| @@ -68,6 +71,14 @@ mpz_set_intmax (mpz_t result, intmax_t v) | |||
| 68 | else | 71 | else |
| 69 | mpz_set_intmax_slow (result, v); | 72 | mpz_set_intmax_slow (result, v); |
| 70 | } | 73 | } |
| 74 | INLINE void ARG_NONNULL ((1)) | ||
| 75 | mpz_set_uintmax (mpz_t result, uintmax_t v) | ||
| 76 | { | ||
| 77 | if (v <= ULONG_MAX) | ||
| 78 | mpz_set_ui (result, v); | ||
| 79 | else | ||
| 80 | mpz_set_uintmax_slow (result, v); | ||
| 81 | } | ||
| 71 | 82 | ||
| 72 | /* Return a pointer to an mpz_t that is equal to the Lisp integer I. | 83 | /* Return a pointer to an mpz_t that is equal to the Lisp integer I. |
| 73 | If I is a bignum this returns a pointer to I's representation; | 84 | If I is a bignum this returns a pointer to I's representation; |