aboutsummaryrefslogtreecommitdiffstats
path: root/src/fns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c53
1 files changed, 33 insertions, 20 deletions
diff --git a/src/fns.c b/src/fns.c
index efec74d4959..74fdf29417e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4474,7 +4474,7 @@ hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h)
4474/* Given H, return a hash code for KEY which uses a user-defined 4474/* Given H, return a hash code for KEY which uses a user-defined
4475 function to compare keys. */ 4475 function to compare keys. */
4476 4476
4477Lisp_Object 4477static Lisp_Object
4478hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h) 4478hashfn_user_defined (Lisp_Object key, struct Lisp_Hash_Table *h)
4479{ 4479{
4480 Lisp_Object args[] = { h->test.user_hash_function, key }; 4480 Lisp_Object args[] = { h->test.user_hash_function, key };
@@ -4638,11 +4638,10 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
4638 if (h->next_free < 0) 4638 if (h->next_free < 0)
4639 { 4639 {
4640 ptrdiff_t old_size = HASH_TABLE_SIZE (h); 4640 ptrdiff_t old_size = HASH_TABLE_SIZE (h);
4641 EMACS_INT new_size; 4641 /* FIXME: better growth management, ditch std_rehash_size */
4642 4642 EMACS_INT new_size = old_size * std_rehash_size;
4643 double float_new_size = old_size * std_rehash_size; 4643 if (new_size < EMACS_INT_MAX)
4644 if (float_new_size < EMACS_INT_MAX) 4644 new_size = max (new_size, 32); /* avoid slow initial growth */
4645 new_size = float_new_size;
4646 else 4645 else
4647 new_size = EMACS_INT_MAX; 4646 new_size = EMACS_INT_MAX;
4648 if (PTRDIFF_MAX < new_size) 4647 if (PTRDIFF_MAX < new_size)
@@ -4691,20 +4690,39 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
4691 } 4690 }
4692} 4691}
4693 4692
4694/* Recompute the hashes (and hence also the "next" pointers). 4693static const struct hash_table_test *
4695 Normally there's never a need to recompute hashes. 4694hash_table_test_from_std (hash_table_std_test_t test)
4696 This is done only on first access to a hash-table loaded from 4695{
4697 the "pdump", because the objects' addresses may have changed, thus 4696 switch (test)
4698 affecting their hashes. */ 4697 {
4698 case Test_eq: return &hashtest_eq;
4699 case Test_eql: return &hashtest_eql;
4700 case Test_equal: return &hashtest_equal;
4701 }
4702 emacs_abort();
4703}
4704
4705/* Rebuild a hash table from its frozen (dumped) form. */
4699void 4706void
4700hash_table_rehash (Lisp_Object hash) 4707hash_table_thaw (Lisp_Object hash_table)
4701{ 4708{
4702 struct Lisp_Hash_Table *h = XHASH_TABLE (hash); 4709 struct Lisp_Hash_Table *h = XHASH_TABLE (hash_table);
4703 ptrdiff_t i, count = h->count; 4710
4711 /* Freezing discarded most non-essential information; recompute it.
4712 The allocation is minimal with no room for growth. */
4713 h->test = *hash_table_test_from_std (h->frozen_test);
4714 ptrdiff_t size = ASIZE (h->key_and_value) / 2;
4715 h->count = size;
4716 ptrdiff_t index_size = hash_index_size (size);
4717 h->next_free = -1;
4718
4719 h->hash = make_nil_vector (size);
4720 h->next = make_vector (size, make_fixnum (-1));
4721 h->index = make_vector (index_size, make_fixnum (-1));
4704 4722
4705 /* Recompute the actual hash codes for each entry in the table. 4723 /* Recompute the actual hash codes for each entry in the table.
4706 Order is still invalid. */ 4724 Order is still invalid. */
4707 for (i = 0; i < count; i++) 4725 for (ptrdiff_t i = 0; i < size; i++)
4708 { 4726 {
4709 Lisp_Object key = HASH_KEY (h, i); 4727 Lisp_Object key = HASH_KEY (h, i);
4710 Lisp_Object hash_code = hash_from_key (h, key); 4728 Lisp_Object hash_code = hash_from_key (h, key);
@@ -4712,12 +4730,7 @@ hash_table_rehash (Lisp_Object hash)
4712 set_hash_hash_slot (h, i, hash_code); 4730 set_hash_hash_slot (h, i, hash_code);
4713 set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket)); 4731 set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
4714 set_hash_index_slot (h, start_of_bucket, i); 4732 set_hash_index_slot (h, start_of_bucket, i);
4715 eassert (HASH_NEXT (h, i) != i); /* Stop loops. */
4716 } 4733 }
4717
4718 ptrdiff_t size = ASIZE (h->next);
4719 for (; i + 1 < size; i++)
4720 set_hash_next_slot (h, i, i + 1);
4721} 4734}
4722 4735
4723/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH 4736/* Lookup KEY in hash table H. If HASH is non-null, return in *HASH