summaryrefslogtreecommitdiff
path: root/src/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/data.c')
-rw-r--r--src/data.c1017
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");