]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/hash.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 00 Hash Tables */
22 #include <gnumalloc.h>
27 static void hash_next_bucket(hash_table
* hid
);
30 hash_string(const void *data
, unsigned int size
)
32 const unsigned char *s
= static_cast<const unsigned char *>(data
);
45 /* the following function(s) were adapted from
46 * usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite */
48 /* Hash function from Chris Torek. */
50 hash4(const void *data
, unsigned int size
)
52 const char *key
= static_cast<const char *>(data
);
57 #define HASH4a h = (h << 5) - h + *key++;
58 #define HASH4b h = (h << 5) + h + *key++;
64 switch (len
& (8 - 1)) {
103 * hash_create - creates a new hash table, uses the cmp_func
104 * to compare keys. Returns the identification for the hash table;
105 * otherwise returns a negative number on error.
108 hash_create(HASHCMP
* cmp_func
, int hash_sz
, HASHHASH
* hash_func
)
110 hash_table
*hid
= (hash_table
*)xcalloc(1, sizeof(hash_table
));
112 hid
->size
= (unsigned int) DEFAULT_HASH_SIZE
;
114 hid
->size
= (unsigned int) hash_sz
;
115 /* allocate and null the buckets */
116 hid
->buckets
= (hash_link
**)xcalloc(hid
->size
, sizeof(hash_link
*));
118 hid
->hash
= hash_func
;
120 hid
->current_slot
= 0;
125 * hash_join - joins a hash_link under its key lnk->key
126 * into the hash table 'hid'.
128 * It does not copy any data into the hash table, only links pointers.
131 hash_join(hash_table
* hid
, hash_link
* lnk
)
134 i
= hid
->hash(lnk
->key
, hid
->size
);
135 lnk
->next
= hid
->buckets
[i
];
136 hid
->buckets
[i
] = lnk
;
141 * hash_lookup - locates the item under the key 'k' in the hash table
142 * 'hid'. Returns a pointer to the hash bucket on success; otherwise
146 hash_lookup(hash_table
* hid
, const void *k
)
149 assert(k
!= nullptr);
150 b
= hid
->hash(k
, hid
->size
);
151 for (hash_link
*walker
= hid
->buckets
[b
]; walker
!= nullptr; walker
= walker
->next
) {
152 if ((hid
->cmp
) (k
, walker
->key
) == 0) {
155 assert(walker
!= walker
->next
);
161 hash_next_bucket(hash_table
* hid
)
163 while (hid
->next
== nullptr && ++hid
->current_slot
< hid
->size
)
164 hid
->next
= hid
->buckets
[hid
->current_slot
];
168 * hash_first - initializes the hash table for the hash_next()
172 hash_first(hash_table
* hid
)
174 assert(nullptr == hid
->next
);
175 hid
->current_slot
= 0;
176 hid
->next
= hid
->buckets
[hid
->current_slot
];
177 if (nullptr == hid
->next
)
178 hash_next_bucket(hid
);
182 * hash_next - returns the next item in the hash table 'hid'.
183 * Otherwise, returns NULL on error or end of list.
185 * MUST call hash_first() before hash_next().
188 hash_next(hash_table
* hid
)
190 hash_link
*p
= hid
->next
;
194 if (nullptr == hid
->next
)
195 hash_next_bucket(hid
);
200 * hash_last - resets hash traversal state to NULL
204 hash_last(hash_table
* hid
)
206 assert(hid
!= nullptr);
208 hid
->current_slot
= 0;
212 * hash_remove_link - deletes the given hash_link node from the
213 * hash table 'hid'. Does not free the item, only removes it
216 * An assertion is triggered if the hash_link is not found in the
220 hash_remove_link(hash_table
* hid
, hash_link
* hl
)
222 assert(hl
!= nullptr);
223 int i
= hid
->hash(hl
->key
, hid
->size
);
224 for (hash_link
**P
= &hid
->buckets
[i
]; *P
; P
= &(*P
)->next
) {
228 if (hid
->next
== hl
) {
229 hid
->next
= hl
->next
;
230 if (nullptr == hid
->next
)
231 hash_next_bucket(hid
);
240 * hash_get_bucket - returns the head item of the bucket
241 * in the hash table 'hid'. Otherwise, returns NULL on error.
244 hash_get_bucket(hash_table
* hid
, unsigned int bucket
)
246 if (bucket
>= hid
->size
)
248 return (hid
->buckets
[bucket
]);
252 hashFreeItems(hash_table
* hid
, HASHFREE
* free_func
)
256 hash_link
**list
= (hash_link
**)xcalloc(hid
->count
, sizeof(hash_link
*));
258 while ((l
= hash_next(hid
)) && i
< hid
->count
) {
262 for (int j
= 0; j
< i
; ++j
)
263 free_func(*(list
+ j
));
268 hashFreeMemory(hash_table
* hid
)
277 static int hash_primes
[] = {
295 int I
= sizeof(hash_primes
) / sizeof(int);
296 int best_prime
= hash_primes
[0];
297 double min
= fabs(log((double) n
) - log((double) hash_primes
[0]));
299 for (int i
= 0; i
< I
; ++i
) {
300 d
= fabs(log((double) n
) - log((double) hash_primes
[i
]));
304 best_prime
= hash_primes
[i
];
310 * return the key of a hash_link as a const string
313 hashKeyStr(const hash_link
* hl
)
315 return (const char *) hl
->key
;
320 * hash-driver - Run with a big file as stdin to insert each line into the
321 * hash table, then prints the whole hash table, then deletes a random item,
322 * and prints the table again...
328 LOCAL_ARRAY(char, buf
, BUFSIZ
);
329 LOCAL_ARRAY(char, todelete
, BUFSIZ
);
330 hash_link
*walker
= nullptr;
335 printf("creating hash table\n");
336 if ((hid
= hash_create((HASHCMP
*) strcmp
, 229, hash4
)) < 0) {
337 printf("hash_create error.\n");
340 printf("done creating hash table: %d\n", hid
);
343 std::uniform_int_distribution
<> dist(0,16);
345 while (fgets(buf
, BUFSIZ
, stdin
)) {
346 buf
[strlen(buf
) - 1] = '\0';
347 printf("Inserting '%s' for item %p to hash table: %d\n",
349 hash_insert(hid
, xstrdup(buf
), (void *) 0x12345678);
351 strcpy(todelete
, buf
);
354 printf("walking hash table...\n");
355 for (int i
= 0, walker
= hash_first(hid
); walker
; walker
= hash_next(hid
)) {
356 printf("item %5d: key: '%s' item: %p\n", i
++, walker
->key
,
359 printf("done walking hash table...\n");
362 printf("deleting %s from %d\n", todelete
, hid
);
363 if (hash_delete(hid
, todelete
))
364 printf("hash_delete error\n");
366 printf("walking hash table...\n");
367 for (int i
= 0, walker
= hash_first(hid
); walker
; walker
= hash_next(hid
)) {
368 printf("item %5d: key: '%s' item: %p\n", i
++, walker
->key
,
371 printf("done walking hash table...\n");
373 printf("driver finished.\n");