0.6.7.22: removed CVS dollar-Header-dollar tags from sources
[sbcl.git] / src / code / hash-table.lisp
1 ;;;; the needed-on-the-cross-compilation-host part of HASH-TABLE
2 ;;;; implementation
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
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.
12
13 (in-package "SB!IMPL")
14
15 ;;; an internal tag for marking empty slots
16 ;;;
17 ;;; CMU CL 18b used :EMPTY for this purpose, which was somewhat nasty
18 ;;; since it's easily accessible to the user, so that e.g.
19 ;;;     (DEFVAR *HT* (MAKE-HASH-TABLE))
20 ;;;     (SETF (GETHASH :EMPTY *HT*) :EMPTY)
21 ;;;     (MAPHASH (LAMBDA (K V) (FORMAT T "~&~S ~S~%" K V)))
22 ;;; gives no output -- oops!
23 ;;;
24 ;;; Note that as of version 0.6.6 there's a dependence in the gencgc.c
25 ;;; code on this value being a symbol. (This is only one of many nasty
26 ;;; dependencies between that code and this, alas.)
27 (defconstant +empty-ht-slot+ '%empty-ht-slot%)
28 ;;; KLUDGE: Using a private symbol still leaves us vulnerable to users
29 ;;; getting nonconforming behavior by messing around with
30 ;;; DO-ALL-SYMBOLS. That seems like a fairly obscure problem, so for
31 ;;; now we just don't worry about it. If for some reason it becomes
32 ;;; worrisome and the magic value needs replacement:
33 ;;;   * The replacement value needs to be LOADable with EQL preserved,
34 ;;;     so that macroexpansion for WITH-HASH-TABLE-ITERATOR will work
35 ;;;     when compiled into a file and loaded back into SBCL.
36 ;;;     (Thus, just uninterning %EMPTY-HT-SLOT% doesn't work.)
37 ;;;   * The replacement value needs to be acceptable to the
38 ;;;     low-level gencgc.lisp hash table scavenging code. 
39 ;;;   * The change will break binary compatibility, since comparisons
40 ;;;     against the value used at the time of compilation are wired
41 ;;;     into FASL files.
42 ;;; -- WHN 20000622
43
44 ;;; HASH-TABLE is implemented as a STRUCTURE-OBJECT.
45 (sb!xc:defstruct (hash-table (:constructor %make-hash-table))
46   ;; The type of hash table this is. Only used for printing and as part of
47   ;; the exported interface.
48   (test (required-argument) :type symbol :read-only t)
49   ;; The function used to compare two keys. Returns T if they are the same
50   ;; and NIL if not.
51   (test-fun (required-argument) :type function :read-only t)
52   ;; The function used to compute the hashing of a key. Returns two values:
53   ;; the index hashing and T if that might change with the next GC.
54   (hash-fun (required-argument) :type function :read-only t)
55   ;; How much to grow the hash table by when it fills up. If an index, then
56   ;; add that amount. If a floating point number, then multiple it by that.
57   (rehash-size (required-argument) :type (or index (single-float (1.0)))
58                :read-only t)
59   ;; How full the hash table has to get before we rehash.
60   (rehash-threshold (required-argument) :type (single-float (0.0) 1.0)
61                     :read-only t)
62   ;; The number of entries before a rehash, just the one less than the
63   ;; size of the next-vector, hash-vector, and half the size of the
64   ;; kv-vector.
65   (rehash-trigger (required-argument) :type index)
66   ;; The current number of entries in the table.
67   (number-entries 0 :type index)
68   ;; The Key-Value pair vector.
69   (table (required-argument) :type simple-vector)
70   ;; True if this is a weak hash table, meaning that key->value mappings will
71   ;; disappear if there are no other references to the key. Note: this only
72   ;; matters if the hash function indicates that the hashing is EQ based.
73   (weak-p nil :type (member t nil))
74   ;; Index into the next-vector, chaining together buckets that need
75   ;; to be rehashed because their hashing is EQ based and the key has
76   ;; been moved by the garbage collector.
77   (needing-rehash 0 :type index)
78   ;; Index into the Next vector chaining together free slots in the KV
79   ;; vector.
80   (next-free-kv 0 :type index)
81   ;; The index vector. This may be larger than the hash size to help
82   ;; reduce collisions.
83   (index-vector (required-argument)
84                 :type (simple-array (unsigned-byte 32) (*)))
85   ;; This table parallels the KV vector, and is used to chain together
86   ;; the hash buckets, the free list, and the values needing rehash, a
87   ;; slot will only ever be in one of these lists.
88   (next-vector (required-argument) :type (simple-array (unsigned-byte 32) (*)))
89   ;; This table parallels the KV table, and can be used to store the
90   ;; hash associated with the key, saving recalculation. Could be
91   ;; useful for EQL, and EQUAL hash tables. This table is not needed
92   ;; for EQ hash tables, and when present the value of #x8000000
93   ;; represents EQ-based hashing on the respective Key.
94   (hash-vector nil :type (or null (simple-array (unsigned-byte 32) (*)))))
95 \f
96 (defmacro-mundanely with-hash-table-iterator ((function hash-table) &body body)
97   #!+sb-doc
98   "WITH-HASH-TABLE-ITERATOR ((function hash-table) &body body)
99    provides a method of manually looping over the elements of a hash-table.
100    FUNCTION is bound to a generator-macro that, within the scope of the
101    invocation, returns one or three values. The first value tells whether
102    any objects remain in the hash table. When the first value is non-NIL,
103    the second and third values are the key and the value of the next object."
104   (let ((n-function (gensym "WITH-HASH-TABLE-ITERATOR-")))
105     `(let ((,n-function
106             (let* ((table ,hash-table)
107                    (length (length (hash-table-next-vector table)))
108                    (index 1))
109               (declare (type (mod #.(floor most-positive-fixnum 2)) index))
110               (labels
111                   ((,function ()
112                      ;; (We grab the table again on each iteration just in
113                      ;; case it was rehashed by a PUTHASH.)
114                      (let ((kv-vector (hash-table-table table)))
115                        (do ()
116                            ((>= index length) (values nil))
117                          (let ((key (aref kv-vector (* 2 index)))
118                                (value (aref kv-vector (1+ (* 2 index)))))
119                            (incf index)
120                            (unless (and (eq key '#.+empty-ht-slot+)
121                                         (eq value '#.+empty-ht-slot+))
122                              (return (values t key value))))))))
123                 #',function))))
124       (macrolet ((,function () '(funcall ,n-function)))
125         ,@body))))