4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
35 * HASHSET is hash table managing pointers to a set of keys
36 * (set is a collection without duplicates). The public interface
37 * of the HASHSET is similar to the java.util.Set interface.
38 * Unlike the libc `hsearch' based hash table, this implementation
39 * does allow multiple instances of HASHSET within a single application,
40 * and the HASHSET_ITERATOR allows to iterate through the entire set
43 * HASHSET does not store actual keys but only pointers to keys. Hence the
44 * data remains intact when HASHSET grows (resizes itself). HASHSET accesses
45 * the actual key data only through the hash and equal functions given
46 * as arguments to h_create.
48 * Hash collisions are resolved with linked lists.
51 typedef struct HashSetEntry
{
52 uint_t e_hash
; /* Hash value */
53 const void *e_key
; /* Pointer to a key */
54 struct HashSetEntry
*e_next
;
58 ENTRY
**h_table
; /* Pointer to an array of ENTRY'ies */
59 uint_t h_tableSize
; /* Size of the array */
60 uint_t h_count
; /* Current count */
61 uint_t h_threshold
; /* loadFactor threshold */
62 float h_loadFactor
; /* Current loadFactor (h_count/h_tableSize( */
63 uint_t (*h_hash
) (const void *);
64 int (*h_equal
) (const void *, const void *);
67 struct HashSetIterator
{
74 static void rehash(HASHSET h
);
76 #define DEFAULT_INITIALCAPACITY 1
77 #define DEFAULT_LOADFACTOR 0.75
81 * - HASHSET is a hash table of pointers to keys
82 * - duplicate keys are not allowed
83 * - the HASHSET is opaque and can be accessed only through the h_ functions
84 * - two keys k1 and k2 are considered equal if the result of equal(k1, k2)
86 * - the function hash(key) is used to compute hash values for keys; if
87 * keys are "equal" the values returned by the hash function must be
92 h_create(uint_t (*hash
) (const void *),
93 int (*equal
) (const void *, const void *),
94 uint_t initialCapacity
,
99 if (initialCapacity
== 0)
100 initialCapacity
= DEFAULT_INITIALCAPACITY
;
102 if (loadFactor
< 0.0)
103 loadFactor
= DEFAULT_LOADFACTOR
;
105 h
= exmalloc(sizeof (*h
));
110 h
->h_table
= exmalloc(initialCapacity
* sizeof (ENTRY
*));
112 (void) memset(h
->h_table
, 0, initialCapacity
* sizeof (ENTRY
*));
114 if (h
->h_table
== NULL
) {
118 h
->h_tableSize
= initialCapacity
;
121 h
->h_loadFactor
= loadFactor
;
122 h
->h_threshold
= (uint_t
)(initialCapacity
* loadFactor
);
129 * Return a pointer to a matching key
133 h_get(const HASHSET h
, void *key
)
135 uint_t hash
= h
->h_hash(key
);
136 uint_t i
= hash
% h
->h_tableSize
;
139 for (e
= h
->h_table
[i
]; e
; e
= e
->e_next
)
140 if (e
->e_hash
== hash
&& h
->h_equal(e
->e_key
, key
))
147 * Rehash (grow) HASHSET
148 * - called when loadFactor exceeds threshold
149 * - new size is 2*old_size+1
155 uint_t i
= h
->h_tableSize
;
156 uint_t newtabSize
= 2 * i
+ 1;
157 ENTRY
**newtab
= exmalloc(newtabSize
* sizeof (ENTRY
*));
159 (void) memset(newtab
, 0, newtabSize
* sizeof (ENTRY
*));
164 for (e
= h
->h_table
[i
]; e
; e
= next
) {
165 uint_t k
= e
->e_hash
% newtabSize
;
167 next
= (ENTRY
*) e
->e_next
;
168 e
->e_next
= (ENTRY
*) newtab
[k
];
173 h
->h_threshold
= (uint_t
)(newtabSize
* h
->h_loadFactor
);
174 h
->h_tableSize
= newtabSize
;
180 * Store a key into a HASHSET
181 * - if there is already an "equal" key then the new key will not
182 * be stored and the function returns a pointer to an existing key
183 * - otherwise the function stores pointer to the new key and return NULL
187 h_put(HASHSET h
, const void *key
)
189 uint_t hash
= h
->h_hash(key
);
190 uint_t indx
= hash
% h
->h_tableSize
;
193 for (e
= h
->h_table
[indx
]; e
; e
= e
->e_next
)
194 if (e
->e_hash
== hash
&& h
->h_equal(e
->e_key
, key
))
197 if (h
->h_count
>= h
->h_threshold
) {
200 indx
= hash
% h
->h_tableSize
;
203 e
= exmalloc(sizeof (ENTRY
));
205 e
->e_key
= (void *) key
;
206 e
->e_next
= h
->h_table
[indx
];
208 h
->h_table
[indx
] = e
;
211 DTRACE_PROBE2(mountd
, hashset
, h
->h_count
, h
->h_loadFactor
);
218 * - if there is no "equal" key in the HASHSET the fuction returns NULL
219 * - otherwise the function returns a pointer to the deleted key
223 h_delete(HASHSET h
, const void *key
)
225 uint_t hash
= h
->h_hash(key
);
226 uint_t indx
= hash
% h
->h_tableSize
;
229 for (e
= h
->h_table
[indx
], prev
= NULL
; e
; prev
= e
, e
= e
->e_next
) {
230 if (e
->e_hash
== hash
&& h
->h_equal(e
->e_key
, key
)) {
233 prev
->e_next
= e
->e_next
;
235 h
->h_table
[indx
] = e
->e_next
;
245 * Return an opaque HASHSET_ITERATOR (to be used in h_next())
249 h_iterator(HASHSET h
)
251 HASHSET_ITERATOR i
= exmalloc(sizeof (*i
));
254 i
->i_indx
= h
->h_tableSize
;
262 * Return a pointer to a next key
266 h_next(HASHSET_ITERATOR i
)
270 while (i
->i_e
== NULL
) {
271 if (i
->i_indx
-- == 0)
274 i
->i_e
= i
->i_h
->h_table
[i
->i_indx
];
278 i
->i_e
= i
->i_e
->e_next
;