2 Copyright (c) 2002, 2004, Christopher Clark
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 * Neither the name of the original author; nor the names of any contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 /* Modifications made by Jack Lange <jarusl@cs.northwestern.edu> */
38 #include <palacios/vmm.h>
39 #include <palacios/vmm_hashtable.h>
40 #include <palacios/vmm_string.h>
50 struct hash_entry * next;
55 struct hash_entry ** table;
59 uint_t (*hash_fn) (addr_t key);
60 int (*eq_fn) (addr_t key1, addr_t key2);
69 static inline uint_t do_hash(struct hashtable * htable, addr_t key) {
70 /* Aim to protect against poor hash functions by adding logic here
71 * - logic taken from java 1.4 hashtable source */
72 uint_t i = htable->hash_fn(key);
74 i ^= ((i >> 14) | (i << 18)); /* >>> */
76 i ^= ((i >> 10) | (i << 22)); /* >>> */
82 /* HASH AN UNSIGNED LONG */
83 /* LINUX UNSIGHED LONG HASH FUNCTION */
85 /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
86 #define GOLDEN_RATIO_PRIME 0x9e370001UL
87 #define BITS_PER_LONG 32
88 #elif defined(__V3_64BIT__)
89 /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
90 #define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
91 #define BITS_PER_LONG 64
93 #error Define GOLDEN_RATIO_PRIME for your wordsize.
96 ulong_t v3_hash_long(ulong_t val, uint_t bits) {
100 /* Sigh, gcc can't optimise this alone like it does for 32 bits. */
115 /* On some cpus multiply is faster, on others gcc will do shifts */
116 hash *= GOLDEN_RATIO_PRIME;
119 /* High bits are more random, so use them. */
120 return hash >> (BITS_PER_LONG - bits);
123 /* HASH GENERIC MEMORY BUFFER */
124 /* ELF HEADER HASH FUNCTION */
125 ulong_t v3_hash_buffer(uchar_t * msg, uint_t length) {
130 for (i = 0; i < length; i++) {
131 hash = (hash << 4) + *(msg + i) + i;
132 if ((temp = (hash & 0xF0000000))) {
133 hash ^= (temp >> 24);
142 /*****************************************************************************/
144 static inline uint_t indexFor(uint_t table_length, uint_t hash_value) {
145 return (hash_value % table_length);
148 /* Only works if table_length == 2^N */
150 static inline uint_t indexFor(uint_t table_length, uint_t hashvalue)
152 return (hashvalue & (table_length - 1u));
156 /*****************************************************************************/
157 #define freekey(X) V3_Free(X)
158 /*define freekey(X) ; */
161 static void * tmp_realloc(void * old_ptr, uint_t old_size, uint_t new_size) {
162 void * new_buf = V3_Malloc(new_size);
164 if (new_buf == NULL) {
168 memcpy(new_buf, old_ptr, old_size);
176 Credit for primes table: Aaron Krowne
177 http://br.endernet.org/~akrowne/
178 http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
180 static const uint_t primes[] = {
182 769, 1543, 3079, 6151,
183 12289, 24593, 49157, 98317,
184 196613, 393241, 786433, 1572869,
185 3145739, 6291469, 12582917, 25165843,
186 50331653, 100663319, 201326611, 402653189,
187 805306457, 1610612741 };
190 // this assumes that the max load factor is .65
191 static const uint_t load_factors[] = {
193 500, 1003, 2002, 3999,
194 7988, 15986, 31953, 63907,
195 127799, 255607, 511182, 1022365,
196 2044731, 4089455, 8178897, 16357798,
197 32715575, 65431158, 130862298, 261724573,
198 523449198, 1046898282 };
200 const uint_t prime_table_length = sizeof(primes) / sizeof(primes[0]);
204 /*****************************************************************************/
205 struct hashtable * v3_create_htable(uint_t min_size,
206 uint_t (*hash_fn) (addr_t),
207 int (*eq_fn) (addr_t, addr_t)) {
208 struct hashtable * htable;
210 uint_t size = primes[0];
212 /* Check requested hashtable isn't too large */
213 if (min_size > (1u << 30)) {
217 /* Enforce size as prime */
218 for (prime_index = 0; prime_index < prime_table_length; prime_index++) {
219 if (primes[prime_index] > min_size) {
220 size = primes[prime_index];
225 htable = (struct hashtable *)V3_Malloc(sizeof(struct hashtable));
227 if (htable == NULL) {
231 htable->table = (struct hash_entry **)V3_Malloc(sizeof(struct hash_entry*) * size);
233 if (htable->table == NULL) {
239 memset(htable->table, 0, size * sizeof(struct hash_entry *));
241 htable->table_length = size;
242 htable->prime_index = prime_index;
243 htable->entry_count = 0;
244 htable->hash_fn = hash_fn;
245 htable->eq_fn = eq_fn;
246 htable->load_limit = load_factors[prime_index];
253 /*****************************************************************************/
254 static int hashtable_expand(struct hashtable * htable) {
255 /* Double the size of the table to accomodate more entries */
256 struct hash_entry ** new_table;
257 struct hash_entry * tmp_entry;
258 struct hash_entry ** entry_ptr;
263 /* Check we're not hitting max capacity */
264 if (htable->prime_index == (prime_table_length - 1)) {
268 new_size = primes[++(htable->prime_index)];
270 new_table = (struct hash_entry **)V3_Malloc(sizeof(struct hash_entry*) * new_size);
272 if (new_table != NULL) {
273 memset(new_table, 0, new_size * sizeof(struct hash_entry *));
274 /* This algorithm is not 'stable'. ie. it reverses the list
275 * when it transfers entries between the tables */
277 for (i = 0; i < htable->table_length; i++) {
279 while ((tmp_entry = htable->table[i]) != NULL) {
280 htable->table[i] = tmp_entry->next;
282 index = indexFor(new_size, tmp_entry->hash);
284 tmp_entry->next = new_table[index];
286 new_table[index] = tmp_entry;
290 V3_Free(htable->table);
292 htable->table = new_table;
294 /* Plan B: realloc instead */
296 //new_table = (struct hash_entry **)realloc(htable->table, new_size * sizeof(struct hash_entry *));
297 new_table = (struct hash_entry **)tmp_realloc(htable->table, primes[htable->prime_index - 1],
298 new_size * sizeof(struct hash_entry *));
300 if (new_table == NULL) {
301 (htable->prime_index)--;
305 htable->table = new_table;
307 memset(new_table[htable->table_length], 0, new_size - htable->table_length);
309 for (i = 0; i < htable->table_length; i++) {
311 for (entry_ptr = &(new_table[i]), tmp_entry = *entry_ptr;
313 tmp_entry = *entry_ptr) {
315 index = indexFor(new_size, tmp_entry->hash);
318 entry_ptr = &(tmp_entry->next);
320 *entry_ptr = tmp_entry->next;
321 tmp_entry->next = new_table[index];
322 new_table[index] = tmp_entry;
328 htable->table_length = new_size;
330 htable->load_limit = load_factors[htable->prime_index];
335 /*****************************************************************************/
336 uint_t v3_htable_count(struct hashtable * htable) {
337 return htable->entry_count;
340 /*****************************************************************************/
341 int v3_htable_insert(struct hashtable * htable, addr_t key, addr_t value) {
342 /* This method allows duplicate keys - but they shouldn't be used */
344 struct hash_entry * new_entry;
346 if (++(htable->entry_count) > htable->load_limit) {
347 /* Ignore the return value. If expand fails, we should
348 * still try cramming just this value into the existing table
349 * -- we may not have memory for a larger table, but one more
350 * element may be ok. Next time we insert, we'll try expanding again.*/
351 hashtable_expand(htable);
355 new_entry = (struct hash_entry *)V3_Malloc(sizeof(struct hash_entry));
357 if (new_entry == NULL) {
358 (htable->entry_count)--;
362 new_entry->hash = do_hash(htable, key);
364 index = indexFor(htable->table_length, new_entry->hash);
366 new_entry->key = key;
367 new_entry->value = value;
369 new_entry->next = htable->table[index];
371 htable->table[index] = new_entry;
378 int v3_htable_change(struct hashtable * htable, addr_t key, addr_t value, int free_value) {
379 struct hash_entry * tmp_entry;
383 hash_value = do_hash(htable, key);
385 index = indexFor(htable->table_length, hash_value);
387 tmp_entry = htable->table[index];
389 while (tmp_entry != NULL) {
390 /* Check hash value to short circuit heavier comparison */
391 if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
394 V3_Free((void *)(tmp_entry->value));
397 tmp_entry->value = value;
400 tmp_entry = tmp_entry->next;
407 int v3_htable_inc(struct hashtable * htable, addr_t key, addr_t value) {
408 struct hash_entry * tmp_entry;
412 hash_value = do_hash(htable, key);
414 index = indexFor(htable->table_length, hash_value);
416 tmp_entry = htable->table[index];
418 while (tmp_entry != NULL) {
419 /* Check hash value to short circuit heavier comparison */
420 if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
422 tmp_entry->value += value;
425 tmp_entry = tmp_entry->next;
431 int v3_htable_dec(struct hashtable * htable, addr_t key, addr_t value) {
432 struct hash_entry * tmp_entry;
436 hash_value = do_hash(htable, key);
438 index = indexFor(htable->table_length, hash_value);
440 tmp_entry = htable->table[index];
442 while (tmp_entry != NULL) {
443 /* Check hash value to short circuit heavier comparison */
444 if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
446 tmp_entry->value -= value;
449 tmp_entry = tmp_entry->next;
457 /*****************************************************************************/
458 /* returns value associated with key */
459 addr_t v3_htable_search(struct hashtable * htable, addr_t key) {
460 struct hash_entry * cursor;
464 hash_value = do_hash(htable, key);
466 index = indexFor(htable->table_length, hash_value);
468 cursor = htable->table[index];
470 while (cursor != NULL) {
471 /* Check hash value to short circuit heavier comparison */
472 if ((hash_value == cursor->hash) &&
473 (htable->eq_fn(key, cursor->key))) {
474 return cursor->value;
477 cursor = cursor->next;
483 /*****************************************************************************/
484 /* returns value associated with key */
485 addr_t v3_htable_remove(struct hashtable * htable, addr_t key, int free_key) {
486 /* TODO: consider compacting the table when the load factor drops enough,
487 * or provide a 'compact' method. */
489 struct hash_entry * cursor;
490 struct hash_entry ** entry_ptr;
495 hash_value = do_hash(htable, key);
497 index = indexFor(htable->table_length, hash_value);
499 entry_ptr = &(htable->table[index]);
502 while (cursor != NULL) {
503 /* Check hash value to short circuit heavier comparison */
504 if ((hash_value == cursor->hash) &&
505 (htable->eq_fn(key, cursor->key))) {
507 *entry_ptr = cursor->next;
508 htable->entry_count--;
509 value = cursor->value;
512 freekey((void *)(cursor->key));
519 entry_ptr = &(cursor->next);
520 cursor = cursor->next;
525 /*****************************************************************************/
527 void v3_free_htable(struct hashtable * htable, int free_values, int free_keys) {
529 struct hash_entry * cursor;;
530 struct hash_entry **table = htable->table;
533 for (i = 0; i < htable->table_length; i++) {
536 while (cursor != NULL) {
537 struct hash_entry * tmp;
540 cursor = cursor->next;
543 freekey((void *)(tmp->key));
545 V3_Free((void *)(tmp->value));
550 for (i = 0; i < htable->table_length; i++) {
553 while (cursor != NULL) {
554 struct hash_entry * tmp;
557 cursor = cursor->next;
560 freekey((void *)(tmp->key));
567 V3_Free(htable->table);
574 /* HASH TABLE ITERATORS */
578 struct hashtable_iter * v3_create_htable_iter(struct hashtable * htable) {
582 struct hashtable_iter * iter = (struct hashtable_iter *)V3_Malloc(sizeof(struct hashtable_iter));
588 iter->htable = htable;
591 table_length = htable->table_length;
592 iter->index = table_length;
594 if (htable->entry_count == 0) {
598 for (i = 0; i < table_length; i++) {
599 if (htable->table[i] != NULL) {
600 iter->entry = htable->table[i];
610 addr_t v3_htable_get_iter_key(struct hashtable_iter * iter) {
611 return iter->entry->key;
614 addr_t v3_htable_get_iter_value(struct hashtable_iter * iter) {
615 return iter->entry->value;
619 /* advance - advance the iterator to the next element
620 * returns zero if advanced to end of table */
621 int v3_htable_iter_advance(struct hashtable_iter * iter) {
624 struct hash_entry ** table;
625 struct hash_entry * next;
627 if (iter->entry == NULL) {
628 return 0; /* stupidity check */
632 next = iter->entry->next;
635 iter->parent = iter->entry;
640 table_length = iter->htable->table_length;
643 if (table_length <= (j = ++(iter->index))) {
648 table = iter->htable->table;
650 while ((next = table[j]) == NULL) {
651 if (++j >= table_length) {
652 iter->index = table_length;
665 /* remove - remove the entry at the current iterator position
666 * and advance the iterator, if there is a successive
668 * If you want the value, read it before you remove:
669 * beware memory leaks if you don't.
670 * Returns zero if end of iteration. */
671 int v3_htable_iter_remove(struct hashtable_iter * iter, int free_key) {
672 struct hash_entry * remember_entry;
673 struct hash_entry * remember_parent;
677 if ((iter->parent) == NULL) {
678 /* element is head of a chain */
679 iter->htable->table[iter->index] = iter->entry->next;
681 /* element is mid-chain */
682 iter->parent->next = iter->entry->next;
686 /* itr->e is now outside the hashtable */
687 remember_entry = iter->entry;
688 iter->htable->entry_count--;
690 freekey((void *)(remember_entry->key));
693 /* Advance the iterator, correcting the parent */
694 remember_parent = iter->parent;
695 ret = v3_htable_iter_advance(iter);
697 if (iter->parent == remember_entry) {
698 iter->parent = remember_parent;
701 V3_Free(remember_entry);
706 /* returns zero if not found */
707 int v3_htable_iter_search(struct hashtable_iter * iter,
708 struct hashtable * htable, addr_t key) {
709 struct hash_entry * entry;
710 struct hash_entry * parent;
714 hash_value = do_hash(htable, key);
715 index = indexFor(htable->table_length, hash_value);
717 entry = htable->table[index];
720 while (entry != NULL) {
721 /* Check hash value to short circuit heavier comparison */
722 if ((hash_value == entry->hash) &&
723 (htable->eq_fn(key, entry->key))) {
726 iter->parent = parent;
727 iter->htable = htable;
751 * Copyright (c) 2002, Christopher Clark
752 * All rights reserved.
754 * Redistribution and use in source and binary forms, with or without
755 * modification, are permitted provided that the following conditions
758 * * Redistributions of source code must retain the above copyright
759 * notice, this list of conditions and the following disclaimer.
761 * * Redistributions in binary form must reproduce the above copyright
762 * notice, this list of conditions and the following disclaimer in the
763 * documentation and/or other materials provided with the distribution.
765 * * Neither the name of the original author; nor the names of any contributors
766 * may be used to endorse or promote products derived from this software
767 * without specific prior written permission.
770 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
771 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
772 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
773 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
774 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
775 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
776 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
777 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
778 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
779 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
780 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.