h->next = next;
}
static void
-set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
+set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val)
{
- gc_aset (h->next, idx, val);
+ gc_aset (h->next, idx, make_number (val));
}
static void
set_hash_hash (struct Lisp_Hash_Table *h, Lisp_Object hash)
h->index = index;
}
static void
-set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
+set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val)
{
- gc_aset (h->index, idx, val);
+ gc_aset (h->index, idx, make_number (val));
}
/* If OBJ is a Lisp hash table, return a pointer to its struct
/* Return a Lisp vector which has the same contents as VEC but has
at least INCR_MIN more entries, where INCR_MIN is positive.
If NITEMS_MAX is not -1, do not grow the vector to be any larger
- than NITEMS_MAX. Entries in the resulting
- vector that are not copied from VEC are set to nil. */
+ than NITEMS_MAX. New entries in the resulting vector are
+ uninitialized. */
-Lisp_Object
-larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max)
+static Lisp_Object
+larger_vecalloc (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max)
{
struct Lisp_Vector *v;
ptrdiff_t incr, incr_max, old_size, new_size;
new_size = old_size + incr;
v = allocate_vector (new_size);
memcpy (v->contents, XVECTOR (vec)->contents, old_size * sizeof *v->contents);
- memclear (v->contents + old_size, incr * word_size);
XSETVECTOR (vec, v);
return vec;
}
+/* Likewise, except set new entries in the resulting vector to nil. */
+
+Lisp_Object
+larger_vector (Lisp_Object vec, ptrdiff_t incr_min, ptrdiff_t nitems_max)
+{
+ ptrdiff_t old_size = ASIZE (vec);
+ Lisp_Object v = larger_vecalloc (vec, incr_min, nitems_max);
+ ptrdiff_t new_size = ASIZE (v);
+ memclear (XVECTOR (v)->contents + old_size,
+ (new_size - old_size) * word_size);
+ return v;
+}
+
/***********************************************************************
Low-level Functions
***********************************************************************/
+/* Return the index of the next entry in H following the one at IDX,
+ or -1 if none. */
+
+static ptrdiff_t
+HASH_NEXT (struct Lisp_Hash_Table *h, ptrdiff_t idx)
+{
+ return XINT (AREF (h->next, idx));
+}
+
+/* Return the index of the element in hash table H that is the start
+ of the collision list at index IDX, or -1 if the list is empty. */
+
+static ptrdiff_t
+HASH_INDEX (struct Lisp_Hash_Table *h, ptrdiff_t idx)
+{
+ return XINT (AREF (h->index, idx));
+}
+
/* Compare KEY1 which has hash code HASH1 and KEY2 with hash code
HASH2 in hash table H using `eql'. Value is true if KEY1 and
KEY2 are the same. */
h->count = 0;
h->key_and_value = Fmake_vector (make_number (2 * sz), Qnil);
h->hash = Fmake_vector (size, Qnil);
- h->next = Fmake_vector (size, Qnil);
- h->index = Fmake_vector (make_number (index_size), Qnil);
+ h->next = Fmake_vector (size, make_number (-1));
+ h->index = Fmake_vector (make_number (index_size), make_number (-1));
h->pure = pure;
/* Set up the free list. */
for (i = 0; i < sz - 1; ++i)
- set_hash_next_slot (h, i, make_number (i + 1));
- h->next_free = make_number (0);
+ set_hash_next_slot (h, i, i + 1);
+ h->next_free = 0;
XSET_HASH_TABLE (table, h);
eassert (HASH_TABLE_P (table));
static void
maybe_resize_hash_table (struct Lisp_Hash_Table *h)
{
- if (NILP (h->next_free))
+ if (h->next_free < 0)
{
ptrdiff_t old_size = HASH_TABLE_SIZE (h);
EMACS_INT new_size, index_size, nsize;
set_hash_key_and_value (h, larger_vector (h->key_and_value,
2 * (new_size - old_size), -1));
- set_hash_next (h, larger_vector (h->next, new_size - old_size, -1));
set_hash_hash (h, larger_vector (h->hash, new_size - old_size, -1));
- set_hash_index (h, Fmake_vector (make_number (index_size), Qnil));
+ set_hash_index (h, Fmake_vector (make_number (index_size),
+ make_number (-1)));
+ set_hash_next (h, larger_vecalloc (h->next, new_size - old_size, -1));
/* Update the free list. Do it so that new entries are added at
the end of the free list. This makes some operations like
maphash faster. */
for (i = old_size; i < new_size - 1; ++i)
- set_hash_next_slot (h, i, make_number (i + 1));
+ set_hash_next_slot (h, i, i + 1);
+ set_hash_next_slot (h, i, -1);
- if (!NILP (h->next_free))
+ if (h->next_free < 0)
+ h->next_free = old_size;
+ else
{
- Lisp_Object last, next;
-
- last = h->next_free;
- while (next = HASH_NEXT (h, XFASTINT (last)),
- !NILP (next))
- last = next;
-
- set_hash_next_slot (h, XFASTINT (last), make_number (old_size));
+ ptrdiff_t last = h->next_free;
+ while (true)
+ {
+ ptrdiff_t next = HASH_NEXT (h, last);
+ if (next < 0)
+ break;
+ last = next;
+ }
+ set_hash_next_slot (h, last, old_size);
}
- else
- XSETFASTINT (h->next_free, old_size);
/* Rehash. */
for (i = 0; i < old_size; ++i)
EMACS_UINT hash_code = XUINT (HASH_HASH (h, i));
ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index);
set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
- set_hash_index_slot (h, start_of_bucket, make_number (i));
+ set_hash_index_slot (h, start_of_bucket, i);
}
}
}
hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, EMACS_UINT *hash)
{
EMACS_UINT hash_code;
- ptrdiff_t start_of_bucket;
- Lisp_Object idx;
+ ptrdiff_t start_of_bucket, i;
hash_code = h->test.hashfn (&h->test, key);
eassert ((hash_code & ~INTMASK) == 0);
*hash = hash_code;
start_of_bucket = hash_code % ASIZE (h->index);
- idx = HASH_INDEX (h, start_of_bucket);
- while (!NILP (idx))
- {
- ptrdiff_t i = XFASTINT (idx);
- if (EQ (key, HASH_KEY (h, i))
- || (h->test.cmpfn
- && hash_code == XUINT (HASH_HASH (h, i))
- && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
- break;
- idx = HASH_NEXT (h, i);
- }
+ for (i = HASH_INDEX (h, start_of_bucket); 0 <= i; i = HASH_NEXT (h, i))
+ if (EQ (key, HASH_KEY (h, i))
+ || (h->test.cmpfn
+ && hash_code == XUINT (HASH_HASH (h, i))
+ && h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
+ break;
- return NILP (idx) ? -1 : XFASTINT (idx);
+ return i;
}
h->count++;
/* Store key/value in the key_and_value vector. */
- i = XFASTINT (h->next_free);
+ i = h->next_free;
h->next_free = HASH_NEXT (h, i);
set_hash_key_slot (h, i, key);
set_hash_value_slot (h, i, value);
/* Add new entry to its collision chain. */
start_of_bucket = hash % ASIZE (h->index);
set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
- set_hash_index_slot (h, start_of_bucket, make_number (i));
+ set_hash_index_slot (h, start_of_bucket, i);
return i;
}
void
hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key)
{
- EMACS_UINT hash_code;
- ptrdiff_t start_of_bucket;
- Lisp_Object idx, prev;
-
- hash_code = h->test.hashfn (&h->test, key);
+ EMACS_UINT hash_code = h->test.hashfn (&h->test, key);
eassert ((hash_code & ~INTMASK) == 0);
- start_of_bucket = hash_code % ASIZE (h->index);
- idx = HASH_INDEX (h, start_of_bucket);
- prev = Qnil;
+ ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index);
+ ptrdiff_t prev = -1;
- while (!NILP (idx))
+ for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket);
+ 0 <= i;
+ i = HASH_NEXT (h, i))
{
- ptrdiff_t i = XFASTINT (idx);
-
if (EQ (key, HASH_KEY (h, i))
|| (h->test.cmpfn
&& hash_code == XUINT (HASH_HASH (h, i))
&& h->test.cmpfn (&h->test, key, HASH_KEY (h, i))))
{
/* Take entry out of collision chain. */
- if (NILP (prev))
+ if (prev < 0)
set_hash_index_slot (h, start_of_bucket, HASH_NEXT (h, i));
else
- set_hash_next_slot (h, XFASTINT (prev), HASH_NEXT (h, i));
+ set_hash_next_slot (h, prev, HASH_NEXT (h, i));
/* Clear slots in key_and_value and add the slots to
the free list. */
set_hash_value_slot (h, i, Qnil);
set_hash_hash_slot (h, i, Qnil);
set_hash_next_slot (h, i, h->next_free);
- h->next_free = make_number (i);
+ h->next_free = i;
h->count--;
eassert (h->count >= 0);
break;
}
- else
- {
- prev = idx;
- idx = HASH_NEXT (h, i);
- }
+
+ prev = i;
}
}
for (i = 0; i < size; ++i)
{
- set_hash_next_slot (h, i, i < size - 1 ? make_number (i + 1) : Qnil);
+ set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1);
set_hash_key_slot (h, i, Qnil);
set_hash_value_slot (h, i, Qnil);
set_hash_hash_slot (h, i, Qnil);
}
for (i = 0; i < ASIZE (h->index); ++i)
- ASET (h->index, i, Qnil);
+ ASET (h->index, i, make_number (-1));
- h->next_free = make_number (0);
+ h->next_free = 0;
h->count = 0;
}
}
for (ptrdiff_t bucket = 0; bucket < n; ++bucket)
{
- Lisp_Object idx, next, prev;
-
/* Follow collision chain, removing entries that
don't survive this garbage collection. */
- prev = Qnil;
- for (idx = HASH_INDEX (h, bucket); !NILP (idx); idx = next)
+ ptrdiff_t prev = -1;
+ ptrdiff_t next;
+ for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next)
{
- ptrdiff_t i = XFASTINT (idx);
bool key_known_to_survive_p = survives_gc_p (HASH_KEY (h, i));
bool value_known_to_survive_p = survives_gc_p (HASH_VALUE (h, i));
bool remove_p;
if (remove_p)
{
/* Take out of collision chain. */
- if (NILP (prev))
+ if (prev < 0)
set_hash_index_slot (h, bucket, next);
else
- set_hash_next_slot (h, XFASTINT (prev), next);
+ set_hash_next_slot (h, prev, next);
/* Add to free list. */
set_hash_next_slot (h, i, h->next_free);
- h->next_free = idx;
+ h->next_free = i;
/* Clear key, value, and hash. */
set_hash_key_slot (h, i, Qnil);
}
else
{
- prev = idx;
+ prev = i;
}
}
else