1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-04-25 07:40:40 -07:00

Alternative implementation for weak hash tables

It can be enabled with -DUSE_EPHEMERON_POOL.

This variant uses the ephemeron pool and hence sovles the key-in-value
problem.

This version stores key/values pairs a vector-of-pairs instead of a
pair-of-vectors.  The same vector-of-pairs type is used for weak and
non-weak.  This avoids the code duplication used by the pair-of-vector
version; though it adds a bit of overhead to the non-weak code path.

* src/lisp.h: (struct vector_pair [!USE_EPHEMERON_POOL]): New type.
(struct pair_vector [USE_EPHEMERON_POOL]):New type.
(hash_table_kv): New typedef used to both version.
(hash_table_kv_create, hash_table_kv_free, hash_table_kv_key)
(hash_table_kv_value, hash_table_kv_set_key, hash_table_kv_set_value)
(hash_table_kv_null): New helpers
(struct Lisp_Hash_Table): Use a single field kv of type hash_table_kv
instead of two fields.
(HASH_KEY, HASH_VALUE, WEAK_HASH_KEY, WEAK_HASH_VALUE, DOHASH)
(DOHASH_WEAK, set_hash_key_slot, set_hash_value_slot)
(set_weak_hash_key_slot, set_weak_hash_value_slot): Adapt to
hash_table_kv.
(DOHASH [USE_EPHEMERON_POOL]): New version.
* src/igc.h (enum igc_obj_type): Add IGC_OBJ_PAIR_VECTOR,
IGC_OBJ_WEAK_KEY_PAIR_VECTOR, IGC_OBJ_WEAK_VALUE_PAIR_VECTOR,
IGC_OBJ_WEAK_OR_PAIR_VECTOR.
(igc_alloc_pair_vector): New prototype.
* src/igc.c (obj_type_names, set_header, dflt_scan_obj, thread_ap):
Handle new tpes.
(struct igc_thread, create_ephemeron_ap, create_thread_aps)
(igc_thread_remove): Add allocation point for ephemeron pool.
(struct igc, make_pool_aeph, make_igc): Add ephemeron pool.
(as_igc_header, fix_pair_vector, decode_ptr, encode_ptr)
(increment_ndeleted, splat_pair, fix_weak_key_pair, fix_weak_value_pair)
(fix_weak_or_pair, fix_weak_and_pair, scan_pair_vector)
(fix_weak_key_pair_vector, fix_weak_value_pair_vector)
(fix_weak_or_pair_vector, fix_weak_and_pair_vector): New helpers.
(fix_hash_table, fix_weak_hash_table_strong_part)
(fix_weak_hash_table_weak_part): Adapt to hash_table_kv.
(igc_alloc_pair_vector): New function.
* src/fns.c (maybe_resize_hash_table): Call maybe_resize_hash_table.
(Fgethash): Add assertion for HASH_UNUSED_ENTRY_KEY.
(Fhash_table_count): Take deleted entries into account.
(hash_table_kv_init, hash_table_kv_create)
(hash_table_kv_resize, hash_table_kv_free): New helpers.
(hash_table_kv_ndeleted, hash_table_ndeleted)
(hash_table_count, reclaim_deleted_entries)
(maybe_reclaim_deleted_entries): New helpers.
(make_hash_table, copy_hash_table, hash_table_thaw, hash_table_rehash)
(allocate_weak_hash_table_parts, make_weak_hash_table)
(maybe_resize_weak_hash_table): Adapt to hash_table_kv.
* src/alloc.c (cleanup_vector): Adapt to hash_table_kv.
* src/pdumper.c (hash_table_contents, hash_table_freeze)
(dump_hash_table): Adapt to hash_table_kv.
(dump_hash_table_kv_slot, dump_hash_table_kv, dump_hash_table_kv_part):
New helpers.
* src/print.c (print_object): Use Fhash_table_count instead
of the h->count field.
* test/src/fns-tests.el (ft--check-entries): Check hash-table-count.
(ft-weak-fixnums2, ft--test-weak-fixnums2): New test.
(ft--test-ephemeron-table): Better check for hash-table-count.
This commit is contained in:
Helmut Eller 2026-02-02 22:29:19 +01:00
parent c067ff171e
commit b3ee5b351e
10 changed files with 992 additions and 164 deletions

View file

@ -1307,7 +1307,8 @@
(cl-loop for (k1 . v1) in expected
for (k2 . v2) in actual
do (ft--check-entry w k1 v1 k2 v2))
(should (= (length expected) (length actual)))))
(should (= (length expected) (length actual)))
(should (= (hash-table-count table) (length expected)))))
(defun ft--gc (weakness)
(cond ((fboundp 'igc--collect)
@ -1388,6 +1389,23 @@
(dolist (test '(eq eql equal))
(ft--test-weak-fixnums w test))))
(defun ft--test-weak-fixnums2 (weakness test)
(let ((h (make-hash-table :weakness weakness :test test)))
(dotimes (i 3)
(cl-ecase i
(#b00 (dotimes (i 10)
(puthash i (lognot i) h)))
(#b01 (dotimes (i 10)
(puthash i (cons nil nil) h)))
(#b10 (dotimes (i 10)
(puthash (cons nil nil) i h)))))
(ft--gc weakness)))
(ert-deftest ft-weak-fixnums2 ()
(dolist (w '(key value key-and-value key-or-value))
(dolist (test '(eq eql equal))
(ft--test-weak-fixnums2 w test))))
(defun ft--test-ephemeron-table (weakness)
(let* ((h (make-hash-table :weakness weakness :test 'eq))
(n 1000))
@ -1395,6 +1413,7 @@
(let* ((obj (cons 'a i)))
(puthash obj obj h)))
(ft--gc weakness)
(should (< (length (ft--hash-table-entries h)) n))
(should (< (hash-table-count h) n))))
(ert-deftest ft-ephemeron-table ()