aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-10-03 09:10:01 -0700
committerPaul Eggert2018-10-06 23:31:04 -0700
commit84f39d3389209e566dde9acbdd78f5572f0c6751 (patch)
treead9788f26ffd9e9ceb7a520ed863833a5b60db8b /src
parent0faad0a0025cb4c6cbdba44e5b259690fae27b1a (diff)
downloademacs-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.c91
-rw-r--r--src/bignum.h11
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
104static void mpz_set_uintmax_slow (mpz_t, uintmax_t);
105
106/* Set RESULT to V. */
107static void
108mpz_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. */
117Lisp_Object 105Lisp_Object
118make_bigint (intmax_t n) 106make_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}
186static void 174void
187mpz_set_uintmax_slow (mpz_t result, uintmax_t v) 175mpz_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. */
205intmax_t 193bool
206bignum_to_intmax (Lisp_Object x) 194mpz_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}
230uintmax_t 223bool
231bignum_to_uintmax (Lisp_Object x) 224mpz_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. */
249intmax_t
250bignum_to_intmax (Lisp_Object x)
251{
252 intmax_t i;
253 return mpz_to_intmax (XBIGNUM (x)->value, &i) ? i : 0;
254}
255uintmax_t
256bignum_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
46extern void init_bignum (void); 46extern void init_bignum (void);
47extern Lisp_Object make_integer_mpz (void); 47extern Lisp_Object make_integer_mpz (void);
48extern bool mpz_to_intmax (mpz_t const, intmax_t *) ARG_NONNULL ((1, 2));
49extern bool mpz_to_uintmax (mpz_t const, uintmax_t *) ARG_NONNULL ((1, 2));
48extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1)); 50extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1));
51extern void mpz_set_uintmax_slow (mpz_t, uintmax_t) ARG_NONNULL ((1));
49extern double mpz_get_d_rounded (mpz_t const); 52extern double mpz_get_d_rounded (mpz_t const);
50 53
51INLINE_HEADER_BEGIN 54INLINE_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}
74INLINE void ARG_NONNULL ((1))
75mpz_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;