aboutsummaryrefslogtreecommitdiffstats
path: root/src/bignum.c
diff options
context:
space:
mode:
authorPaul Eggert2018-08-27 21:27:50 -0700
committerPaul Eggert2018-08-27 21:45:23 -0700
commitd77d01d22902acdc45c2c7059de4f1b158ab5806 (patch)
tree35f2b77594dc43e824852bb29598430945c5e6a4 /src/bignum.c
parent9abaf5f3581ecb76f30e8a6e7ee0e9633c133d1c (diff)
downloademacs-d77d01d22902acdc45c2c7059de4f1b158ab5806.tar.gz
emacs-d77d01d22902acdc45c2c7059de4f1b158ab5806.zip
Improve bignum support for system types
Use bignums when Emacs converts to and from system types like off_t for file sizes whose values can exceed fixnum range. Formerly, Emacs sometimes generted floats and sometimes ad-hoc conses of integers. Emacs still accepts floats and conses for these system types, in case some stray Lisp code is generating them, though this usage is obsolescent. * doc/lispref/files.texi (File Attributes): * doc/lispref/hash.texi (Defining Hash): * doc/lispref/nonascii.texi (Character Sets): * doc/lispref/os.texi (User Identification): * doc/lispref/processes.texi (System Processes): * etc/NEWS: Document changes. * src/bignum.c (mpz_set_uintmax, make_biguint) (mpz_set_uintmax_slow, bignum_to_intmax, bignum_to_uintmax): New functions. (mpz_set_intmax_slow): Implement via mpz_limbs_write, to avoid the need for an extra pass through a negative number. * src/charset.c (Fencode_char): * src/composite.h (LGLYPH_SET_CODE): * src/dired.c (file_attributes): * src/dosfns.c, src/w32.c (list_system_processes) (system_process_attributes): * src/editfns.c (init_editfns, Fuser_uid, Fuser_real_uid) (Fgroup_gid, Fgroup_real_gid, Femacs_pid): * src/emacs-module.c (check_vec_index): * src/fns.c (Fsafe_length): * src/process.c (record_deleted_pid, Fprocess_id): * src/sysdep.c (list_system_processes, system_process_attributes): * src/xselect.c (x_own_selection, selection_data_to_lisp_data): * src/xterm.c (set_wm_state): * src/inotify.c (inotifyevent_to_event, add_watch) (inotify_callback): If an integer is out of fixnum range, use a bignum instead of converting it to a float or a cons of integers. * src/coding.c (Fdefine_coding_system_internal): * src/frame.c (frame_windows_min_size) (x_set_frame_parameters): * src/fringe.c (Fdefine_fringe_bitmap): * src/nsterm.m (mouseDown:): * src/syntax.c (find_defun_start): * src/w32fns.c (x_set_undecorated, w32_createwindow) (w32_wnd_proc, Fx_create_frame, Fx_show_tip) (w32_console_toggle_lock_key): * src/w32inevt.c (key_event): * src/w32proc.c (Fw32_get_locale_info): Do not mishandle floats by treating their addresses as their values. * src/data.c (store_symval_forwarding): * src/gnutls.c (Fgnutls_error_fatalp, Fgnutls_error_string): * src/keyboard.c (command_loop_1, make_lispy_event): * src/lread.c (read_filtered_event, read1) (substitute_object_recurse): * src/window.c (Fcoordinates_in_window_p, Fwindow_at) (window_resize_apply, Fset_window_vscroll): * src/xdisp.c (handle_single_display_spec, try_scrolling) (redisplay_window, calc_pixel_width_or_height) (calc_line_height_property, on_hot_spot_p): * src/xfaces.c (check_lface_attrs): * src/xselect.c (x_get_local_selection, cons_to_x_long) (lisp_data_to_selection_data, clean_local_selection_data) (x_check_property_data, x_fill_property_data): (x_send_client_event): Do not reject bignums. * src/data.c (INTBIG_TO_LISP, intbig_to_lisp) (uintbig_to_lisp): Remove. All uses removed. * src/data.c (cons_to_unsigned, cons_to_signed): * src/dbusbind.c (xd_signature, xd_extract_signed) (xd_extract_unsigned): * src/dispnew.c (sit_for): * src/dosfns.c, src/w32.c (system_process_attributes): * src/editfns.c (Fuser_full_name): * src/fileio.c (file_offset): * src/fileio.c (write_region): * src/font.c (font_unparse_xlfd, font_open_for_lface, Fopen_font): * src/frame.c (x_set_screen_gamma): * src/frame.h (NUMVAL, FRAME_PIXEL_X_FROM_CANON_X) (FRAME_PIXEL_Y_FROM_CANON_Y): * src/image.c (parse_image_spec, x_edge_detection) (compute_image_size): * src/json.c (json_to_lisp): * src/lcms.c (PARSE_LAB_LIST_FIELD, Flcms_cie_de2000) (PARSE_XYZ_LIST_FIELD, PARSE_JCH_LIST_FIELD) (PARSE_JAB_LIST_FIELD, PARSE_VIEW_CONDITION_FLOAT) (Flcms_temp_to_white_point): * src/nsimage.m (ns_load_image, setSizeFromSpec): * src/process.c (Fsignal_process, handle_child_signal): * src/sysdep.c (system_process_attributes): * src/xdisp.c (calc_line_height_property): Handle bignums. * src/data.c (Fnumber_to_string): Use proper predicate name in signal if the argument is not a number. * src/lisp.h (make_uint): New function. (INT_TO_INTEGER): New macro. (FIXED_OR_FLOATP, CHECK_FIXNUM_OR_FLOAT) (CHECK_FIXNUM_OR_FLOAT_COERCE_MARKER, INTEGER_TO_CONS) (make_fixnum_or_float): Remove; no longer used. * src/nsfns.m, src/w32fns.c, src/xfns.c (Fx_create_frame): Reject floating-point min-width or min-height. * src/process.c (handle_child_signal): Do not worry about floating-point pids, as they are no longer generated.
Diffstat (limited to 'src/bignum.c')
-rw-r--r--src/bignum.c123
1 files changed, 109 insertions, 14 deletions
diff --git a/src/bignum.c b/src/bignum.c
index 18f94e7ed63..5dbfdb9319a 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -67,6 +67,18 @@ make_bignum (mpz_t const op)
67 return make_bignum_bits (op, mpz_sizeinbase (op, 2)); 67 return make_bignum_bits (op, mpz_sizeinbase (op, 2));
68} 68}
69 69
70static void mpz_set_uintmax_slow (mpz_t, uintmax_t);
71
72/* Set RESULT to V. */
73static void
74mpz_set_uintmax (mpz_t result, uintmax_t v)
75{
76 if (v <= ULONG_MAX)
77 mpz_set_ui (result, v);
78 else
79 mpz_set_uintmax_slow (result, v);
80}
81
70/* Return a Lisp integer equal to N, which must not be in fixnum range. */ 82/* Return a Lisp integer equal to N, which must not be in fixnum range. */
71Lisp_Object 83Lisp_Object
72make_bigint (intmax_t n) 84make_bigint (intmax_t n)
@@ -79,6 +91,17 @@ make_bigint (intmax_t n)
79 mpz_clear (z); 91 mpz_clear (z);
80 return result; 92 return result;
81} 93}
94Lisp_Object
95make_biguint (uintmax_t n)
96{
97 eassert (FIXNUM_OVERFLOW_P (n));
98 mpz_t z;
99 mpz_init (z);
100 mpz_set_uintmax (z, n);
101 Lisp_Object result = make_bignum (z);
102 mpz_clear (z);
103 return result;
104}
82 105
83/* Return a Lisp integer with value taken from OP. */ 106/* Return a Lisp integer with value taken from OP. */
84Lisp_Object 107Lisp_Object
@@ -109,23 +132,95 @@ make_integer (mpz_t const op)
109 return make_bignum_bits (op, bits); 132 return make_bignum_bits (op, bits);
110} 133}
111 134
135/* Set RESULT to V. This code is for when intmax_t is wider than long. */
112void 136void
113mpz_set_intmax_slow (mpz_t result, intmax_t v) 137mpz_set_intmax_slow (mpz_t result, intmax_t v)
114{ 138{
115 bool complement = v < 0; 139 int maxlimbs = (INTMAX_WIDTH + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
116 if (complement) 140 mp_limb_t *limb = mpz_limbs_write (result, maxlimbs);
117 v = -1 - v; 141 int n = 0;
118 142 uintmax_t u = v;
119 enum { nails = sizeof v * CHAR_BIT - INTMAX_WIDTH }; 143 bool negative = v < 0;
120# ifndef HAVE_GMP 144 if (negative)
121 /* mini-gmp requires NAILS to be zero, which is true for all 145 {
122 likely Emacs platforms. Sanity-check this. */ 146 uintmax_t two = 2;
123 verify (nails == 0); 147 u = -u & ((two << (UINTMAX_WIDTH - 1)) - 1);
124# endif 148 }
125 149
126 mpz_import (result, 1, -1, sizeof v, 0, nails, &v); 150 do
127 if (complement) 151 {
128 mpz_com (result, result); 152 limb[n++] = u;
153 u = GMP_NUMB_BITS < UINTMAX_WIDTH ? u >> GMP_NUMB_BITS : 0;
154 }
155 while (u != 0);
156
157 mpz_limbs_finish (result, negative ? -n : n);
158}
159static void
160mpz_set_uintmax_slow (mpz_t result, uintmax_t v)
161{
162 int maxlimbs = (UINTMAX_WIDTH + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
163 mp_limb_t *limb = mpz_limbs_write (result, maxlimbs);
164 int n = 0;
165
166 do
167 {
168 limb[n++] = v;
169 v = GMP_NUMB_BITS < INTMAX_WIDTH ? v >> GMP_NUMB_BITS : 0;
170 }
171 while (v != 0);
172
173 mpz_limbs_finish (result, n);
174}
175
176/* Return the value of the bignum X if it fits, 0 otherwise.
177 A bignum cannot be zero, so 0 indicates failure reliably. */
178intmax_t
179bignum_to_intmax (Lisp_Object x)
180{
181 ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2);
182 bool negative = mpz_sgn (XBIGNUM (x)->value) < 0;
183
184 if (bits < INTMAX_WIDTH)
185 {
186 intmax_t v = 0;
187 int i = 0, shift = 0;
188
189 do
190 {
191 intmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++);
192 v += limb << shift;
193 shift += GMP_NUMB_BITS;
194 }
195 while (shift < bits);
196
197 return negative ? -v : v;
198 }
199 return ((bits == INTMAX_WIDTH && INTMAX_MIN < -INTMAX_MAX && negative
200 && mpz_scan1 (XBIGNUM (x)->value, 0) == INTMAX_WIDTH - 1)
201 ? INTMAX_MIN : 0);
202}
203uintmax_t
204bignum_to_uintmax (Lisp_Object x)
205{
206 uintmax_t v = 0;
207 if (0 <= mpz_sgn (XBIGNUM (x)->value))
208 {
209 ptrdiff_t bits = mpz_sizeinbase (XBIGNUM (x)->value, 2);
210 if (bits <= UINTMAX_WIDTH)
211 {
212 int i = 0, shift = 0;
213
214 do
215 {
216 uintmax_t limb = mpz_getlimbn (XBIGNUM (x)->value, i++);
217 v += limb << shift;
218 shift += GMP_NUMB_BITS;
219 }
220 while (shift < bits);
221 }
222 }
223 return v;
129} 224}
130 225
131/* Convert NUM to a base-BASE Lisp string. */ 226/* Convert NUM to a base-BASE Lisp string. */