1 ;;;; that part of the implementation of HASH-TABLE which lives solely
2 ;;;; on the target system, not on the cross-compilation host
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 (in-package "SB!IMPL")
17 ;;; Code for detecting concurrent accesses to the same table from
18 ;;; multiple threads. Only compiled in when the :SB-HASH-TABLE-DEBUG
19 ;;; feature is enabled. The main reason for the existence of this code
20 ;;; is to detect thread-unsafe uses of hash-tables in sbcl itself,
21 ;;; where debugging anythign can be impossible after an important
22 ;;; internal hash-table has been corrupted. It's plausible that this
23 ;;; could be useful for some user code too, but the runtime cost is
24 ;;; really too high to enable it by default.
25 (defmacro with-concurrent-access-check
(hash-table operation
&body body
)
26 (declare (ignorable hash-table operation
)
27 (type (member :read
:write
) operation
))
28 #!-sb-hash-table-debug
30 #!+sb-hash-table-debug
31 (let ((thread-slot-accessor (if (eq operation
:read
)
32 'hash-table-reading-thread
33 'hash-table-writing-thread
)))
34 (once-only ((hash-table hash-table
))
39 ;; Don't signal more errors for this table.
40 (setf (hash-table-signal-concurrent-access ,hash-table
) nil
)
41 (cerror "Ignore the concurrent access"
42 "Concurrent access to ~A" ,hash-table
)))
43 (declare (inline body-fun
))
44 (if (hash-table-signal-concurrent-access ,hash-table
)
47 (unless (and (null (hash-table-writing-thread
49 ,@(when (eq operation
:write
)
50 `((null (hash-table-reading-thread
53 (setf (,thread-slot-accessor
,hash-table
)
54 sb
!thread
::*current-thread
*)
56 (unless (and ,@(when (eq operation
:read
)
57 `((null (hash-table-writing-thread
59 ,@(when (eq operation
:write
)
60 ;; no readers are allowed while writing
61 `((null (hash-table-reading-thread
63 (eq (hash-table-writing-thread
65 sb
!thread
::*current-thread
*))))
67 (when (eq (,thread-slot-accessor
,hash-table
)
68 sb
!thread
::*current-thread
*)
69 ;; this is not 100% correct here and may hide
70 ;; concurrent access in rare circumstances.
71 (setf (,thread-slot-accessor
,hash-table
) nil
)))
74 #!-sb-fluid
(declaim (inline eq-hash
))
76 (declare (values hash
(member t nil
)))
77 (values (pointer-hash key
)
78 (oddp (get-lisp-obj-address key
))))
80 #!-sb-fluid
(declaim (inline equal-hash
))
81 (defun equal-hash (key)
82 (declare (values hash
(member t nil
)))
84 ;; For some types the definition of EQUAL implies a special hash
85 ((or string cons number bit-vector pathname
)
86 (values (sxhash key
) nil
))
87 ;; Otherwise use an EQ hash, rather than SXHASH, since the values
88 ;; of SXHASH will be extremely badly distributed due to the
89 ;; requirements of the spec fitting badly with our implementation
94 #!-sb-fluid
(declaim (inline eql-hash
))
96 (declare (values hash
(member t nil
)))
101 (defun equalp-hash (key)
102 (declare (values hash
(member t nil
)))
104 ;; Types requiring special treatment. Note that PATHNAME and
105 ;; HASH-TABLE are caught by the STRUCTURE-OBJECT test.
106 ((or array cons number character structure-object
)
107 (values (psxhash key
) nil
))
111 (declaim (inline index-for-hashing
))
112 (defun index-for-hashing (hash length
)
113 (declare (type hash hash length
))
114 ;; We're using power of two tables which obviously are very
115 ;; sensitive to the exact values of the low bits in the hash
116 ;; value. Do a little shuffling of the value to mix the high bits in
120 (+ (logxor #b11100101010001011010100111
127 ;;;; user-defined hash table tests
129 (defvar *hash-table-tests
* nil
)
131 (defun define-hash-table-test (name test-fun hash-fun
)
133 "Define a new kind of hash table test."
134 (declare (type symbol name
)
135 (type function test-fun hash-fun
))
136 (setf *hash-table-tests
*
137 (cons (list name test-fun hash-fun
)
138 (remove name
*hash-table-tests
* :test
#'eq
:key
#'car
)))
141 ;;;; construction and simple accessors
143 (defconstant +min-hash-table-size
+ 16)
144 (defconstant +min-hash-table-rehash-threshold
+ (float 1/16 1.0))
146 (defun make-hash-table (&key
(test 'eql
)
147 (size +min-hash-table-size
+)
153 "Create and return a new hash table. The keywords are as follows:
154 :TEST -- Indicates what kind of test to use.
155 :SIZE -- A hint as to how many elements will be put in this hash
157 :REHASH-SIZE -- Indicates how to expand the table when it fills up.
158 If an integer, add space for that many elements. If a floating
159 point number (which must be greater than 1.0), multiply the size
161 :REHASH-THRESHOLD -- Indicates how dense the table can become before
162 forcing a rehash. Can be any positive number <=1, with density
163 approaching zero as the threshold approaches 0. Density 1 means an
164 average of one entry per bucket.
165 :WEAKNESS -- If NIL (the default) it is a normal non-weak hash table.
166 If one of :KEY, :VALUE, :KEY-AND-VALUE, :KEY-OR-VALUE it is a weak
168 Depending on the type of weakness the lack of references to the
169 key and the value may allow for removal of the entry. If WEAKNESS
170 is :KEY and the key would otherwise be garbage the entry is eligible
171 for removal from the hash table. Similarly, if WEAKNESS is :VALUE
172 the life of an entry depends on its value's references. If WEAKNESS
173 is :KEY-AND-VALUE and either the key or the value would otherwise be
174 garbage the entry can be removed. If WEAKNESS is :KEY-OR-VALUE and
175 both the key and the value would otherwise be garbage the entry can
177 :SYNCHRONIZED -- If NIL (the default), the hash-table may have
178 multiple concurrent readers, but results are undefined if a
179 thread writes to the hash-table concurrently with another
180 reader or writer. If T, all concurrent accesses are safe, but
181 note that CLHS 3.6 (Traversal Rules and Side Effects) remains
182 in force. See also: SB-EXT:WITH-LOCKED-HASH-TABLE. This keyword
183 argument is experimental, and may change incompatibly or be
184 removed in the future."
185 (declare (type (or function symbol
) test
))
186 (declare (type unsigned-byte size
))
187 (multiple-value-bind (test test-fun hash-fun
)
188 (cond ((or (eq test
#'eq
) (eq test
'eq
))
189 (values 'eq
#'eq
#'eq-hash
))
190 ((or (eq test
#'eql
) (eq test
'eql
))
191 (values 'eql
#'eql
#'eql-hash
))
192 ((or (eq test
#'equal
) (eq test
'equal
))
193 (values 'equal
#'equal
#'equal-hash
))
194 ((or (eq test
#'equalp
) (eq test
'equalp
))
195 (values 'equalp
#'equalp
#'equalp-hash
))
197 ;; FIXME: I'd like to remove *HASH-TABLE-TESTS* stuff.
198 ;; Failing that, I'd like to rename it to
199 ;; *USER-HASH-TABLE-TESTS*.
200 (dolist (info *hash-table-tests
*
201 (error "unknown :TEST for MAKE-HASH-TABLE: ~S"
203 (destructuring-bind (test-name test-fun hash-fun
) info
204 (when (or (eq test test-name
) (eq test test-fun
))
205 (return (values test-name test-fun hash-fun
)))))))
206 (let* ((size (max +min-hash-table-size
+
208 ;; SIZE is just a hint, so if the user asks
209 ;; for a SIZE which'd be too big for us to
210 ;; easily implement, we bump it down.
211 (floor array-dimension-limit
1024))))
212 (rehash-size (if (integerp rehash-size
)
214 (float rehash-size
1.0)))
215 ;; FIXME: Original REHASH-THRESHOLD default should be 1.0,
216 ;; not 1, to make it easier for the compiler to avoid
218 (rehash-threshold (max +min-hash-table-rehash-threshold
+
219 (float rehash-threshold
1.0)))
220 (size+1 (1+ size
)) ; The first element is not usable.
221 ;; KLUDGE: The most natural way of expressing the below is
222 ;; (round (/ (float size+1) rehash-threshold)), and indeed
223 ;; it was expressed like that until 0.7.0. However,
224 ;; MAKE-HASH-TABLE is called very early in cold-init, and
225 ;; the SPARC has no primitive instructions for rounding,
226 ;; but only for truncating; therefore, we fudge this issue
227 ;; a little. The other uses of truncate, below, similarly
228 ;; used to be round. -- CSR, 2002-10-01
230 ;; Note that this has not yet been audited for
231 ;; correctness. It just seems to work. -- CSR, 2002-11-02
232 (scaled-size (truncate (/ (float size
+1) rehash-threshold
)))
233 (length (power-of-two-ceiling (max scaled-size
234 (1+ +min-hash-table-size
+))))
235 (index-vector (make-array length
237 '(unsigned-byte #.sb
!vm
:n-word-bits
)
239 ;; Needs to be the half the length of the KV vector to link
240 ;; KV entries - mapped to indeces at 2i and 2i+1 -
242 (next-vector (make-array size
+1
244 '(unsigned-byte #.sb
!vm
:n-word-bits
)))
245 (kv-vector (make-array (* 2 size
+1)
246 :initial-element
+empty-ht-slot
+))
247 (table (%make-hash-table
251 :rehash-size rehash-size
252 :rehash-threshold rehash-threshold
256 :index-vector index-vector
257 :next-vector next-vector
259 (unless (eq test
'eq
)
261 :element-type
'(unsigned-byte
263 :initial-element
+magic-hash-vector-value
+))
264 :synchronized-p synchronized
)))
265 (declare (type index size
+1 scaled-size length
))
266 ;; Set up the free list, all free. These lists are 0 terminated.
269 (setf (aref next-vector i
) (1+ i
)))
270 (setf (aref next-vector size
) 0)
271 (setf (hash-table-next-free-kv table
) 1)
272 (setf (aref kv-vector
0) table
)
275 (defun hash-table-count (hash-table)
277 "Return the number of entries in the given HASH-TABLE."
278 (declare (type hash-table hash-table
)
280 (hash-table-number-entries hash-table
))
283 (setf (fdocumentation 'hash-table-rehash-size
'function
)
284 "Return the rehash-size HASH-TABLE was created with.")
287 (setf (fdocumentation 'hash-table-rehash-threshold
'function
)
288 "Return the rehash-threshold HASH-TABLE was created with.")
290 (defun hash-table-size (hash-table)
292 "Return a size that can be used with MAKE-HASH-TABLE to create a hash
293 table that can hold however many entries HASH-TABLE can hold without
295 (hash-table-rehash-trigger hash-table
))
298 (setf (fdocumentation 'hash-table-test
'function
)
299 "Return the test HASH-TABLE was created with.")
302 (setf (fdocumentation 'hash-table-weakness
'function
)
303 "Return the WEAKNESS of HASH-TABLE which is one of NIL, :KEY,
304 :VALUE, :KEY-AND-VALUE, :KEY-OR-VALUE.")
306 ;;; Called when we detect circular chains in a hash-table.
307 (defun signal-corrupt-hash-table (hash-table)
308 (error "Corrupt NEXT-chain in ~A. This is probably caused by ~
309 multiple threads accessing the same hash-table without locking."
313 ;;;; accessing functions
315 ;;; Make new vectors for the table, extending the table based on the
317 (defun rehash (table)
318 (declare (type hash-table table
))
320 (let* ((old-kv-vector (hash-table-table table
))
321 (old-next-vector (hash-table-next-vector table
))
322 (old-hash-vector (hash-table-hash-vector table
))
323 (old-size (length old-next-vector
))
325 (power-of-two-ceiling
326 (let ((rehash-size (hash-table-rehash-size table
)))
327 (etypecase rehash-size
329 (+ rehash-size old-size
))
331 (the index
(truncate (* rehash-size old-size
))))))))
332 (new-kv-vector (make-array (* 2 new-size
)
333 :initial-element
+empty-ht-slot
+))
336 :element-type
'(unsigned-byte #.sb
!vm
:n-word-bits
)
339 (when old-hash-vector
341 :element-type
'(unsigned-byte #.sb
!vm
:n-word-bits
)
342 :initial-element
+magic-hash-vector-value
+)))
343 (new-length new-size
)
345 (make-array new-length
346 :element-type
'(unsigned-byte #.sb
!vm
:n-word-bits
)
347 :initial-element
0)))
348 (declare (type index new-size new-length old-size
))
350 ;; Disable GC tricks on the OLD-KV-VECTOR.
351 (set-header-data old-kv-vector sb
!vm
:vector-normal-subtype
)
353 ;; Non-empty weak hash tables always need GC support.
354 (when (and (hash-table-weakness table
) (plusp (hash-table-count table
)))
355 (set-header-data new-kv-vector sb
!vm
:vector-valid-hashing-subtype
))
357 ;; FIXME: here and in several other places in the hash table code,
358 ;; loops like this one are used when FILL or REPLACE would be
359 ;; appropriate. why are standard CL functions not used?
360 ;; Performance issues? General laziness? -- NJF, 2004-03-10
362 ;; Copy over the kv-vector. The element positions should not move
363 ;; in case there are active scans.
364 (dotimes (i (* old-size
2))
365 (declare (type index i
))
366 (setf (aref new-kv-vector i
) (aref old-kv-vector i
)))
368 ;; Copy over the hash-vector.
369 (when old-hash-vector
370 (dotimes (i old-size
)
371 (setf (aref new-hash-vector i
) (aref old-hash-vector i
))))
373 (setf (hash-table-next-free-kv table
) 0)
374 ;; Rehash all the entries; last to first so that after the pushes
375 ;; the chains are first to last.
376 (do ((i (1- new-size
) (1- i
)))
378 (declare (type index
/2 i
))
379 (let ((key (aref new-kv-vector
(* 2 i
)))
380 (value (aref new-kv-vector
(1+ (* 2 i
)))))
381 (cond ((and (eq key
+empty-ht-slot
+)
382 (eq value
+empty-ht-slot
+))
383 ;; Slot is empty, push it onto the free list.
384 (setf (aref new-next-vector i
)
385 (hash-table-next-free-kv table
))
386 (setf (hash-table-next-free-kv table
) i
))
387 ((and new-hash-vector
388 (not (= (aref new-hash-vector i
)
389 +magic-hash-vector-value
+)))
390 ;; Can use the existing hash value (not EQ based)
391 (let* ((hashing (aref new-hash-vector i
))
392 (index (index-for-hashing hashing new-length
))
393 (next (aref new-index-vector index
)))
394 (declare (type index index
)
396 ;; Push this slot into the next chain.
397 (setf (aref new-next-vector i
) next
)
398 (setf (aref new-index-vector index
) i
)))
402 (set-header-data new-kv-vector
403 sb
!vm
:vector-valid-hashing-subtype
)
404 (let* ((hashing (pointer-hash key
))
405 (index (index-for-hashing hashing new-length
))
406 (next (aref new-index-vector index
)))
407 (declare (type index index
)
409 ;; Push this slot onto the next chain.
410 (setf (aref new-next-vector i
) next
)
411 (setf (aref new-index-vector index
) i
))))))
412 (setf (hash-table-table table
) new-kv-vector
)
413 (setf (hash-table-index-vector table
) new-index-vector
)
414 (setf (hash-table-next-vector table
) new-next-vector
)
415 (setf (hash-table-hash-vector table
) new-hash-vector
)
416 ;; Fill the old kv-vector with 0 to help the conservative GC. Even
417 ;; if nothing else were zeroed, it's important to clear the
418 ;; special first cells in old-kv-vector.
419 (fill old-kv-vector
0)
420 (setf (hash-table-rehash-trigger table
) new-size
)
421 (setf (hash-table-needs-rehash-p table
) nil
))
424 ;;; Use the same size as before, re-using the vectors.
425 (defun rehash-without-growing (table)
426 (declare (type hash-table table
))
428 (let* ((kv-vector (hash-table-table table
))
429 (next-vector (hash-table-next-vector table
))
430 (hash-vector (hash-table-hash-vector table
))
431 (size (length next-vector
))
432 (index-vector (hash-table-index-vector table
))
433 (length (length index-vector
)))
434 (declare (type index size length
))
436 ;; Non-empty weak hash tables always need GC support.
437 (unless (and (hash-table-weakness table
) (plusp (hash-table-count table
)))
438 ;; Disable GC tricks, they will be re-enabled during the re-hash
440 (set-header-data kv-vector sb
!vm
:vector-normal-subtype
))
442 ;; Rehash all the entries.
443 (setf (hash-table-next-free-kv table
) 0)
445 (setf (aref next-vector i
) 0))
447 (setf (aref index-vector i
) 0))
448 (do ((i (1- size
) (1- i
)))
450 (declare (type index
/2 i
))
451 (let ((key (aref kv-vector
(* 2 i
)))
452 (value (aref kv-vector
(1+ (* 2 i
)))))
453 (cond ((and (eq key
+empty-ht-slot
+)
454 (eq value
+empty-ht-slot
+))
455 ;; Slot is empty, push it onto free list.
456 (setf (aref next-vector i
) (hash-table-next-free-kv table
))
457 (setf (hash-table-next-free-kv table
) i
))
458 ((and hash-vector
(not (= (aref hash-vector i
)
459 +magic-hash-vector-value
+)))
460 ;; Can use the existing hash value (not EQ based)
461 (let* ((hashing (aref hash-vector i
))
462 (index (index-for-hashing hashing length
))
463 (next (aref index-vector index
)))
464 (declare (type index index
))
465 ;; Push this slot into the next chain.
466 (setf (aref next-vector i
) next
)
467 (setf (aref index-vector index
) i
)))
471 (set-header-data kv-vector sb
!vm
:vector-valid-hashing-subtype
)
472 (let* ((hashing (pointer-hash key
))
473 (index (index-for-hashing hashing length
))
474 (next (aref index-vector index
)))
475 (declare (type index index
)
477 ;; Push this slot into the next chain.
478 (setf (aref next-vector i
) next
)
479 (setf (aref index-vector index
) i
)))))))
480 ;; Clear the rehash bit only at the very end, otherwise another thread
481 ;; might see a partially rehashed table as a normal one.
482 (setf (hash-table-needs-rehash-p table
) nil
)
485 (declaim (inline maybe-rehash
))
486 (defun maybe-rehash (hash-table ensure-free-slot-p
)
487 (when (hash-table-weakness hash-table
)
490 (and ensure-free-slot-p
491 (zerop (hash-table-next-free-kv hash-table
))))
492 (rehash-without-growing-p ()
493 (hash-table-needs-rehash-p hash-table
)))
494 (declare (inline rehash-p rehash-without-growing-p
))
496 ;; Use recursive spinlocks since for weak tables the
497 ;; spinlock has already been acquired. GC must be inhibited
498 ;; to prevent the GC from seeing a rehash in progress.
499 (sb!thread
::with-recursive-system-spinlock
500 ((hash-table-spinlock hash-table
) :without-gcing t
)
501 ;; Repeat the condition inside the lock to ensure that if
502 ;; two reader threads enter MAYBE-REHASH at the same time
503 ;; only one rehash is performed.
505 (rehash hash-table
))))
506 ((rehash-without-growing-p)
507 (sb!thread
::with-recursive-system-spinlock
508 ((hash-table-spinlock hash-table
) :without-gcing t
)
509 (when (rehash-without-growing-p)
510 (rehash-without-growing hash-table
)))))))
512 (declaim (inline update-hash-table-cache
))
513 (defun update-hash-table-cache (hash-table index
)
514 (unless (hash-table-weakness hash-table
)
515 (setf (hash-table-cache hash-table
) index
)))
517 (defmacro with-hash-table-locks
((hash-table
518 &key
(operation :write
) inline pin
519 (synchronized `(hash-table-synchronized-p ,hash-table
)))
521 (declare (type (member :read
:write
) operation
))
522 (with-unique-names (body-fun)
523 `(with-concurrent-access-check ,hash-table
,operation
525 (locally (declare (inline ,@inline
))
527 (if (hash-table-weakness ,hash-table
)
528 (sb!thread
::with-recursive-system-spinlock
529 ((hash-table-spinlock ,hash-table
) :without-gcing t
)
531 (with-pinned-objects ,pin
533 ;; We use a "system" spinlock here because it is very
534 ;; slightly faster, as it doesn't re-enable interrupts.
535 (sb!thread
::with-recursive-system-spinlock
536 ((hash-table-spinlock ,hash-table
))
540 (defun gethash (key hash-table
&optional default
)
542 "Finds the entry in HASH-TABLE whose key is KEY and returns the
543 associated value and T as multiple values, or returns DEFAULT and NIL
544 if there is no such entry. Entries can be added using SETF."
545 (declare (type hash-table hash-table
)
546 (values t
(member t nil
)))
547 (gethash3 key hash-table default
))
549 (declaim (maybe-inline %gethash3
))
550 (defun %gethash3
(key hash-table default
)
551 (declare (type hash-table hash-table
)
553 (values t
(member t nil
)))
556 (let ((start-epoch sb
!kernel
::*gc-epoch
*))
557 (macrolet ((result (value foundp
)
558 ;; When the table has multiple concurrent readers,
559 ;; it's possible that there was a GC after this
560 ;; thread called MAYBE-REHASH from %GETHASH3, and
561 ;; some other thread then rehashed the table. If
562 ;; this happens, we might not find the key even if
563 ;; it's in the table. To protect against this,
564 ;; redo the lookup if the GC epoch counter has changed.
565 ;; -- JES, 2007-09-30
566 `(if (and (not ,foundp
)
567 (not (eql start-epoch sb
!kernel
::*gc-epoch
*)))
569 (return-from %gethash3
(values ,value
,foundp
))))
571 ;; The next-vector chain is circular. This is caused
572 ;; caused by thread-unsafe mutations of the table.
573 `(signal-corrupt-hash-table hash-table
)))
574 (maybe-rehash hash-table nil
)
575 ;; Note that it's OK for a GC + a REHASH-WITHOUT-GROWING to
576 ;; be triggered by another thread after this point, since the
577 ;; GC epoch check will catch it.
578 (let ((cache (hash-table-cache hash-table
))
579 (table (hash-table-table hash-table
)))
580 ;; First check the cache. Use EQ here for speed.
582 (< cache
(length table
))
583 (eq (aref table cache
) key
))
584 (let ((value (aref table
(1+ cache
))))
586 ;; Search for key in the hash table.
587 (multiple-value-bind (hashing eq-based
)
588 (funcall (hash-table-hash-fun hash-table
) key
)
589 (declare (type hash hashing
))
590 (let* ((index-vector (hash-table-index-vector hash-table
))
591 (length (length index-vector
))
592 (index (index-for-hashing hashing length
))
593 (next (aref index-vector index
))
594 (next-vector (hash-table-next-vector hash-table
))
595 (hash-vector (hash-table-hash-vector hash-table
))
596 (test-fun (hash-table-test-fun hash-table
)))
597 (declare (type index index
))
598 ;; Search next-vector chain for a matching key.
599 (if (or eq-based
(not hash-vector
))
600 (do ((next next
(aref next-vector next
))
602 ((zerop next
) (result default nil
))
603 (declare (type index
/2 next i
))
606 (when (eq key
(aref table
(* 2 next
)))
607 (update-hash-table-cache hash-table
(* 2 next
))
608 (let ((value (aref table
(1+ (* 2 next
)))))
610 (do ((next next
(aref next-vector next
))
612 ((zerop next
) (result default nil
))
613 (declare (type index
/2 next i
))
616 (when (and (= hashing
(aref hash-vector next
))
617 (funcall test-fun key
618 (aref table
(* 2 next
))))
620 (update-hash-table-cache hash-table
(* 2 next
))
621 (let ((value (aref table
(1+ (* 2 next
)))))
622 (result value t
)))))))))))))
624 (defun gethash3 (key hash-table default
)
625 "Three argument version of GETHASH"
626 (declare (type hash-table hash-table
))
627 (with-hash-table-locks (hash-table :operation
:read
:inline
(%gethash3
)
629 (%gethash3 key hash-table default
)))
631 ;;; so people can call #'(SETF GETHASH)
632 (defun (setf gethash
) (new-value key table
&optional default
)
633 (declare (ignore default
))
634 (%puthash key table new-value
))
636 (declaim (maybe-inline %%puthash
))
637 (defun %%puthash
(key hash-table value
)
638 (declare (optimize speed
))
639 ;; We need to rehash here so that a current key can be found if it
640 ;; exists. Check that there is room for one more entry. May not be
641 ;; needed if the key is already present.
642 (maybe-rehash hash-table t
)
643 ;; Search for key in the hash table.
644 (multiple-value-bind (hashing eq-based
)
645 (funcall (hash-table-hash-fun hash-table
) key
)
646 (declare (type hash hashing
))
647 (let* ((index-vector (hash-table-index-vector hash-table
))
648 (length (length index-vector
))
649 (index (index-for-hashing hashing length
))
650 (next (aref index-vector index
))
651 (kv-vector (hash-table-table hash-table
))
652 (next-vector (hash-table-next-vector hash-table
))
653 (hash-vector (hash-table-hash-vector hash-table
))
654 (test-fun (hash-table-test-fun hash-table
)))
655 (declare (type index index next
))
656 (when (hash-table-weakness hash-table
)
657 (set-header-data kv-vector sb
!vm
:vector-valid-hashing-subtype
))
658 (cond ((or eq-based
(not hash-vector
))
660 (set-header-data kv-vector
661 sb
!vm
:vector-valid-hashing-subtype
))
662 ;; Search next-vector chain for a matching key.
663 (do ((next next
(aref next-vector next
))
666 (declare (type index
/2 next i
))
668 (signal-corrupt-hash-table hash-table
))
669 (when (eq key
(aref kv-vector
(* 2 next
)))
670 ;; Found, just replace the value.
671 (update-hash-table-cache hash-table
(* 2 next
))
672 (setf (aref kv-vector
(1+ (* 2 next
))) value
)
673 (return-from %%puthash value
))))
675 ;; Search next-vector chain for a matching key.
676 (do ((next next
(aref next-vector next
))
679 (declare (type index
/2 next i
))
681 (signal-corrupt-hash-table hash-table
))
682 (when (and (= hashing
(aref hash-vector next
))
683 (funcall test-fun key
684 (aref kv-vector
(* 2 next
))))
685 ;; Found, just replace the value.
686 (update-hash-table-cache hash-table
(* 2 next
))
687 (setf (aref kv-vector
(1+ (* 2 next
))) value
)
688 (return-from %%puthash value
)))))
689 ;; Pop a KV slot off the free list
690 (let ((free-kv-slot (hash-table-next-free-kv hash-table
)))
691 (declare (type index
/2 free-kv-slot
))
692 ;; Double-check for overflow.
693 (aver (not (zerop free-kv-slot
)))
694 (setf (hash-table-next-free-kv hash-table
)
695 (aref next-vector free-kv-slot
))
696 (incf (hash-table-number-entries hash-table
))
697 (update-hash-table-cache hash-table
(* 2 free-kv-slot
))
698 (setf (aref kv-vector
(* 2 free-kv-slot
)) key
)
699 (setf (aref kv-vector
(1+ (* 2 free-kv-slot
))) value
)
700 ;; Setup the hash-vector if necessary.
703 (setf (aref hash-vector free-kv-slot
) hashing
)
704 (aver (= (aref hash-vector free-kv-slot
)
705 +magic-hash-vector-value
+))))
706 ;; Push this slot into the next chain.
707 (setf (aref next-vector free-kv-slot
) next
)
708 (setf (aref index-vector index
) free-kv-slot
)))
711 (defun %puthash
(key hash-table value
)
712 (declare (type hash-table hash-table
))
713 (aver (hash-table-index-vector hash-table
))
714 (macrolet ((put-it (lockedp)
715 `(let ((cache (hash-table-cache hash-table
))
716 (kv-vector (hash-table-table hash-table
)))
719 (< cache
(length kv-vector
))
720 (eq (aref kv-vector cache
) key
))
721 ;; If cached, just store here
722 (setf (aref kv-vector
(1+ cache
)) value
)
723 ;; Otherwise do things the hard way
725 '(%%puthash key hash-table value
)
726 '(with-hash-table-locks
727 (hash-table :inline
(%%puthash
) :pin
(key)
729 (%%puthash key hash-table value
)))))))
730 (if (hash-table-synchronized-p hash-table
)
731 (with-hash-table-locks (hash-table :pin
(key) :synchronized t
)
735 (declaim (maybe-inline %remhash
))
736 (defun %remhash
(key hash-table
)
737 ;; We need to rehash here so that a current key can be found if it
740 ;; Note that if a GC happens after MAYBE-REHASH returns and another
741 ;; thread the accesses the table (triggering a rehash), we might not
742 ;; find the key even if it is in the table. But that's ok, since the
743 ;; only concurrent case that we safely allow is multiple readers
745 (maybe-rehash hash-table nil
)
746 ;; Search for key in the hash table.
747 (multiple-value-bind (hashing eq-based
)
748 (funcall (hash-table-hash-fun hash-table
) key
)
749 (declare (type hash hashing
))
750 (let* ((index-vector (hash-table-index-vector hash-table
))
751 (length (length index-vector
))
752 (index (index-for-hashing hashing length
))
753 (next (aref index-vector index
))
754 (table (hash-table-table hash-table
))
755 (next-vector (hash-table-next-vector hash-table
))
756 (hash-vector (hash-table-hash-vector hash-table
))
757 (test-fun (hash-table-test-fun hash-table
)))
758 (declare (type index index
)
760 (flet ((clear-slot (chain-vector prior-slot-location slot-location
)
761 (declare (type index
/2 slot-location
))
762 ;; Mark slot as empty.
763 (setf (aref table
(* 2 slot-location
)) +empty-ht-slot
+
764 (aref table
(1+ (* 2 slot-location
))) +empty-ht-slot
+)
765 ;; Update the prior pointer in the chain to skip this.
766 (setf (aref chain-vector prior-slot-location
)
767 (aref next-vector slot-location
))
768 ;; Push KV slot onto free chain.
769 (setf (aref next-vector slot-location
)
770 (hash-table-next-free-kv hash-table
))
771 (setf (hash-table-next-free-kv hash-table
) slot-location
)
773 (setf (aref hash-vector slot-location
)
774 +magic-hash-vector-value
+))
775 ;; On parallel accesses this may turn out to be a
776 ;; type-error, so don't turn down the safety!
777 (decf (hash-table-number-entries hash-table
))
781 ((if (or eq-based
(not hash-vector
))
782 (eq key
(aref table
(* 2 next
)))
783 (and (= hashing
(aref hash-vector next
))
784 (funcall test-fun key
(aref table
(* 2 next
)))))
785 (clear-slot index-vector index next
))
786 ;; Search next-vector chain for a matching key.
787 ((or eq-based
(not hash-vector
))
789 (do ((prior next next
)
791 (next (aref next-vector next
) (aref next-vector next
)))
793 (declare (type index next
))
795 (signal-corrupt-hash-table hash-table
))
796 (when (eq key
(aref table
(* 2 next
)))
797 (return-from %remhash
(clear-slot next-vector prior next
)))))
800 (do ((prior next next
)
802 (next (aref next-vector next
) (aref next-vector next
)))
804 (declare (type index
/2 next
))
806 (signal-corrupt-hash-table hash-table
))
807 (when (and (= hashing
(aref hash-vector next
))
808 (funcall test-fun key
(aref table
(* 2 next
))))
809 (return-from %remhash
810 (clear-slot next-vector prior next
))))))))))
812 (defun remhash (key hash-table
)
814 "Remove the entry in HASH-TABLE associated with KEY. Return T if
815 there was such an entry, or NIL if not."
816 (declare (type hash-table hash-table
)
817 (values (member t nil
)))
818 (with-hash-table-locks (hash-table :inline
(%remhash
) :pin
(key))
819 ;; For now, just clear the cache
820 (setf (hash-table-cache hash-table
) nil
)
821 (%remhash key hash-table
)))
823 (defun clrhash (hash-table)
825 "This removes all the entries from HASH-TABLE and returns the hash
827 (when (plusp (hash-table-number-entries hash-table
))
828 (with-hash-table-locks (hash-table)
829 (let* ((kv-vector (hash-table-table hash-table
))
830 (next-vector (hash-table-next-vector hash-table
))
831 (hash-vector (hash-table-hash-vector hash-table
))
832 (size (length next-vector
))
833 (index-vector (hash-table-index-vector hash-table
)))
834 ;; Disable GC tricks.
835 (set-header-data kv-vector sb
!vm
:vector-normal-subtype
)
836 ;; Mark all slots as empty by setting all keys and values to magic
838 (aver (eq (aref kv-vector
0) hash-table
))
839 (fill kv-vector
+empty-ht-slot
+ :start
2)
840 ;; Set up the free list, all free.
843 (setf (aref next-vector i
) (1+ i
)))
844 (setf (aref next-vector
(1- size
)) 0)
845 (setf (hash-table-next-free-kv hash-table
) 1)
846 ;; Clear the index-vector.
847 (fill index-vector
0)
848 ;; Clear the hash-vector.
850 (fill hash-vector
+magic-hash-vector-value
+)))
851 (setf (hash-table-cache hash-table
) nil
)
852 (setf (hash-table-number-entries hash-table
) 0)))
858 ;;; FIXME: This should be made into a compiler transform for two reasons:
859 ;;; 1. It would then be available for compiling the entire system,
860 ;;; not only parts of the system which are defined after DEFUN MAPHASH.
861 ;;; 2. It could be conditional on compilation policy, so that
862 ;;; it could be compiled as a full call instead of an inline
863 ;;; expansion when SPACE>SPEED.
864 (declaim (inline maphash
))
865 (defun maphash (function-designator hash-table
)
867 "For each entry in HASH-TABLE, call the designated two-argument function on
868 the key and value of the entry. Return NIL.
870 Consequences are undefined if HASH-TABLE is mutated during the call to
871 MAPHASH, except for changing or removing elements corresponding to the
872 current key. The applies to all threads, not just the current one --
873 even for synchronized hash-tables. If the table may be mutated by
874 another thread during iteration, use eg. SB-EXT:WITH-LOCKED-HASH-TABLE
875 to protect the MAPHASH call."
876 ;; This essentially duplicates WITH-HASH-TABLE-ITERATOR, so
877 ;; any changes here should be reflected there as well.
878 (let ((fun (%coerce-callable-to-fun function-designator
))
879 (size (length (hash-table-next-vector hash-table
))))
880 (declare (type function fun
))
883 (declare (type index
/2 i
))
884 (let* ((kv-vector (hash-table-table hash-table
))
885 (key (aref kv-vector
(* 2 i
)))
886 (value (aref kv-vector
(1+ (* 2 i
)))))
887 ;; We are running without locking or WITHOUT-GCING. For a weak
888 ;; :VALUE hash table it's possible that the GC hit after KEY
889 ;; was read and now the entry is gone. So check if either the
890 ;; key or the value is empty.
891 (unless (or (eq key
+empty-ht-slot
+)
892 (eq value
+empty-ht-slot
+))
893 (funcall fun key value
))))))
895 ;;;; methods on HASH-TABLE
897 ;;; Return a list of keyword args and values to use for MAKE-HASH-TABLE
898 ;;; when reconstructing HASH-TABLE.
899 (defun %hash-table-ctor-args
(hash-table)
900 `(:test
',(hash-table-test hash-table
)
901 :size
',(hash-table-size hash-table
)
902 :rehash-size
',(hash-table-rehash-size hash-table
)
903 :rehash-threshold
',(hash-table-rehash-threshold hash-table
)
904 :weakness
',(hash-table-weakness hash-table
)))
906 ;;; Return an association list representing the same data as HASH-TABLE.
907 (defun %hash-table-alist
(hash-table)
909 (maphash (lambda (key value
)
910 (push (cons key value
) result
))
914 ;;; Stuff an association list into HASH-TABLE. Return the hash table,
915 ;;; so that we can use this for the *PRINT-READABLY* case in
916 ;;; PRINT-OBJECT (HASH-TABLE T) without having to worry about LET
917 ;;; forms and readable gensyms and stuff.
918 (defun %stuff-hash-table
(hash-table alist
)
920 (setf (gethash (car x
) hash-table
) (cdr x
)))
923 (def!method print-object
((hash-table hash-table
) stream
)
924 (declare (type stream stream
))
925 (cond ((or (not *print-readably
*) (not *read-eval
*))
926 (print-unreadable-object (hash-table stream
:type t
:identity t
)
928 ":TEST ~S :COUNT ~S~@[ :WEAKNESS ~S~]"
929 (hash-table-test hash-table
)
930 (hash-table-count hash-table
)
931 (hash-table-weakness hash-table
))))
933 (write-string "#." stream
)
934 (write `(%stuff-hash-table
(make-hash-table ,@(%hash-table-ctor-args
936 ',(%hash-table-alist hash-table
))
939 (def!method make-load-form
((hash-table hash-table
) &optional environment
)
940 (declare (ignore environment
))
941 (values `(make-hash-table ,@(%hash-table-ctor-args hash-table
))
942 `(%stuff-hash-table
,hash-table
',(%hash-table-alist hash-table
))))