4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains a basic dictionary implementation which stores
31 * arbitrary key-value mappings. It is used by libpool to store
32 * information about element pointers (pool_elem_t) in the kernel
33 * provider implementation.
38 #include <sys/types.h>
46 * HASH_64_INIT is the same as the INIT value since it is the value
47 * used by FNV (FNV1_64_INIT). More details on FNV are available at:
49 * http://www.isthe.com/chongo/tech/comp/fnv/index.html
51 #define HASH_64_INIT (0xcbf29ce484222325ULL) /* Hash initializer */
54 * HASH_64_PRIME is a large prime number chosen to minimize hashing
57 #define HASH_64_PRIME (0x100000001b3ULL) /* Large Prime */
60 * DICT_SIZE is chosen as it is the nearest prime to 2^9 (512). 512 is
61 * chosen as it is unlikely that this dictionary will contain more
62 * elements than this in normal operation. Of course overflow in each
63 * bucket is acceptable, but if there is too much overflow, then
64 * performance will degrade to that of a list.
66 #define DICT_SIZE 509 /* Reasonable prime */
75 typedef struct dict_bucket
77 const void *db_key
; /* key */
78 void *db_value
; /* value */
79 struct dict_bucket
*db_next
; /* next bucket */
83 * A dictionary which holds a mapping between a key and a value.
84 * dh_change - detects changes to the dictionary.
85 * dh_cmp - comparison function
86 * dh_hash - hashing function
87 * dh_buckets - key storage
88 * dh_size - # of buckets
92 int (*dh_cmp
)(const void *, const void *);
93 uint64_t (*dh_hash
)(const void *);
95 dict_bucket_t
**dh_buckets
;
100 * Utility functions. Mainly used for debugging
105 static void bit_print_32(unsigned int);
106 static void bit_print_64(unsigned long long);
111 * Default functions for hashing and comparing if the user does not specify
112 * these values when creating the dictionary.
114 static int cmp_addr(const void *, const void *);
115 static uint64_t hash_addr(const void *);
124 * Print to standard out the bit representation of the supplied value
127 bit_print_32(unsigned int v
)
129 #pragma error_messages(off, E_INTEGER_OVERFLOW_DETECTED)
130 int i
, mask
= 1 << 31;
131 #pragma error_messages(on, E_INTEGER_OVERFLOW_DETECTED)
133 for (i
= 1; i
<= 32; i
++) {
134 (void) putchar(((v
& mask
) == 0) ? '0' : '1');
136 if (i
% 8 == 0 && i
!= 32)
139 (void) putchar('\n');
143 * Print to standard out the bit representation of the supplied value
146 bit_print_64(unsigned long long v
)
148 #pragma error_messages(off, E_INTEGER_OVERFLOW_DETECTED)
149 long long mask
= 1ll << 63;
150 #pragma error_messages(on, E_INTEGER_OVERFLOW_DETECTED)
153 for (i
= 1; i
<= 64; i
++) {
154 (void) putchar(((v
& mask
) == 0) ? '0' : '1');
156 if (i
% 8 == 0 && i
!= 64)
159 (void) putchar('\n');
167 * Default comparison function which is used if no comparison function
168 * is supplied when the dictionary is created. The default behaviour
169 * is to compare memory address.
172 cmp_addr(const void *x
, const void *y
)
179 * The default hashing function which is used if no hashing function
180 * is provided when the dictionary is created. The default behaviour
181 * is to use the hash_buf() function.
184 hash_addr(const void *key
)
186 return (hash_buf(&key
, sizeof (key
)));
195 * Return a hash which is built by manipulating each byte in the
196 * supplied data. The hash logic follows the approach suggested in the
200 hash_buf(const void *buf
, size_t len
)
202 uchar_t
*start
= (uchar_t
*)buf
;
203 uchar_t
*end
= start
+ len
;
204 uint64_t hash
= HASH_64_INIT
;
206 while (start
< end
) {
207 hash
*= HASH_64_PRIME
;
208 hash
^= (uint64_t)*start
++;
216 * Return a hash which is built by manipulating each byte in the
217 * supplied string. The hash logic follows the approach suggested in
221 hash_str(const char *str
)
223 uchar_t
*p
= (uchar_t
*)str
;
224 uint64_t hash
= HASH_64_INIT
;
227 hash
*= HASH_64_PRIME
;
228 hash
^= (uint64_t)*p
++;
235 * Return the number of keys held in the supplied dictionary.
238 dict_length(dict_hdl_t
*hdl
)
240 return (hdl
->dh_length
);
244 * Free the supplied dictionary and all it's associated resource.
247 dict_free(dict_hdl_t
**hdl
)
249 if ((*hdl
)->dh_length
> 0) {
251 for (i
= 0; i
< (*hdl
)->dh_size
; i
++) {
252 dict_bucket_t
*this, *next
;
253 for (this = (*hdl
)->dh_buckets
[i
]; this != NULL
;
255 next
= this->db_next
;
260 free((*hdl
)->dh_buckets
);
266 * Create a new dictionary using the supplied comparison and hashing
267 * functions. If none are supplied then the defaults are used.
270 dict_new(int (*cmp
)(const void *, const void *),
271 uint64_t (*hash
)(const void *))
275 if ((hdl
= calloc(1, sizeof (dict_hdl_t
))) == NULL
)
277 hdl
->dh_size
= DICT_SIZE
;
278 if ((hdl
->dh_buckets
= calloc(hdl
->dh_size
, sizeof (dict_bucket_t
*)))
283 hdl
->dh_cmp
= cmp
? cmp
: cmp_addr
;
284 hdl
->dh_hash
= hash
? hash
: hash_addr
;
289 * Get a value from the hash. Null is returned if the key cannot be
293 dict_get(dict_hdl_t
*hdl
, const void *key
)
296 dict_bucket_t
*bucket
;
298 i
= (*hdl
->dh_hash
)(key
)%hdl
->dh_size
;
299 for (bucket
= hdl
->dh_buckets
[i
]; bucket
!= NULL
;
300 bucket
= bucket
->db_next
)
301 if ((*hdl
->dh_cmp
)(key
, bucket
->db_key
) == 0)
303 return (bucket
? bucket
->db_value
: NULL
);
307 * Put an entry into the hash. Null is returned if this key was not
308 * already present, otherwise the previous value is returned.
311 dict_put(dict_hdl_t
*hdl
, const void *key
, void *value
)
314 dict_bucket_t
*bucket
;
317 i
= (*hdl
->dh_hash
)(key
)%hdl
->dh_size
;
318 for (bucket
= hdl
->dh_buckets
[i
]; bucket
!= NULL
;
319 bucket
= bucket
->db_next
)
320 if ((*hdl
->dh_cmp
)(key
, bucket
->db_key
) == 0)
323 prev
= bucket
->db_value
;
325 bucket
= malloc(sizeof (dict_bucket_t
));
326 bucket
->db_key
= key
;
327 bucket
->db_next
= hdl
->dh_buckets
[i
];
328 hdl
->dh_buckets
[i
] = bucket
;
332 bucket
->db_value
= value
;
337 * Remove the key/value from the dictionary. The value is returned if
338 * the key is found. NULL is returned if the key cannot be located.
341 dict_remove(dict_hdl_t
*hdl
, const void *key
)
344 dict_bucket_t
**pbucket
;
347 i
= (*hdl
->dh_hash
)(key
)%hdl
->dh_size
;
349 for (pbucket
= &hdl
->dh_buckets
[i
]; *pbucket
!= NULL
;
350 pbucket
= &(*pbucket
)->db_next
) {
351 if ((*hdl
->dh_cmp
)(key
, (*pbucket
)->db_key
) == 0) {
352 dict_bucket_t
*bucket
= *pbucket
;
353 void *value
= bucket
->db_value
;
355 *pbucket
= bucket
->db_next
;
365 * For all entries in the dictionary call the user supplied function
366 * (apply) with the key, value and user supplied data. If the
367 * dictionary is modifed while this function is executing, then the
368 * function will fail with an assertion about table modifcation.
371 dict_map(dict_hdl_t
*hdl
, void (*apply
)(const void *, void **, void *),
375 dict_bucket_t
*bucket
= NULL
;
376 uint64_t change_stamp
= hdl
->dh_change
;
378 for (i
= 0; i
< hdl
->dh_size
; i
++) {
379 for (bucket
= hdl
->dh_buckets
[i
]; bucket
!= NULL
;
380 bucket
= bucket
->db_next
) {
381 apply(bucket
->db_key
, &bucket
->db_value
, cl
);
382 if (hdl
->dh_change
!= change_stamp
)
383 assert(!"table modified illegally");