Simplify, port and tune bool vector implementation.

* configure.ac (BITSIZEOF_SIZE_T, SIZEOF_SIZE_T): Remove.
* src/alloc.c (bool_vector_exact_payload_bytes)
(bool_vector_payload_bytes): Remove.
(bool_vector_fill): Return its argument.
* src/alloc.c (bool_vector_fill):
* src/lread.c (read1):
* src/print.c (print_object):
Simplify by using bool_vector_bytes.
* src/alloc.c (make_uninit_bool_vector):
New function, broken out from Fmake_bool_vector.
(Fmake_bool_vector): Use it.  Use tail call.
(make_uninit_bool_vector, vector_nbytes): Simplify size calculations.
* src/data.c (BITS_PER_ULL): New constant.
(ULLONG_MAX, count_one_bits_ll): Fall back on long counterparts
if long long versions don't exist.
(shift_right_ull): New function.
(count_one_bits_word): New function, replacing popcount_bits_word
macro.  Don't assume that bits_word is no wider than long long.
(count_one_bits_word, count_trailing_zero_bits):
Don't assume that bits_word is no wider than long long.
* src/data.c (bool_vector_binop_driver, bool_vector_not):
* src/fns.c (Fcopy_sequence):
* src/lread.c (read1):
Create an uninitialized destination, to avoid needless work.
(internal_equal): Simplify.
(Ffillarray): Prefer tail call.
* src/data.c (bool_vector_binop_driver): Don't assume bit vectors always
contain at least one word.
(bits_word_to_host_endian): Prefer if to #if.  Don't assume
chars are narrower than ints.
* src/data.c (Fbool_vector_count_matches, Fbool_vector_count_matches_at):
* src/fns.c (Fcopy_sequence):
Simplify and tune.
* src/lisp.h (bits_word, BITS_WORD_MAX, BITS_PER_BITS_WORD):
Don't try to port to hosts where bits_word values have holes; the
code wouldn't work there anyway.  Verify this assumption, though.
(bool_vector_bytes): New function.
(make_uninit_bool_vector): New decl.
(bool_vector_fill): Now returns Lisp_Object.
This commit is contained in:
Paul Eggert 2013-11-13 18:39:28 -08:00
parent d672ac3c61
commit 2cf00efc1b
9 changed files with 205 additions and 141 deletions

View file

@ -1,3 +1,8 @@
2013-11-14 Paul Eggert <eggert@cs.ucla.edu>
Simplify, port and tune bool vector implementation.
* configure.ac (BITSIZEOF_SIZE_T, SIZEOF_SIZE_T): Remove.
2013-11-13 Paul Eggert <eggert@cs.ucla.edu> 2013-11-13 Paul Eggert <eggert@cs.ucla.edu>
* Makefile.in (ACLOCAL_INPUTS): Add configure.ac. * Makefile.in (ACLOCAL_INPUTS): Add configure.ac.

View file

@ -4720,8 +4720,6 @@ LIBS="$LIB_PTHREAD $pre_PKG_CONFIG_LIBS"
gl_ASSERT_NO_GNULIB_POSIXCHECK gl_ASSERT_NO_GNULIB_POSIXCHECK
gl_ASSERT_NO_GNULIB_TESTS gl_ASSERT_NO_GNULIB_TESTS
gl_INIT gl_INIT
gl_STDINT_BITSIZEOF([size_t], [[#include <stddef.h>]])
AC_CHECK_SIZEOF([size_t])
CFLAGS=$SAVE_CFLAGS CFLAGS=$SAVE_CFLAGS
LIBS=$SAVE_LIBS LIBS=$SAVE_LIBS

View file

@ -1,5 +1,45 @@
2013-11-14 Paul Eggert <eggert@cs.ucla.edu> 2013-11-14 Paul Eggert <eggert@cs.ucla.edu>
Simplify, port and tune bool vector implementation.
* alloc.c (bool_vector_exact_payload_bytes)
(bool_vector_payload_bytes): Remove.
(bool_vector_fill): Return its argument.
* alloc.c (bool_vector_fill):
* lread.c (read1):
* print.c (print_object):
Simplify by using bool_vector_bytes.
* alloc.c (make_uninit_bool_vector):
New function, broken out from Fmake_bool_vector.
(Fmake_bool_vector): Use it. Use tail call.
(make_uninit_bool_vector, vector_nbytes): Simplify size calculations.
* data.c (BITS_PER_ULL): New constant.
(ULLONG_MAX, count_one_bits_ll): Fall back on long counterparts
if long long versions don't exist.
(shift_right_ull): New function.
(count_one_bits_word): New function, replacing popcount_bits_word
macro. Don't assume that bits_word is no wider than long long.
(count_one_bits_word, count_trailing_zero_bits):
Don't assume that bits_word is no wider than long long.
* data.c (bool_vector_binop_driver, bool_vector_not):
* fns.c (Fcopy_sequence):
* lread.c (read1):
Create an uninitialized destination, to avoid needless work.
(internal_equal): Simplify.
(Ffillarray): Prefer tail call.
* data.c (bool_vector_binop_driver): Don't assume bit vectors always
contain at least one word.
(bits_word_to_host_endian): Prefer if to #if. Don't assume
chars are narrower than ints.
* data.c (Fbool_vector_count_matches, Fbool_vector_count_matches_at):
* fns.c (Fcopy_sequence):
Simplify and tune.
* lisp.h (bits_word, BITS_WORD_MAX, BITS_PER_BITS_WORD):
Don't try to port to hosts where bits_word values have holes; the
code wouldn't work there anyway. Verify this assumption, though.
(bool_vector_bytes): New function.
(make_uninit_bool_vector): New decl.
(bool_vector_fill): Now returns Lisp_Object.
* xfns.c (xic_create_fontsetname): * xfns.c (xic_create_fontsetname):
* xrdb.c (gethomedir): Prefer tail calls. * xrdb.c (gethomedir): Prefer tail calls.

View file

@ -2041,26 +2041,10 @@ INIT must be an integer that represents a character. */)
return val; return val;
} }
static EMACS_INT /* Fill A with 1 bits if INIT is non-nil, and with 0 bits otherwise.
bool_vector_exact_payload_bytes (EMACS_INT nbits) Return A. */
{
eassume (0 <= nbits);
return (nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
}
static EMACS_INT Lisp_Object
bool_vector_payload_bytes (EMACS_INT nbits)
{
EMACS_INT exact_needed_bytes = bool_vector_exact_payload_bytes (nbits);
/* Always allocate at least one machine word of payload so that
bool-vector operations in data.c don't need a special case
for empty vectors. */
return ROUNDUP (exact_needed_bytes + !exact_needed_bytes,
sizeof (bits_word));
}
void
bool_vector_fill (Lisp_Object a, Lisp_Object init) bool_vector_fill (Lisp_Object a, Lisp_Object init)
{ {
EMACS_INT nbits = bool_vector_size (a); EMACS_INT nbits = bool_vector_size (a);
@ -2068,12 +2052,36 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init)
{ {
unsigned char *data = bool_vector_uchar_data (a); unsigned char *data = bool_vector_uchar_data (a);
int pattern = NILP (init) ? 0 : (1 << BOOL_VECTOR_BITS_PER_CHAR) - 1; int pattern = NILP (init) ? 0 : (1 << BOOL_VECTOR_BITS_PER_CHAR) - 1;
ptrdiff_t nbytes = ((nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) ptrdiff_t nbytes = bool_vector_bytes (nbits);
/ BOOL_VECTOR_BITS_PER_CHAR);
int last_mask = ~ (~0 << ((nbits - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)); int last_mask = ~ (~0 << ((nbits - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1));
memset (data, pattern, nbytes - 1); memset (data, pattern, nbytes - 1);
data[nbytes - 1] = pattern & last_mask; data[nbytes - 1] = pattern & last_mask;
} }
return a;
}
/* Return a newly allocated, uninitialized bool vector of size NBITS. */
Lisp_Object
make_uninit_bool_vector (EMACS_INT nbits)
{
Lisp_Object val;
struct Lisp_Bool_Vector *p;
EMACS_INT word_bytes, needed_elements;
word_bytes = bool_vector_words (nbits) * sizeof (bits_word);
needed_elements = ((bool_header_size - header_size + word_bytes
+ word_size - 1)
/ word_size);
p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements);
XSETVECTOR (val, p);
XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0);
p->size = nbits;
/* Clear padding at the end. */
if (nbits)
p->data[bool_vector_words (nbits) - 1] = 0;
return val;
} }
DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
@ -2082,32 +2090,10 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */)
(Lisp_Object length, Lisp_Object init) (Lisp_Object length, Lisp_Object init)
{ {
Lisp_Object val; Lisp_Object val;
struct Lisp_Bool_Vector *p;
EMACS_INT exact_payload_bytes, total_payload_bytes, needed_elements;
CHECK_NATNUM (length); CHECK_NATNUM (length);
val = make_uninit_bool_vector (XFASTINT (length));
exact_payload_bytes = bool_vector_exact_payload_bytes (XFASTINT (length)); return bool_vector_fill (val, init);
total_payload_bytes = bool_vector_payload_bytes (XFASTINT (length));
needed_elements = ((bool_header_size - header_size + total_payload_bytes
+ word_size - 1)
/ word_size);
p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements);
XSETVECTOR (val, p);
XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0);
p->size = XFASTINT (length);
bool_vector_fill (val, init);
/* Clear padding at the end. */
eassume (exact_payload_bytes <= total_payload_bytes);
memset (bool_vector_uchar_data (val) + exact_payload_bytes,
0,
total_payload_bytes - exact_payload_bytes);
return val;
} }
@ -2858,24 +2844,27 @@ static ptrdiff_t
vector_nbytes (struct Lisp_Vector *v) vector_nbytes (struct Lisp_Vector *v)
{ {
ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG; ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG;
ptrdiff_t nwords;
if (size & PSEUDOVECTOR_FLAG) if (size & PSEUDOVECTOR_FLAG)
{ {
if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR))
{ {
struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v;
ptrdiff_t payload_bytes = bool_vector_payload_bytes (bv->size); ptrdiff_t word_bytes = (bool_vector_words (bv->size)
size = bool_header_size + payload_bytes; * sizeof (bits_word));
ptrdiff_t boolvec_bytes = bool_header_size + word_bytes;
verify (header_size <= bool_header_size);
nwords = (boolvec_bytes - header_size + word_size - 1) / word_size;
} }
else else
size = (header_size nwords = ((size & PSEUDOVECTOR_SIZE_MASK)
+ ((size & PSEUDOVECTOR_SIZE_MASK) + ((size & PSEUDOVECTOR_REST_MASK)
+ ((size & PSEUDOVECTOR_REST_MASK) >> PSEUDOVECTOR_SIZE_BITS));
>> PSEUDOVECTOR_SIZE_BITS)) * word_size);
} }
else else
size = header_size + size * word_size; nwords = size;
return vroundup (size); return vroundup (header_size + word_size * nwords);
} }
/* Release extra resources still in use by VECTOR, which may be any /* Release extra resources still in use by VECTOR, which may be any

View file

@ -2962,9 +2962,7 @@ lowercase l) for small endian machines. */)
/* Because we round up the bool vector allocate size to word_size /* Because we round up the bool vector allocate size to word_size
units, we can safely read past the "end" of the vector in the units, we can safely read past the "end" of the vector in the
operations below. These extra bits are always zero. Also, we operations below. These extra bits are always zero. */
always allocate bool vectors with at least one bits_word of storage so
that we don't have to special-case empty bit vectors. */
static bits_word static bits_word
bool_vector_spare_mask (EMACS_INT nr_bits) bool_vector_spare_mask (EMACS_INT nr_bits)
@ -2972,16 +2970,47 @@ bool_vector_spare_mask (EMACS_INT nr_bits)
return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1; return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1;
} }
#if BITS_WORD_MAX <= UINT_MAX /* Info about unsigned long long, falling back on unsigned long
# define popcount_bits_word count_one_bits if unsigned long long is not available. */
#elif BITS_WORD_MAX <= ULONG_MAX
# define popcount_bits_word count_one_bits_l #if HAVE_UNSIGNED_LONG_LONG_INT
#elif BITS_WORD_MAX <= ULLONG_MAX enum { BITS_PER_ULL = CHAR_BIT * sizeof (unsigned long long) };
# define popcount_bits_word count_one_bits_ll
#else #else
# error "bits_word wider than long long? Please file a bug report." enum { BITS_PER_ULL = CHAR_BIT * sizeof (unsigned long) };
# define ULLONG_MAX ULONG_MAX
# define count_one_bits_ll count_one_bits_l
#endif #endif
/* Shift VAL right by the width of an unsigned long long.
BITS_PER_ULL must be less than BITS_PER_BITS_WORD. */
static bits_word
shift_right_ull (bits_word w)
{
/* Pacify bogus GCC warning about shift count exceeding type width. */
int shift = BITS_PER_ULL - BITS_PER_BITS_WORD < 0 ? BITS_PER_ULL : 0;
return w >> shift;
}
/* Return the number of 1 bits in W. */
static int
count_one_bits_word (bits_word w)
{
if (BITS_WORD_MAX <= UINT_MAX)
return count_one_bits (w);
else if (BITS_WORD_MAX <= ULONG_MAX)
return count_one_bits_l (w);
else
{
int i = 0, count = 0;
while (count += count_one_bits_ll (w),
BITS_PER_BITS_WORD <= (i += BITS_PER_ULL))
w = shift_right_ull (w);
return count;
}
}
enum bool_vector_op { bool_vector_exclusive_or, enum bool_vector_op { bool_vector_exclusive_or,
bool_vector_union, bool_vector_union,
bool_vector_intersection, bool_vector_intersection,
@ -2997,7 +3026,7 @@ bool_vector_binop_driver (Lisp_Object op1,
EMACS_INT nr_bits; EMACS_INT nr_bits;
bits_word *adata, *bdata, *cdata; bits_word *adata, *bdata, *cdata;
ptrdiff_t i; ptrdiff_t i;
bits_word changed = 0; bool changed = 0;
bits_word mword; bits_word mword;
ptrdiff_t nr_words; ptrdiff_t nr_words;
@ -3010,7 +3039,7 @@ bool_vector_binop_driver (Lisp_Object op1,
if (NILP (dest)) if (NILP (dest))
{ {
dest = Fmake_bool_vector (make_number (nr_bits), Qnil); dest = make_uninit_bool_vector (nr_bits);
changed = 1; changed = 1;
} }
else else
@ -3025,8 +3054,8 @@ bool_vector_binop_driver (Lisp_Object op1,
adata = bool_vector_data (dest); adata = bool_vector_data (dest);
bdata = bool_vector_data (op1); bdata = bool_vector_data (op1);
cdata = bool_vector_data (op2); cdata = bool_vector_data (op2);
i = 0;
do for (i = 0; i < nr_words; i++)
{ {
if (op == bool_vector_exclusive_or) if (op == bool_vector_exclusive_or)
mword = bdata[i] ^ cdata[i]; mword = bdata[i] ^ cdata[i];
@ -3039,14 +3068,12 @@ bool_vector_binop_driver (Lisp_Object op1,
else else
abort (); abort ();
changed |= adata[i] ^ mword; if (! changed)
changed = adata[i] != mword;
if (op != bool_vector_subsetp) if (op != bool_vector_subsetp)
adata[i] = mword; adata[i] = mword;
i++;
} }
while (i < nr_words);
return changed ? dest : Qnil; return changed ? dest : Qnil;
} }
@ -3060,27 +3087,33 @@ count_trailing_zero_bits (bits_word val)
return count_trailing_zeros (val); return count_trailing_zeros (val);
if (BITS_WORD_MAX == ULONG_MAX) if (BITS_WORD_MAX == ULONG_MAX)
return count_trailing_zeros_l (val); return count_trailing_zeros_l (val);
# if HAVE_UNSIGNED_LONG_LONG_INT
if (BITS_WORD_MAX == ULLONG_MAX) if (BITS_WORD_MAX == ULLONG_MAX)
return count_trailing_zeros_ll (val); return count_trailing_zeros_ll (val);
# endif
/* The rest of this code is for the unlikely platform where bits_word differs /* The rest of this code is for the unlikely platform where bits_word differs
in width from unsigned int, unsigned long, and unsigned long long. */ in width from unsigned int, unsigned long, and unsigned long long. */
if (val == 0) val |= ~ BITS_WORD_MAX;
return CHAR_BIT * sizeof (val);
if (BITS_WORD_MAX <= UINT_MAX) if (BITS_WORD_MAX <= UINT_MAX)
return count_trailing_zeros (val); return count_trailing_zeros (val);
if (BITS_WORD_MAX <= ULONG_MAX) if (BITS_WORD_MAX <= ULONG_MAX)
return count_trailing_zeros_l (val); return count_trailing_zeros_l (val);
{ else
# if HAVE_UNSIGNED_LONG_LONG_INT {
verify (BITS_WORD_MAX <= ULLONG_MAX); int count;
return count_trailing_zeros_ll (val); for (count = 0;
# else count < BITS_PER_BITS_WORD - BITS_PER_ULL;
verify (BITS_WORD_MAX <= ULONG_MAX); count += BITS_PER_ULL)
# endif {
} if (val & ULLONG_MAX)
return count + count_trailing_zeros_ll (val);
val = shift_right_ull (val);
}
if (BITS_PER_BITS_WORD % BITS_PER_ULL != 0
&& BITS_WORD_MAX == (bits_word) -1)
val |= (bits_word) 1 << (BITS_PER_BITS_WORD % BITS_PER_ULL);
return count + count_trailing_zeros_ll (val);
}
} }
static bits_word static bits_word
@ -3088,20 +3121,24 @@ bits_word_to_host_endian (bits_word val)
{ {
#ifndef WORDS_BIGENDIAN #ifndef WORDS_BIGENDIAN
return val; return val;
#elif BITS_WORD_MAX >> 31 == 1
return bswap_32 (val);
#elif BITS_WORD_MAX >> 31 >> 31 >> 1 == 1
return bswap_64 (val);
#else #else
int i; if (BITS_WORD_MAX >> 31 == 1)
bits_word r = 0; return bswap_32 (val);
for (i = 0; i < sizeof val; i++) # if HAVE_UNSIGNED_LONG_LONG
{ if (BITS_WORD_MAX >> 31 >> 31 >> 1 == 1)
r = ((r << 1 << (CHAR_BIT - 1)) return bswap_64 (val);
| (val & ((1u << 1 << (CHAR_BIT - 1)) - 1))); # endif
val = val >> 1 >> (CHAR_BIT - 1); {
} int i;
return r; bits_word r = 0;
for (i = 0; i < sizeof val; i++)
{
r = ((r << 1 << (CHAR_BIT - 1))
| (val & ((1u << 1 << (CHAR_BIT - 1)) - 1)));
val = val >> 1 >> (CHAR_BIT - 1);
}
return r;
}
#endif #endif
} }
@ -3174,7 +3211,7 @@ Return the destination vector. */)
nr_bits = bool_vector_size (a); nr_bits = bool_vector_size (a);
if (NILP (b)) if (NILP (b))
b = Fmake_bool_vector (make_number (nr_bits), Qnil); b = make_uninit_bool_vector (nr_bits);
else else
{ {
CHECK_BOOL_VECTOR (b); CHECK_BOOL_VECTOR (b);
@ -3208,27 +3245,20 @@ A must be a bool vector. B is a generalized bool. */)
EMACS_INT count; EMACS_INT count;
EMACS_INT nr_bits; EMACS_INT nr_bits;
bits_word *adata; bits_word *adata;
bits_word match; ptrdiff_t i, nwords;
ptrdiff_t i;
CHECK_BOOL_VECTOR (a); CHECK_BOOL_VECTOR (a);
nr_bits = bool_vector_size (a); nr_bits = bool_vector_size (a);
nwords = bool_vector_words (nr_bits);
count = 0; count = 0;
match = NILP (b) ? BITS_WORD_MAX : 0;
adata = bool_vector_data (a); adata = bool_vector_data (a);
for (i = 0; i < nr_bits / BITS_PER_BITS_WORD; ++i) for (i = 0; i < nwords; i++)
count += popcount_bits_word (adata[i] ^ match); count += count_one_bits_word (adata[i]);
/* Mask out trailing parts of final mword. */
if (nr_bits % BITS_PER_BITS_WORD)
{
bits_word mword = adata[i] ^ match;
mword = bits_word_to_host_endian (mword);
count += popcount_bits_word (mword & bool_vector_spare_mask (nr_bits));
}
if (NILP (b))
count = nr_bits - count;
return make_number (count); return make_number (count);
} }
@ -3246,7 +3276,7 @@ index into the vector. */)
bits_word *adata; bits_word *adata;
bits_word twiddle; bits_word twiddle;
bits_word mword; /* Machine word. */ bits_word mword; /* Machine word. */
ptrdiff_t pos; ptrdiff_t pos, pos0;
ptrdiff_t nr_words; ptrdiff_t nr_words;
CHECK_BOOL_VECTOR (a); CHECK_BOOL_VECTOR (a);
@ -3273,8 +3303,8 @@ index into the vector. */)
mword = bits_word_to_host_endian (adata[pos]); mword = bits_word_to_host_endian (adata[pos]);
mword ^= twiddle; mword ^= twiddle;
mword >>= offset; mword >>= offset;
mword |= (bits_word) 1 << (BITS_PER_BITS_WORD - offset);
count = count_trailing_zero_bits (mword); count = count_trailing_zero_bits (mword);
count = min (count, BITS_PER_BITS_WORD - offset);
pos++; pos++;
if (count + offset < BITS_PER_BITS_WORD) if (count + offset < BITS_PER_BITS_WORD)
return make_number (count); return make_number (count);
@ -3283,11 +3313,10 @@ index into the vector. */)
/* Scan whole words until we either reach the end of the vector or /* Scan whole words until we either reach the end of the vector or
find an mword that doesn't completely match. twiddle is find an mword that doesn't completely match. twiddle is
endian-independent. */ endian-independent. */
pos0 = pos;
while (pos < nr_words && adata[pos] == twiddle) while (pos < nr_words && adata[pos] == twiddle)
{ pos++;
count += BITS_PER_BITS_WORD; count += (pos - pos0) * BITS_PER_BITS_WORD;
++pos;
}
if (pos < nr_words) if (pos < nr_words)
{ {

View file

@ -435,13 +435,10 @@ with the original. */)
if (BOOL_VECTOR_P (arg)) if (BOOL_VECTOR_P (arg))
{ {
Lisp_Object val; EMACS_INT nbits = bool_vector_size (arg);
ptrdiff_t size_in_chars ptrdiff_t nbytes = bool_vector_bytes (nbits);
= ((bool_vector_size (arg) + BOOL_VECTOR_BITS_PER_CHAR - 1) Lisp_Object val = make_uninit_bool_vector (nbits);
/ BOOL_VECTOR_BITS_PER_CHAR); memcpy (bool_vector_data (val), bool_vector_data (arg), nbytes);
val = Fmake_bool_vector (Flength (arg), Qnil);
memcpy (bool_vector_data (val), bool_vector_data (arg), size_in_chars);
return val; return val;
} }
@ -2066,8 +2063,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props)
if (size != bool_vector_size (o2)) if (size != bool_vector_size (o2))
return 0; return 0;
if (memcmp (bool_vector_data (o1), bool_vector_data (o2), if (memcmp (bool_vector_data (o1), bool_vector_data (o2),
((size + BOOL_VECTOR_BITS_PER_CHAR - 1) bool_vector_bytes (size)))
/ BOOL_VECTOR_BITS_PER_CHAR)))
return 0; return 0;
return 1; return 1;
} }
@ -2157,7 +2153,7 @@ ARRAY is a vector, string, char-table, or bool-vector. */)
p[idx] = charval; p[idx] = charval;
} }
else if (BOOL_VECTOR_P (array)) else if (BOOL_VECTOR_P (array))
bool_vector_fill (array, item); return bool_vector_fill (array, item);
else else
wrong_type_argument (Qarrayp, array); wrong_type_argument (Qarrayp, array);
return array; return array;

View file

@ -92,16 +92,16 @@ enum { BOOL_VECTOR_BITS_PER_CHAR =
/* An unsigned integer type representing a fixed-length bit sequence, /* An unsigned integer type representing a fixed-length bit sequence,
suitable for words in a Lisp bool vector. Normally it is size_t suitable for words in a Lisp bool vector. Normally it is size_t
for speed, but it is unsigned char on weird platforms. */ for speed, but it is unsigned char on weird platforms. */
#if (BITSIZEOF_SIZE_T == CHAR_BIT * SIZEOF_SIZE_T \ #if BOOL_VECTOR_BITS_PER_CHAR == CHAR_BIT
&& BOOL_VECTOR_BITS_PER_CHAR == CHAR_BIT)
typedef size_t bits_word; typedef size_t bits_word;
#define BITS_WORD_MAX SIZE_MAX # define BITS_WORD_MAX SIZE_MAX
enum { BITS_PER_BITS_WORD = CHAR_BIT * sizeof (bits_word) }; enum { BITS_PER_BITS_WORD = CHAR_BIT * sizeof (bits_word) };
#else #else
typedef unsigned char bits_word; typedef unsigned char bits_word;
#define BITS_WORD_MAX ((1u << BOOL_VECTOR_BITS_PER_CHAR) - 1) # define BITS_WORD_MAX ((1u << BOOL_VECTOR_BITS_PER_CHAR) - 1)
enum { BITS_PER_BITS_WORD = BOOL_VECTOR_BITS_PER_CHAR }; enum { BITS_PER_BITS_WORD = BOOL_VECTOR_BITS_PER_CHAR };
#endif #endif
verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
/* Number of bits in some machine integer types. */ /* Number of bits in some machine integer types. */
enum enum
@ -1212,7 +1212,9 @@ struct Lisp_Bool_Vector
struct vectorlike_header header; struct vectorlike_header header;
/* This is the size in bits. */ /* This is the size in bits. */
EMACS_INT size; EMACS_INT size;
/* This contains the actual bits, packed into bytes. */ /* The actual bits, packed into bytes.
The bits are in little-endian order in the bytes, and
the bytes are in little-endian order in the words. */
bits_word data[FLEXIBLE_ARRAY_MEMBER]; bits_word data[FLEXIBLE_ARRAY_MEMBER];
}; };
@ -1236,7 +1238,7 @@ bool_vector_uchar_data (Lisp_Object a)
return (unsigned char *) bool_vector_data (a); return (unsigned char *) bool_vector_data (a);
} }
/* The number of data words in a bool vector with SIZE bits. */ /* The number of data words and bytes in a bool vector with SIZE bits. */
INLINE EMACS_INT INLINE EMACS_INT
bool_vector_words (EMACS_INT size) bool_vector_words (EMACS_INT size)
@ -1245,6 +1247,13 @@ bool_vector_words (EMACS_INT size)
return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD; return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
} }
INLINE EMACS_INT
bool_vector_bytes (EMACS_INT size)
{
eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
}
/* True if A's Ith bit is set. */ /* True if A's Ith bit is set. */
INLINE bool INLINE bool
@ -3588,7 +3597,8 @@ list4i (EMACS_INT x, EMACS_INT y, EMACS_INT w, EMACS_INT h)
make_number (w), make_number (h)); make_number (w), make_number (h));
} }
extern void bool_vector_fill (Lisp_Object, Lisp_Object); extern Lisp_Object make_uninit_bool_vector (EMACS_INT);
extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object);
extern _Noreturn void string_overflow (void); extern _Noreturn void string_overflow (void);
extern Lisp_Object make_string (const char *, ptrdiff_t); extern Lisp_Object make_string (const char *, ptrdiff_t);
extern Lisp_Object make_formatted_string (char *, const char *, ...) extern Lisp_Object make_formatted_string (char *, const char *, ...)

View file

@ -2577,9 +2577,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
if (c == '"') if (c == '"')
{ {
Lisp_Object tmp, val; Lisp_Object tmp, val;
EMACS_INT size_in_chars EMACS_INT size_in_chars = bool_vector_bytes (XFASTINT (length));
= ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1)
/ BOOL_VECTOR_BITS_PER_CHAR);
unsigned char *data; unsigned char *data;
UNREAD (c); UNREAD (c);
@ -2594,7 +2592,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
== (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
invalid_syntax ("#&..."); invalid_syntax ("#&...");
val = Fmake_bool_vector (length, Qnil); val = make_uninit_bool_vector (XFASTINT (length));
data = bool_vector_uchar_data (val); data = bool_vector_uchar_data (val);
memcpy (data, SDATA (tmp), size_in_chars); memcpy (data, SDATA (tmp), size_in_chars);
/* Clear the extraneous bits in the last byte. */ /* Clear the extraneous bits in the last byte. */

View file

@ -1705,8 +1705,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
unsigned char c; unsigned char c;
struct gcpro gcpro1; struct gcpro gcpro1;
EMACS_INT size = bool_vector_size (obj); EMACS_INT size = bool_vector_size (obj);
ptrdiff_t size_in_chars = ((size + BOOL_VECTOR_BITS_PER_CHAR - 1) ptrdiff_t size_in_chars = bool_vector_bytes (size);
/ BOOL_VECTOR_BITS_PER_CHAR);
ptrdiff_t real_size_in_chars = size_in_chars; ptrdiff_t real_size_in_chars = size_in_chars;
GCPRO1 (obj); GCPRO1 (obj);