diff options
Diffstat (limited to 'src/data.c')
-rw-r--r-- | src/data.c | 1017 |
1 files changed, 612 insertions, 405 deletions
diff --git a/src/data.c b/src/data.c index 571114802a1..1c124740815 100644 --- a/src/data.c +++ b/src/data.c @@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <intprops.h> #include "lisp.h" +#include "bignum.h" #include "puresize.h" #include "character.h" #include "buffer.h" @@ -74,7 +75,7 @@ XKBOARD_OBJFWD (union Lisp_Fwd *a) return &a->u_kboard_objfwd; } static struct Lisp_Intfwd * -XINTFWD (union Lisp_Fwd *a) +XFIXNUMFWD (union Lisp_Fwd *a) { eassert (INTFWDP (a)); return &a->u_intfwd; @@ -132,13 +133,13 @@ set_blv_valcell (struct Lisp_Buffer_Local_Value *blv, Lisp_Object val) static _Noreturn void wrong_length_argument (Lisp_Object a1, Lisp_Object a2, Lisp_Object a3) { - Lisp_Object size1 = make_number (bool_vector_size (a1)); - Lisp_Object size2 = make_number (bool_vector_size (a2)); + Lisp_Object size1 = make_fixnum (bool_vector_size (a1)); + Lisp_Object size2 = make_fixnum (bool_vector_size (a2)); if (NILP (a3)) xsignal2 (Qwrong_length_argument, size1, size2); else xsignal3 (Qwrong_length_argument, size1, size2, - make_number (bool_vector_size (a3))); + make_fixnum (bool_vector_size (a3))); } _Noreturn void @@ -221,27 +222,17 @@ for example, (type-of 1) returns `integer'. */) case Lisp_Cons: return Qcons; - case Lisp_Misc: - switch (XMISCTYPE (object)) - { - case Lisp_Misc_Marker: - return Qmarker; - case Lisp_Misc_Overlay: - return Qoverlay; - case Lisp_Misc_Finalizer: - return Qfinalizer; -#ifdef HAVE_MODULES - case Lisp_Misc_User_Ptr: - return Quser_ptr; -#endif - default: - emacs_abort (); - } - case Lisp_Vectorlike: switch (PSEUDOVECTOR_TYPE (XVECTOR (object))) { case PVEC_NORMAL_VECTOR: return Qvector; + case PVEC_BIGNUM: return Qinteger; + case PVEC_MARKER: return Qmarker; + case PVEC_OVERLAY: return Qoverlay; + case PVEC_FINALIZER: return Qfinalizer; +#ifdef HAVE_MODULES + case PVEC_USER_PTR: return Quser_ptr; +#endif case PVEC_WINDOW_CONFIGURATION: return Qwindow_configuration; case PVEC_PROCESS: return Qprocess; case PVEC_WINDOW: return Qwindow; @@ -281,6 +272,7 @@ for example, (type-of 1) returns `integer'. */) case PVEC_XWIDGET_VIEW: return Qxwidget_view; /* "Impossible" cases. */ + case PVEC_MISC_PTR: case PVEC_OTHER: case PVEC_SUB_CHAR_TABLE: case PVEC_FREE: ; @@ -534,9 +526,9 @@ DEFUN ("natnump", Fnatnump, Snatnump, 1, 1, 0, attributes: const) (Lisp_Object object) { - if (NATNUMP (object)) - return Qt; - return Qnil; + return ((FIXNUMP (object) ? 0 <= XFIXNUM (object) + : BIGNUMP (object) && 0 <= mpz_sgn (XBIGNUM (object)->value)) + ? Qt : Qnil); } DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0, @@ -768,7 +760,9 @@ DEFUN ("fset", Ffset, Sfset, 2, 2, 0, register Lisp_Object function; CHECK_SYMBOL (symbol); /* Perhaps not quite the right error signal, but seems good enough. */ - if (NILP (symbol)) + if (NILP (symbol) && !NILP (definition)) + /* There are so many other ways to shoot oneself in the foot, I don't + think this one little sanity check is worth its cost, but anyway. */ xsignal1 (Qsetting_constant, symbol); function = XSYMBOL (symbol)->u.s.function; @@ -858,10 +852,10 @@ function with `&rest' args, or `unevalled' for a special form. */) CHECK_SUBR (subr); minargs = XSUBR (subr)->min_args; maxargs = XSUBR (subr)->max_args; - return Fcons (make_number (minargs), + return Fcons (make_fixnum (minargs), maxargs == MANY ? Qmany : maxargs == UNEVALLED ? Qunevalled - : make_number (maxargs)); + : make_fixnum (maxargs)); } DEFUN ("subr-name", Fsubr_name, Ssubr_name, 1, 1, 0, @@ -992,7 +986,7 @@ do_symval_forwarding (register union Lisp_Fwd *valcontents) switch (XFWDTYPE (valcontents)) { case Lisp_Fwd_Int: - XSETINT (val, *XINTFWD (valcontents)->intvar); + XSETINT (val, *XFIXNUMFWD (valcontents)->intvar); return val; case Lisp_Fwd_Bool: @@ -1029,7 +1023,7 @@ do_symval_forwarding (register union Lisp_Fwd *valcontents) void wrong_choice (Lisp_Object choice, Lisp_Object wrong) { - ptrdiff_t i = 0, len = XINT (Flength (choice)); + ptrdiff_t i = 0, len = XFIXNUM (Flength (choice)); Lisp_Object obj, *args; AUTO_STRING (one_of, "One of "); AUTO_STRING (comma, ", "); @@ -1049,7 +1043,10 @@ wrong_choice (Lisp_Object choice, Lisp_Object wrong) } obj = Fconcat (i, args); - SAFE_FREE (); + + /* No need to call SAFE_FREE, since signaling does that for us. */ + (void) sa_count; + xsignal2 (Qerror, obj, wrong); } @@ -1081,8 +1078,8 @@ store_symval_forwarding (union Lisp_Fwd *valcontents, register Lisp_Object newva switch (XFWDTYPE (valcontents)) { case Lisp_Fwd_Int: - CHECK_NUMBER (newval); - *XINTFWD (valcontents)->intvar = XINT (newval); + CHECK_FIXNUM (newval); + *XFIXNUMFWD (valcontents)->intvar = XFIXNUM (newval); break; case Lisp_Fwd_Bool: @@ -1710,11 +1707,21 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value, set it in the buffers that don't nominally have a local value. */ if (idx > 0) { - struct buffer *b; + Lisp_Object buf, tail; + + /* Do this only in live buffers, so that if there are + a lot of buffers which are dead, that doesn't slow + down let-binding of variables that are + automatically local when set, like + case-fold-search. This is for Lisp programs that + let-bind such variables in their inner loops. */ + FOR_EACH_LIVE_BUFFER (tail, buf) + { + struct buffer *b = XBUFFER (buf); - FOR_EACH_BUFFER (b) - if (!PER_BUFFER_VALUE_P (b, idx)) - set_per_buffer_value (b, offset, value); + if (!PER_BUFFER_VALUE_P (b, idx)) + set_per_buffer_value (b, offset, value); + } } } else @@ -1851,7 +1858,7 @@ The function `default-value' gets the default value and `set-default' sets it. } if (SYMBOL_CONSTANT_P (variable)) - error ("Symbol %s may not be buffer-local", SDATA (SYMBOL_NAME (variable))); + xsignal1 (Qsetting_constant, variable); if (!blv) { @@ -1914,8 +1921,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) } if (sym->u.s.trapped_write == SYMBOL_NOWRITE) - error ("Symbol %s may not be buffer-local", - SDATA (SYMBOL_NAME (variable))); + xsignal1 (Qsetting_constant, variable); if (blv ? blv->local_if_set : (forwarded && BUFFER_OBJFWDP (valcontents.fwd))) @@ -2154,47 +2160,6 @@ If the current binding is global (the default), the value is nil. */) } } -/* This code is disabled now that we use the selected frame to return - keyboard-local-values. */ -#if 0 -extern struct terminal *get_terminal (Lisp_Object display, int); - -DEFUN ("terminal-local-value", Fterminal_local_value, - Sterminal_local_value, 2, 2, 0, - doc: /* Return the terminal-local value of SYMBOL on TERMINAL. -If SYMBOL is not a terminal-local variable, then return its normal -value, like `symbol-value'. - -TERMINAL may be a terminal object, a frame, or nil (meaning the -selected frame's terminal device). */) - (Lisp_Object symbol, Lisp_Object terminal) -{ - Lisp_Object result; - struct terminal *t = get_terminal (terminal, 1); - push_kboard (t->kboard); - result = Fsymbol_value (symbol); - pop_kboard (); - return result; -} - -DEFUN ("set-terminal-local-value", Fset_terminal_local_value, - Sset_terminal_local_value, 3, 3, 0, - doc: /* Set the terminal-local binding of SYMBOL on TERMINAL to VALUE. -If VARIABLE is not a terminal-local variable, then set its normal -binding, like `set'. - -TERMINAL may be a terminal object, a frame, or nil (meaning the -selected frame's terminal device). */) - (Lisp_Object symbol, Lisp_Object terminal, Lisp_Object value) -{ - Lisp_Object result; - struct terminal *t = get_terminal (terminal, 1); - push_kboard (d->kboard); - result = Fset (symbol, value); - pop_kboard (); - return result; -} -#endif /* Find the function at the end of a chain of symbol function indirections. */ @@ -2261,8 +2226,8 @@ or a byte-code object. IDX starts at 0. */) { register EMACS_INT idxval; - CHECK_NUMBER (idx); - idxval = XINT (idx); + CHECK_FIXNUM (idx); + idxval = XFIXNUM (idx); if (STRINGP (array)) { int c; @@ -2271,11 +2236,11 @@ or a byte-code object. IDX starts at 0. */) if (idxval < 0 || idxval >= SCHARS (array)) args_out_of_range (array, idx); if (! STRING_MULTIBYTE (array)) - return make_number ((unsigned char) SREF (array, idxval)); + return make_fixnum ((unsigned char) SREF (array, idxval)); idxval_byte = string_char_to_byte (array, idxval); c = STRING_CHAR (SDATA (array) + idxval_byte); - return make_number (c); + return make_fixnum (c); } else if (BOOL_VECTOR_P (array)) { @@ -2312,8 +2277,8 @@ bool-vector. IDX starts at 0. */) { register EMACS_INT idxval; - CHECK_NUMBER (idx); - idxval = XINT (idx); + CHECK_FIXNUM (idx); + idxval = XFIXNUM (idx); if (! RECORDP (array)) CHECK_ARRAY (array, Qarrayp); @@ -2349,7 +2314,7 @@ bool-vector. IDX starts at 0. */) if (idxval < 0 || idxval >= SCHARS (array)) args_out_of_range (array, idx); CHECK_CHARACTER (newelt); - c = XFASTINT (newelt); + c = XFIXNAT (newelt); if (STRING_MULTIBYTE (array)) { @@ -2403,39 +2368,113 @@ bool-vector. IDX starts at 0. */) return newelt; } +/* GMP tests for this value and aborts (!) if it is exceeded. + This is as of GMP 6.1.2 (2016); perhaps future versions will differ. */ +enum { GMP_NLIMBS_MAX = min (INT_MAX, ULONG_MAX / GMP_NUMB_BITS) }; + +/* An upper bound on limb counts, needed to prevent libgmp and/or + Emacs from aborting or otherwise misbehaving. This bound applies + to estimates of mpz_t sizes before the mpz_t objects are created, + as opposed to integer-width which operates on mpz_t values after + creation and before conversion to Lisp bignums. */ +enum + { + NLIMBS_LIMIT = min (min (/* libgmp needs to store limb counts. */ + GMP_NLIMBS_MAX, + + /* Size calculations need to work. */ + min (PTRDIFF_MAX, SIZE_MAX) / sizeof (mp_limb_t)), + + /* Emacs puts bit counts into fixnums. */ + MOST_POSITIVE_FIXNUM / GMP_NUMB_BITS) + }; + +/* Like mpz_size, but tell the compiler the result is a nonnegative int. */ + +static int +emacs_mpz_size (mpz_t const op) +{ + mp_size_t size = mpz_size (op); + eassume (0 <= size && size <= INT_MAX); + return size; +} + +/* Wrappers to work around GMP limitations. As of GMP 6.1.2 (2016), + the library code aborts when a number is too large. These wrappers + avoid the problem for functions that can return numbers much larger + than their arguments. For slowly-growing numbers, the integer + width checks in bignum.c should suffice. */ + +static void +emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2) +{ + if (NLIMBS_LIMIT - emacs_mpz_size (op1) < emacs_mpz_size (op2)) + overflow_error (); + mpz_mul (rop, op1, op2); +} + +static void +emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, EMACS_INT op2) +{ + /* Fudge factor derived from GMP 6.1.2, to avoid an abort in + mpz_mul_2exp (look for the '+ 1' in its source code). */ + enum { mul_2exp_extra_limbs = 1 }; + enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) }; + + EMACS_INT op2limbs = op2 / GMP_NUMB_BITS; + if (lim - emacs_mpz_size (op1) < op2limbs) + overflow_error (); + mpz_mul_2exp (rop, op1, op2); +} + +static void +emacs_mpz_pow_ui (mpz_t rop, mpz_t const base, unsigned long exp) +{ + /* This fudge factor is derived from GMP 6.1.2, to avoid an abort in + mpz_n_pow_ui (look for the '5' in its source code). */ + enum { pow_ui_extra_limbs = 5 }; + enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - pow_ui_extra_limbs) }; + + int nbase = emacs_mpz_size (base), n; + if (INT_MULTIPLY_WRAPV (nbase, exp, &n) || lim < n) + overflow_error (); + mpz_pow_ui (rop, base, exp); +} + + /* Arithmetic functions */ Lisp_Object arithcompare (Lisp_Object num1, Lisp_Object num2, enum Arith_Comparison comparison) { - double f1, f2; - EMACS_INT i1, i2; - bool lt, eq, gt; + EMACS_INT i1 = 0, i2 = 0; + bool lt, eq = true, gt; bool test; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num1); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num2); + CHECK_NUMBER_COERCE_MARKER (num1); + CHECK_NUMBER_COERCE_MARKER (num2); - /* If either arg is floating point, set F1 and F2 to the 'double' - approximations of the two arguments, and set LT, EQ, and GT to - the <, ==, > floating-point comparisons of F1 and F2 + /* If the comparison is mostly done by comparing two doubles, + set LT, EQ, and GT to the <, ==, > results of that comparison, respectively, taking care to avoid problems if either is a NaN, and trying to avoid problems on platforms where variables (in violation of the C standard) can contain excess precision. Regardless, set I1 and I2 to integers that break ties if the - floating-point comparison is either not done or reports + two-double comparison is either not done or reports equality. */ if (FLOATP (num1)) { - f1 = XFLOAT_DATA (num1); + double f1 = XFLOAT_DATA (num1); if (FLOATP (num2)) { - i1 = i2 = 0; - f2 = XFLOAT_DATA (num2); + double f2 = XFLOAT_DATA (num2); + lt = f1 < f2; + eq = f1 == f2; + gt = f1 > f2; } - else + else if (FIXNUMP (num2)) { /* Compare a float NUM1 to an integer NUM2 by converting the integer I2 (i.e., NUM2) to the double F2 (a conversion that @@ -2445,35 +2484,56 @@ arithcompare (Lisp_Object num1, Lisp_Object num2, floating-point comparison reports a tie, NUM1 = F1 = F2 = I1 (exactly) so I1 - I2 = NUM1 - NUM2 (exactly), so comparing I1 to I2 will break the tie correctly. */ - i1 = f2 = i2 = XINT (num2); + double f2 = XFIXNUM (num2); + lt = f1 < f2; + eq = f1 == f2; + gt = f1 > f2; + i1 = f2; + i2 = XFIXNUM (num2); } - lt = f1 < f2; - eq = f1 == f2; - gt = f1 > f2; + else if (isnan (f1)) + lt = eq = gt = false; + else + i2 = mpz_cmp_d (XBIGNUM (num2)->value, f1); } - else + else if (FIXNUMP (num1)) { - i1 = XINT (num1); if (FLOATP (num2)) { /* Compare an integer NUM1 to a float NUM2. This is the converse of comparing float to integer (see above). */ - i2 = f1 = i1; - f2 = XFLOAT_DATA (num2); + double f1 = XFIXNUM (num1), f2 = XFLOAT_DATA (num2); lt = f1 < f2; eq = f1 == f2; gt = f1 > f2; + i1 = XFIXNUM (num1); + i2 = f1; } - else + else if (FIXNUMP (num2)) { - i2 = XINT (num2); - eq = true; + i1 = XFIXNUM (num1); + i2 = XFIXNUM (num2); } + else + i2 = mpz_sgn (XBIGNUM (num2)->value); + } + else if (FLOATP (num2)) + { + double f2 = XFLOAT_DATA (num2); + if (isnan (f2)) + lt = eq = gt = false; + else + i1 = mpz_cmp_d (XBIGNUM (num1)->value, f2); } + else if (FIXNUMP (num2)) + i1 = mpz_sgn (XBIGNUM (num1)->value); + else + i1 = mpz_cmp (XBIGNUM (num1)->value, XBIGNUM (num2)->value); if (eq) { - /* Break a floating-point tie by comparing the integers. */ + /* The two-double comparison either reported equality, or was not done. + Break the tie by comparing the integers. */ lt = i1 < i2; eq = i1 == i2; gt = i1 > i2; @@ -2569,48 +2629,21 @@ DEFUN ("/=", Fneq, Sneq, 2, 2, 0, return arithcompare (num1, num2, ARITH_NOTEQUAL); } -/* Convert the integer I to a cons-of-integers, where I is not in - fixnum range. */ - -#define INTBIG_TO_LISP(i, extremum) \ - (eassert (FIXNUM_OVERFLOW_P (i)), \ - (! (FIXNUM_OVERFLOW_P ((extremum) >> 16) \ - && FIXNUM_OVERFLOW_P ((i) >> 16)) \ - ? Fcons (make_number ((i) >> 16), make_number ((i) & 0xffff)) \ - : ! (FIXNUM_OVERFLOW_P ((extremum) >> 16 >> 24) \ - && FIXNUM_OVERFLOW_P ((i) >> 16 >> 24)) \ - ? Fcons (make_number ((i) >> 16 >> 24), \ - Fcons (make_number ((i) >> 16 & 0xffffff), \ - make_number ((i) & 0xffff))) \ - : make_float (i))) - -Lisp_Object -intbig_to_lisp (intmax_t i) -{ - return INTBIG_TO_LISP (i, INTMAX_MIN); -} - -Lisp_Object -uintbig_to_lisp (uintmax_t i) -{ - return INTBIG_TO_LISP (i, UINTMAX_MAX); -} - /* Convert the cons-of-integers, integer, or float value C to an unsigned value with maximum value MAX, where MAX is one less than a power of 2. Signal an error if C does not have a valid format or - is out of range. */ + is out of range. + + Although Emacs represents large integers with bignums instead of + cons-of-integers or floats, for now this function still accepts the + obsolete forms in case some old Lisp code still generates them. */ uintmax_t cons_to_unsigned (Lisp_Object c, uintmax_t max) { bool valid = false; uintmax_t val UNINIT; - if (INTEGERP (c)) - { - valid = XINT (c) >= 0; - val = XINT (c); - } - else if (FLOATP (c)) + + if (FLOATP (c)) { double d = XFLOAT_DATA (c); if (d >= 0 && d < 1.0 + max) @@ -2619,27 +2652,34 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) valid = val == d; } } - else if (CONSP (c) && NATNUMP (XCAR (c))) + else { - uintmax_t top = XFASTINT (XCAR (c)); - Lisp_Object rest = XCDR (c); - if (top <= UINTMAX_MAX >> 24 >> 16 - && CONSP (rest) - && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 - && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) - { - uintmax_t mid = XFASTINT (XCAR (rest)); - val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = true; - } - else if (top <= UINTMAX_MAX >> 16) + Lisp_Object hi = CONSP (c) ? XCAR (c) : c; + valid = INTEGERP (hi) && integer_to_uintmax (hi, &val); + + if (valid && CONSP (c)) { - if (CONSP (rest)) - rest = XCAR (rest); - if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + uintmax_t top = val; + Lisp_Object rest = XCDR (c); + if (top <= UINTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && FIXNATP (XCAR (rest)) && XFIXNAT (XCAR (rest)) < 1 << 24 + && FIXNATP (XCDR (rest)) && XFIXNAT (XCDR (rest)) < 1 << 16) { - val = top << 16 | XFASTINT (rest); - valid = true; + uintmax_t mid = XFIXNAT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFIXNAT (XCDR (rest)); + } + else + { + valid = top <= UINTMAX_MAX >> 16; + if (valid) + { + if (CONSP (rest)) + rest = XCAR (rest); + valid = FIXNATP (rest) && XFIXNAT (rest) < 1 << 16; + if (valid) + val = top << 16 | XFIXNAT (rest); + } } } } @@ -2653,18 +2693,18 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) value with extrema MIN and MAX. MAX should be one less than a power of 2, and MIN should be zero or the negative of a power of 2. Signal an error if C does not have a valid format or is out of - range. */ + range. + + Although Emacs represents large integers with bignums instead of + cons-of-integers or floats, for now this function still accepts the + obsolete forms in case some old Lisp code still generates them. */ intmax_t cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) { bool valid = false; intmax_t val UNINIT; - if (INTEGERP (c)) - { - val = XINT (c); - valid = true; - } - else if (FLOATP (c)) + + if (FLOATP (c)) { double d = XFLOAT_DATA (c); if (d >= min && d < 1.0 + max) @@ -2673,27 +2713,34 @@ cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) valid = val == d; } } - else if (CONSP (c) && INTEGERP (XCAR (c))) + else { - intmax_t top = XINT (XCAR (c)); - Lisp_Object rest = XCDR (c); - if (top >= INTMAX_MIN >> 24 >> 16 && top <= INTMAX_MAX >> 24 >> 16 - && CONSP (rest) - && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 - && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) - { - intmax_t mid = XFASTINT (XCAR (rest)); - val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = true; - } - else if (top >= INTMAX_MIN >> 16 && top <= INTMAX_MAX >> 16) + Lisp_Object hi = CONSP (c) ? XCAR (c) : c; + valid = INTEGERP (hi) && integer_to_intmax (hi, &val); + + if (valid && CONSP (c)) { - if (CONSP (rest)) - rest = XCAR (rest); - if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + intmax_t top = val; + Lisp_Object rest = XCDR (c); + if (top >= INTMAX_MIN >> 24 >> 16 && top <= INTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && FIXNATP (XCAR (rest)) && XFIXNAT (XCAR (rest)) < 1 << 24 + && FIXNATP (XCDR (rest)) && XFIXNAT (XCDR (rest)) < 1 << 16) { - val = top << 16 | XFASTINT (rest); - valid = true; + intmax_t mid = XFIXNAT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFIXNAT (XCDR (rest)); + } + else + { + valid = INTMAX_MIN >> 16 <= top && top <= INTMAX_MAX >> 16; + if (valid) + { + if (CONSP (rest)) + rest = XCAR (rest); + valid = FIXNATP (rest) && XFIXNAT (rest) < 1 << 16; + if (valid) + val = top << 16 | XFIXNAT (rest); + } } } } @@ -2712,12 +2759,15 @@ NUMBER may be an integer or a floating point number. */) char buffer[max (FLOAT_TO_STRING_BUFSIZE, INT_BUFSIZE_BOUND (EMACS_INT))]; int len; - CHECK_NUMBER_OR_FLOAT (number); + CHECK_NUMBER (number); + + if (BIGNUMP (number)) + return bignum_to_string (number, 10); if (FLOATP (number)) len = float_to_string (buffer, XFLOAT_DATA (number)); else - len = sprintf (buffer, "%"pI"d", XINT (number)); + len = sprintf (buffer, "%"pI"d", XFIXNUM (number)); return make_unibyte_string (buffer, len); } @@ -2732,9 +2782,7 @@ present, base 10 is used. BASE must be between 2 and 16 (inclusive). If the base used is not 10, STRING is always parsed as an integer. */) (register Lisp_Object string, Lisp_Object base) { - register char *p; - register int b; - Lisp_Object val; + int b; CHECK_STRING (string); @@ -2742,18 +2790,18 @@ If the base used is not 10, STRING is always parsed as an integer. */) b = 10; else { - CHECK_NUMBER (base); - if (! (XINT (base) >= 2 && XINT (base) <= 16)) + CHECK_FIXNUM (base); + if (! (XFIXNUM (base) >= 2 && XFIXNUM (base) <= 16)) xsignal1 (Qargs_out_of_range, base); - b = XINT (base); + b = XFIXNUM (base); } - p = SSDATA (string); + char *p = SSDATA (string); while (*p == ' ' || *p == '\t') p++; - val = string_to_number (p, b, 1); - return NILP (val) ? make_number (0) : val; + Lisp_Object val = string_to_number (p, b, 0); + return NILP (val) ? make_fixnum (0) : val; } enum arithop @@ -2766,151 +2814,178 @@ enum arithop Alogior, Alogxor }; +static bool +floating_point_op (enum arithop code) +{ + return code <= Adiv; +} + +/* Return the result of applying the floating-point operation CODE to + the NARGS arguments starting at ARGS. If ARGNUM is positive, + ARGNUM of the arguments were already consumed, yielding ACCUM. + 0 <= ARGNUM < NARGS, 2 <= NARGS, and NEXT is the value of + ARGS[ARGSNUM], converted to double. */ -static Lisp_Object float_arith_driver (double, ptrdiff_t, enum arithop, - ptrdiff_t, Lisp_Object *); static Lisp_Object -arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) +floatop_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, double accum, double next) { - Lisp_Object val; - ptrdiff_t argnum, ok_args; - EMACS_INT accum = 0; - EMACS_INT next, ok_accum; - bool overflow = 0; - - switch (code) - { - case Alogior: - case Alogxor: - case Aadd: - case Asub: - accum = 0; - break; - case Amult: - case Adiv: - accum = 1; - break; - case Alogand: - accum = -1; - break; - default: - break; + if (argnum == 0) + { + accum = next; + goto next_arg; } - for (argnum = 0; argnum < nargs; argnum++) + while (true) { - if (! overflow) - { - ok_args = argnum; - ok_accum = accum; - } - - /* Using args[argnum] as argument to CHECK_NUMBER_... */ - val = args[argnum]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); - - if (FLOATP (val)) - return float_arith_driver (ok_accum, ok_args, code, - nargs, args); - args[argnum] = val; - next = XINT (args[argnum]); switch (code) { - case Aadd: - overflow |= INT_ADD_WRAPV (accum, next, &accum); - break; - case Asub: - if (! argnum) - accum = nargs == 1 ? - next : next; - else - overflow |= INT_SUBTRACT_WRAPV (accum, next, &accum); - break; - case Amult: - overflow |= INT_MULTIPLY_WRAPV (accum, next, &accum); - break; + case Aadd : accum += next; break; + case Asub : accum -= next; break; + case Amult: accum *= next; break; case Adiv: - if (! (argnum || nargs == 1)) - accum = next; - else - { - if (next == 0) - xsignal0 (Qarith_error); - if (INT_DIVIDE_OVERFLOW (accum, next)) - overflow = true; - else - accum /= next; - } - break; - case Alogand: - accum &= next; - break; - case Alogior: - accum |= next; - break; - case Alogxor: - accum ^= next; + if (! IEEE_FLOATING_POINT && next == 0) + xsignal0 (Qarith_error); + accum /= next; break; + default: eassume (false); } + + next_arg: + argnum++; + if (argnum == nargs) + return make_float (accum); + Lisp_Object val = args[argnum]; + CHECK_NUMBER_COERCE_MARKER (val); + next = XFLOATINT (val); } +} - XSETINT (val, accum); - return val; +/* Like floatop_arith_driver, except CODE might not be a floating-point + operation, and NEXT is a Lisp float rather than a C double. */ + +static Lisp_Object +float_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, double accum, Lisp_Object next) +{ + if (! floating_point_op (code)) + wrong_type_argument (Qinteger_or_marker_p, next); + return floatop_arith_driver (code, nargs, args, argnum, accum, + XFLOAT_DATA (next)); } -#ifndef isnan -# define isnan(x) ((x) != (x)) -#endif +/* Return the result of applying the arithmetic operation CODE to the + NARGS arguments starting at ARGS. If ARGNUM is positive, ARGNUM of + the arguments were already consumed, yielding IACCUM. 0 <= ARGNUM + < NARGS, 2 <= NARGS, and VAL is the value of ARGS[ARGSNUM], + converted to integer. */ static Lisp_Object -float_arith_driver (double accum, ptrdiff_t argnum, enum arithop code, - ptrdiff_t nargs, Lisp_Object *args) +bignum_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + ptrdiff_t argnum, intmax_t iaccum, Lisp_Object val) { - register Lisp_Object val; - double next; + mpz_t *accum; + if (argnum == 0) + { + accum = bignum_integer (&mpz[0], val); + goto next_arg; + } + mpz_set_intmax (mpz[0], iaccum); + accum = &mpz[0]; - for (; argnum < nargs; argnum++) + while (true) { - val = args[argnum]; /* using args[argnum] as argument to CHECK_NUMBER_... */ - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); + mpz_t *next = bignum_integer (&mpz[1], val); - if (FLOATP (val)) - { - next = XFLOAT_DATA (val); - } - else - { - args[argnum] = val; /* runs into a compiler bug. */ - next = XINT (args[argnum]); - } switch (code) { - case Aadd: - accum += next; - break; - case Asub: - accum = argnum ? accum - next : nargs == 1 ? - next : next; - break; - case Amult: - accum *= next; - break; + case Aadd : mpz_add (mpz[0], *accum, *next); break; + case Asub : mpz_sub (mpz[0], *accum, *next); break; + case Amult : emacs_mpz_mul (mpz[0], *accum, *next); break; + case Alogand: mpz_and (mpz[0], *accum, *next); break; + case Alogior: mpz_ior (mpz[0], *accum, *next); break; + case Alogxor: mpz_xor (mpz[0], *accum, *next); break; case Adiv: - if (! (argnum || nargs == 1)) - accum = next; - else - { - if (! IEEE_FLOATING_POINT && next == 0) - xsignal0 (Qarith_error); - accum /= next; - } + if (mpz_sgn (*next) == 0) + xsignal0 (Qarith_error); + mpz_tdiv_q (mpz[0], *accum, *next); break; - case Alogand: - case Alogior: - case Alogxor: - wrong_type_argument (Qinteger_or_marker_p, val); + default: + eassume (false); } + accum = &mpz[0]; + + next_arg: + argnum++; + if (argnum == nargs) + return make_integer_mpz (); + val = args[argnum]; + CHECK_NUMBER_COERCE_MARKER (val); + if (FLOATP (val)) + return float_arith_driver (code, nargs, args, argnum, + mpz_get_d_rounded (*accum), val); } +} - return make_float (accum); +/* Return the result of applying the arithmetic operation CODE to the + NARGS arguments starting at ARGS, with the first argument being the + number VAL. 2 <= NARGS. Check that the remaining arguments are + numbers or markers. */ + +static Lisp_Object +arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args, + Lisp_Object val) +{ + eassume (2 <= nargs); + + ptrdiff_t argnum = 0; + /* Set ACCUM to VAL's value if it is a fixnum, otherwise to some + ignored value to avoid using an uninitialized variable later. */ + intmax_t accum = XFIXNUM (val); + + if (FIXNUMP (val)) + while (true) + { + argnum++; + if (argnum == nargs) + return make_int (accum); + val = args[argnum]; + CHECK_NUMBER_COERCE_MARKER (val); + + /* Set NEXT to the next value if it fits, else exit the loop. */ + intmax_t next; + if (! (INTEGERP (val) && integer_to_intmax (val, &next))) + break; + + /* Set ACCUM to the next operation's result if it fits, + else exit the loop. */ + bool overflow = false; + intmax_t a; + switch (code) + { + case Aadd : overflow = INT_ADD_WRAPV (accum, next, &a); break; + case Amult: overflow = INT_MULTIPLY_WRAPV (accum, next, &a); break; + case Asub : overflow = INT_SUBTRACT_WRAPV (accum, next, &a); break; + case Adiv: + if (next == 0) + xsignal0 (Qarith_error); + overflow = INT_DIVIDE_OVERFLOW (accum, next); + if (!overflow) + a = accum / next; + break; + case Alogand: accum &= next; continue; + case Alogior: accum |= next; continue; + case Alogxor: accum ^= next; continue; + default: eassume (false); + } + if (overflow) + break; + accum = a; + } + + return (FLOATP (val) + ? float_arith_driver (code, nargs, args, argnum, accum, val) + : bignum_arith_driver (code, nargs, args, argnum, accum, val)); } @@ -2919,7 +2994,11 @@ DEFUN ("+", Fplus, Splus, 0, MANY, 0, usage: (+ &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Aadd, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = args[0]; + CHECK_NUMBER_COERCE_MARKER (a); + return nargs == 1 ? a : arith_driver (Aadd, nargs, args, a); } DEFUN ("-", Fminus, Sminus, 0, MANY, 0, @@ -2929,7 +3008,20 @@ subtracts all but the first from the first. usage: (- &optional NUMBER-OR-MARKER &rest MORE-NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Asub, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = args[0]; + CHECK_NUMBER_COERCE_MARKER (a); + if (nargs == 1) + { + if (FIXNUMP (a)) + return make_int (-XFIXNUM (a)); + if (FLOATP (a)) + return make_float (-XFLOAT_DATA (a)); + mpz_neg (mpz[0], XBIGNUM (a)->value); + return make_integer_mpz (); + } + return arith_driver (Asub, nargs, args, a); } DEFUN ("*", Ftimes, Stimes, 0, MANY, 0, @@ -2937,7 +3029,11 @@ DEFUN ("*", Ftimes, Stimes, 0, MANY, 0, usage: (* &rest NUMBERS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Amult, nargs, args); + if (nargs == 0) + return make_fixnum (1); + Lisp_Object a = args[0]; + CHECK_NUMBER_COERCE_MARKER (a); + return nargs == 1 ? a : arith_driver (Amult, nargs, args, a); } DEFUN ("/", Fquo, Squo, 1, MANY, 0, @@ -2948,11 +3044,31 @@ The arguments must be numbers or markers. usage: (/ NUMBER &rest DIVISORS) */) (ptrdiff_t nargs, Lisp_Object *args) { - ptrdiff_t argnum; - for (argnum = 2; argnum < nargs; argnum++) + Lisp_Object a = args[0]; + CHECK_NUMBER_COERCE_MARKER (a); + if (nargs == 1) + { + if (FIXNUMP (a)) + { + if (XFIXNUM (a) == 0) + xsignal0 (Qarith_error); + return make_fixnum (1 / XFIXNUM (a)); + } + if (FLOATP (a)) + { + if (! IEEE_FLOATING_POINT && XFLOAT_DATA (a) == 0) + xsignal0 (Qarith_error); + return make_float (1 / XFLOAT_DATA (a)); + } + /* Dividing 1 by any bignum yields 0. */ + return make_fixnum (0); + } + + /* Do all computation in floating-point if any arg is a float. */ + for (ptrdiff_t argnum = 2; argnum < nargs; argnum++) if (FLOATP (args[argnum])) - return float_arith_driver (0, 0, Adiv, nargs, args); - return arith_driver (Adiv, nargs, args); + return floatop_arith_driver (Adiv, nargs, args, 0, 0, XFLOATINT (a)); + return arith_driver (Adiv, nargs, args, a); } DEFUN ("%", Frem, Srem, 2, 2, 0, @@ -2960,16 +3076,22 @@ DEFUN ("%", Frem, Srem, 2, 2, 0, Both must be integers or markers. */) (register Lisp_Object x, Lisp_Object y) { - Lisp_Object val; - - CHECK_NUMBER_COERCE_MARKER (x); - CHECK_NUMBER_COERCE_MARKER (y); + CHECK_INTEGER_COERCE_MARKER (x); + CHECK_INTEGER_COERCE_MARKER (y); - if (XINT (y) == 0) + /* A bignum can never be 0, so don't check that case. */ + if (FIXNUMP (y) && XFIXNUM (y) == 0) xsignal0 (Qarith_error); - XSETINT (val, XINT (x) % XINT (y)); - return val; + if (FIXNUMP (x) && FIXNUMP (y)) + return make_fixnum (XFIXNUM (x) % XFIXNUM (y)); + else + { + mpz_tdiv_r (mpz[0], + *bignum_integer (&mpz[0], x), + *bignum_integer (&mpz[1], y)); + return make_integer_mpz (); + } } DEFUN ("mod", Fmod, Smod, 2, 2, 0, @@ -2978,29 +3100,45 @@ The result falls between zero (inclusive) and Y (exclusive). Both X and Y must be numbers or markers. */) (register Lisp_Object x, Lisp_Object y) { - Lisp_Object val; - EMACS_INT i1, i2; + CHECK_NUMBER_COERCE_MARKER (x); + CHECK_NUMBER_COERCE_MARKER (y); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (x); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (y); + /* Note that a bignum can never be 0, so we don't need to check that + case. */ + if (FIXNUMP (y) && XFIXNUM (y) == 0) + xsignal0 (Qarith_error); if (FLOATP (x) || FLOATP (y)) return fmod_float (x, y); - i1 = XINT (x); - i2 = XINT (y); + if (FIXNUMP (x) && FIXNUMP (y)) + { + EMACS_INT i1 = XFIXNUM (x), i2 = XFIXNUM (y); - if (i2 == 0) - xsignal0 (Qarith_error); + if (i2 == 0) + xsignal0 (Qarith_error); - i1 %= i2; + i1 %= i2; - /* If the "remainder" comes out with the wrong sign, fix it. */ - if (i2 < 0 ? i1 > 0 : i1 < 0) - i1 += i2; + /* If the "remainder" comes out with the wrong sign, fix it. */ + if (i2 < 0 ? i1 > 0 : i1 < 0) + i1 += i2; - XSETINT (val, i1); - return val; + return make_fixnum (i1); + } + else + { + mpz_t *ym = bignum_integer (&mpz[1], y); + bool neg_y = mpz_sgn (*ym) < 0; + mpz_mod (mpz[0], *bignum_integer (&mpz[0], x), *ym); + + /* Fix the sign if needed. */ + int sgn_r = mpz_sgn (mpz[0]); + if (neg_y ? sgn_r > 0 : sgn_r < 0) + mpz_add (mpz[0], mpz[0], *ym); + + return make_integer_mpz (); + } } static Lisp_Object @@ -3008,11 +3146,11 @@ minmax_driver (ptrdiff_t nargs, Lisp_Object *args, enum Arith_Comparison comparison) { Lisp_Object accum = args[0]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (accum); + CHECK_NUMBER_COERCE_MARKER (accum); for (ptrdiff_t argnum = 1; argnum < nargs; argnum++) { Lisp_Object val = args[argnum]; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val); + CHECK_NUMBER_COERCE_MARKER (val); if (!NILP (arithcompare (val, accum, comparison))) accum = val; else if (FLOATP (val) && isnan (XFLOAT_DATA (val))) @@ -3045,7 +3183,11 @@ Arguments may be integers, or markers converted to integers. usage: (logand &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogand, nargs, args); + if (nargs == 0) + return make_fixnum (-1); + Lisp_Object a = args[0]; + CHECK_INTEGER_COERCE_MARKER (a); + return nargs == 1 ? a : arith_driver (Alogand, nargs, args, a); } DEFUN ("logior", Flogior, Slogior, 0, MANY, 0, @@ -3054,7 +3196,11 @@ Arguments may be integers, or markers converted to integers. usage: (logior &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogior, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = args[0]; + CHECK_INTEGER_COERCE_MARKER (a); + return nargs == 1 ? a : arith_driver (Alogior, nargs, args, a); } DEFUN ("logxor", Flogxor, Slogxor, 0, MANY, 0, @@ -3063,48 +3209,108 @@ Arguments may be integers, or markers converted to integers. usage: (logxor &rest INTS-OR-MARKERS) */) (ptrdiff_t nargs, Lisp_Object *args) { - return arith_driver (Alogxor, nargs, args); + if (nargs == 0) + return make_fixnum (0); + Lisp_Object a = args[0]; + CHECK_INTEGER_COERCE_MARKER (a); + return nargs == 1 ? a : arith_driver (Alogxor, nargs, args, a); } -static Lisp_Object -ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) +DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, + doc: /* Return population count of VALUE. +This is the number of one bits in the two's complement representation +of VALUE. If VALUE is negative, return the number of zero bits in the +representation. */) + (Lisp_Object value) { - /* This code assumes that signed right shifts are arithmetic. */ - verify ((EMACS_INT) -1 >> 1 == -1); - - Lisp_Object val; + CHECK_INTEGER (value); - CHECK_NUMBER (value); - CHECK_NUMBER (count); + if (BIGNUMP (value)) + { + mpz_t *nonneg = &XBIGNUM (value)->value; + if (mpz_sgn (*nonneg) < 0) + { + mpz_com (mpz[0], *nonneg); + nonneg = &mpz[0]; + } + return make_fixnum (mpz_popcount (*nonneg)); + } - if (XINT (count) >= EMACS_INT_WIDTH) - XSETINT (val, 0); - else if (XINT (count) > 0) - XSETINT (val, XUINT (value) << XINT (count)); - else if (XINT (count) <= -EMACS_INT_WIDTH) - XSETINT (val, lsh ? 0 : XINT (value) < 0 ? -1 : 0); - else - XSETINT (val, (lsh ? XUINT (value) >> -XINT (count) - : XINT (value) >> -XINT (count))); - return val; + eassume (FIXNUMP (value)); + EMACS_INT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); + return make_fixnum (EMACS_UINT_WIDTH <= UINT_WIDTH + ? count_one_bits (v) + : EMACS_UINT_WIDTH <= ULONG_WIDTH + ? count_one_bits_l (v) + : count_one_bits_ll (v)); } DEFUN ("ash", Fash, Sash, 2, 2, 0, doc: /* Return VALUE with its bits shifted left by COUNT. If COUNT is negative, shifting is actually to the right. In this case, the sign bit is duplicated. */) - (register Lisp_Object value, Lisp_Object count) + (Lisp_Object value, Lisp_Object count) { - return ash_lsh_impl (value, count, false); + CHECK_INTEGER (value); + CHECK_INTEGER (count); + + if (! FIXNUMP (count)) + { + if (EQ (value, make_fixnum (0))) + return value; + if (mpz_sgn (XBIGNUM (count)->value) < 0) + { + EMACS_INT v = (FIXNUMP (value) ? XFIXNUM (value) + : mpz_sgn (XBIGNUM (value)->value)); + return make_fixnum (v < 0 ? -1 : 0); + } + overflow_error (); + } + + if (XFIXNUM (count) <= 0) + { + if (XFIXNUM (count) == 0) + return value; + + if ((EMACS_INT) -1 >> 1 == -1 && FIXNUMP (value)) + { + EMACS_INT shift = -XFIXNUM (count); + EMACS_INT result + = (shift < EMACS_INT_WIDTH ? XFIXNUM (value) >> shift + : XFIXNUM (value) < 0 ? -1 : 0); + return make_fixnum (result); + } + } + + mpz_t *zval = bignum_integer (&mpz[0], value); + if (XFIXNUM (count) < 0) + { + if (TYPE_MAXIMUM (mp_bitcnt_t) < - XFIXNUM (count)) + return make_fixnum (mpz_sgn (*zval) < 0 ? -1 : 0); + mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count)); + } + else + emacs_mpz_mul_2exp (mpz[0], *zval, XFIXNUM (count)); + return make_integer_mpz (); } -DEFUN ("lsh", Flsh, Slsh, 2, 2, 0, - doc: /* Return VALUE with its bits shifted left by COUNT. -If COUNT is negative, shifting is actually to the right. -In this case, zeros are shifted in on the left. */) - (register Lisp_Object value, Lisp_Object count) -{ - return ash_lsh_impl (value, count, true); +/* Return X ** Y as an integer. X and Y must be integers, and Y must + be nonnegative. */ + +Lisp_Object +expt_integer (Lisp_Object x, Lisp_Object y) +{ + unsigned long exp; + if (TYPE_RANGED_FIXNUMP (unsigned long, y)) + exp = XFIXNUM (y); + else if (MOST_POSITIVE_FIXNUM < ULONG_MAX && BIGNUMP (y) + && mpz_fits_ulong_p (XBIGNUM (y)->value)) + exp = mpz_get_ui (XBIGNUM (y)->value); + else + overflow_error (); + + emacs_mpz_pow_ui (mpz[0], *bignum_integer (&mpz[0], x), exp); + return make_integer_mpz (); } DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, @@ -3112,13 +3318,14 @@ DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, Markers are converted to integers. */) (register Lisp_Object number) { - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (number); + CHECK_NUMBER_COERCE_MARKER (number); + if (FIXNUMP (number)) + return make_int (XFIXNUM (number) + 1); if (FLOATP (number)) return (make_float (1.0 + XFLOAT_DATA (number))); - - XSETINT (number, XINT (number) + 1); - return number; + mpz_add_ui (mpz[0], XBIGNUM (number)->value, 1); + return make_integer_mpz (); } DEFUN ("1-", Fsub1, Ssub1, 1, 1, 0, @@ -3126,22 +3333,25 @@ DEFUN ("1-", Fsub1, Ssub1, 1, 1, 0, Markers are converted to integers. */) (register Lisp_Object number) { - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (number); + CHECK_NUMBER_COERCE_MARKER (number); + if (FIXNUMP (number)) + return make_int (XFIXNUM (number) - 1); if (FLOATP (number)) return (make_float (-1.0 + XFLOAT_DATA (number))); - - XSETINT (number, XINT (number) - 1); - return number; + mpz_sub_ui (mpz[0], XBIGNUM (number)->value, 1); + return make_integer_mpz (); } DEFUN ("lognot", Flognot, Slognot, 1, 1, 0, doc: /* Return the bitwise complement of NUMBER. NUMBER must be an integer. */) (register Lisp_Object number) { - CHECK_NUMBER (number); - XSETINT (number, ~XINT (number)); - return number; + CHECK_INTEGER (number); + if (FIXNUMP (number)) + return make_fixnum (~XFIXNUM (number)); + mpz_com (mpz[0], XBIGNUM (number)->value); + return make_integer_mpz (); } DEFUN ("byteorder", Fbyteorder, Sbyteorder, 0, 0, 0, @@ -3154,7 +3364,7 @@ lowercase l) for small endian machines. */ unsigned i = 0x04030201; int order = *(char *)&i == 1 ? 108 : 66; - return make_number (order); + return make_fixnum (order); } /* Because we round up the bool vector allocate size to word_size @@ -3507,7 +3717,7 @@ value from A's length. */) for (i = 0; i < nwords; i++) count += count_one_bits_word (adata[i]); - return make_number (count); + return make_fixnum (count); } DEFUN ("bool-vector-count-consecutive", Fbool_vector_count_consecutive, @@ -3526,16 +3736,16 @@ A is a bool vector, B is t or nil, and I is an index into A. */) ptrdiff_t nr_words; CHECK_BOOL_VECTOR (a); - CHECK_NATNUM (i); + CHECK_FIXNAT (i); nr_bits = bool_vector_size (a); - if (XFASTINT (i) > nr_bits) /* Allow one past the end for convenience */ + if (XFIXNAT (i) > nr_bits) /* Allow one past the end for convenience */ args_out_of_range (a, i); adata = bool_vector_data (a); nr_words = bool_vector_words (nr_bits); - pos = XFASTINT (i) / BITS_PER_BITS_WORD; - offset = XFASTINT (i) % BITS_PER_BITS_WORD; + pos = XFIXNAT (i) / BITS_PER_BITS_WORD; + offset = XFIXNAT (i) % BITS_PER_BITS_WORD; count = 0; /* By XORing with twiddle, we transform the problem of "count @@ -3556,7 +3766,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) count = count_trailing_zero_bits (mword); pos++; if (count + offset < BITS_PER_BITS_WORD) - return make_number (count); + return make_fixnum (count); } /* Scan whole words until we either reach the end of the vector or @@ -3583,7 +3793,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) count -= BITS_PER_BITS_WORD - nr_bits % BITS_PER_BITS_WORD; } - return make_number (count); + return make_fixnum (count); } @@ -3626,6 +3836,7 @@ syms_of_data (void) DEFSYM (Qlistp, "listp"); DEFSYM (Qconsp, "consp"); DEFSYM (Qsymbolp, "symbolp"); + DEFSYM (Qfixnump, "fixnump"); DEFSYM (Qintegerp, "integerp"); DEFSYM (Qnatnump, "natnump"); DEFSYM (Qwholenump, "wholenump"); @@ -3830,10 +4041,6 @@ syms_of_data (void) defsubr (&Slocal_variable_p); defsubr (&Slocal_variable_if_set_p); defsubr (&Svariable_binding_locus); -#if 0 /* XXX Remove this. --lorentey */ - defsubr (&Sterminal_local_value); - defsubr (&Sset_terminal_local_value); -#endif defsubr (&Saref); defsubr (&Saset); defsubr (&Snumber_to_string); @@ -3855,7 +4062,7 @@ syms_of_data (void) defsubr (&Slogand); defsubr (&Slogior); defsubr (&Slogxor); - defsubr (&Slsh); + defsubr (&Slogcount); defsubr (&Sash); defsubr (&Sadd1); defsubr (&Ssub1); @@ -3879,15 +4086,15 @@ syms_of_data (void) set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->u.s.function); DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, - doc: /* The largest value that is representable in a Lisp integer. + doc: /* The greatest integer that is represented efficiently. This variable cannot be set; trying to do so will signal an error. */); - Vmost_positive_fixnum = make_number (MOST_POSITIVE_FIXNUM); + Vmost_positive_fixnum = make_fixnum (MOST_POSITIVE_FIXNUM); make_symbol_constant (intern_c_string ("most-positive-fixnum")); DEFVAR_LISP ("most-negative-fixnum", Vmost_negative_fixnum, - doc: /* The smallest value that is representable in a Lisp integer. + doc: /* The least integer that is represented efficiently. This variable cannot be set; trying to do so will signal an error. */); - Vmost_negative_fixnum = make_number (MOST_NEGATIVE_FIXNUM); + Vmost_negative_fixnum = make_fixnum (MOST_NEGATIVE_FIXNUM); make_symbol_constant (intern_c_string ("most-negative-fixnum")); DEFSYM (Qwatchers, "watchers"); |