4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <mono/metadata/sgen-gc.h>
29 #include <mono/metadata/sgen-hash-table.h>
32 rehash (SgenHashTable *hash_table)
34 SgenHashTableEntry **old_hash = hash_table->table;
35 guint old_hash_size = hash_table->size;
36 guint i, hash, new_size;
37 SgenHashTableEntry **new_hash;
38 SgenHashTableEntry *entry, *next;
41 sgen_register_fixed_internal_mem_type (hash_table->entry_mem_type,
42 sizeof (SgenHashTableEntry*) + sizeof (gpointer) + hash_table->data_size);
45 new_size = g_spaced_primes_closest (hash_table->num_entries);
48 new_hash = sgen_alloc_internal_dynamic (new_size * sizeof (SgenHashTableEntry*), hash_table->table_mem_type, TRUE);
49 for (i = 0; i < old_hash_size; ++i) {
50 for (entry = old_hash [i]; entry; entry = next) {
51 hash = hash_table->hash_func (entry->key) % new_size;
53 entry->next = new_hash [hash];
54 new_hash [hash] = entry;
57 sgen_free_internal_dynamic (old_hash, old_hash_size * sizeof (SgenHashTableEntry*), hash_table->table_mem_type);
58 hash_table->table = new_hash;
59 hash_table->size = new_size;
63 rehash_if_necessary (SgenHashTable *hash_table)
65 if (hash_table->num_entries >= hash_table->size * 2)
68 SGEN_ASSERT (1, hash_table->size, "rehash guarantees size > 0");
71 static SgenHashTableEntry*
72 lookup (SgenHashTable *hash_table, gpointer key, guint *_hash)
74 SgenHashTableEntry *entry;
76 GEqualFunc equal = hash_table->equal_func;
78 if (!hash_table->size)
81 hash = hash_table->hash_func (key) % hash_table->size;
85 for (entry = hash_table->table [hash]; entry; entry = entry->next) {
86 if ((equal && equal (entry->key, key)) || (!equal && entry->key == key))
93 sgen_hash_table_lookup (SgenHashTable *hash_table, gpointer key)
95 SgenHashTableEntry *entry = lookup (hash_table, key, NULL);
102 sgen_hash_table_replace (SgenHashTable *hash_table, gpointer key, gpointer new_value, gpointer old_value)
105 SgenHashTableEntry *entry;
107 rehash_if_necessary (hash_table);
108 entry = lookup (hash_table, key, &hash);
112 memcpy (old_value, entry->data, hash_table->data_size);
113 memcpy (entry->data, new_value, hash_table->data_size);
117 entry = sgen_alloc_internal (hash_table->entry_mem_type);
119 memcpy (entry->data, new_value, hash_table->data_size);
121 entry->next = hash_table->table [hash];
122 hash_table->table [hash] = entry;
124 hash_table->num_entries++;
130 sgen_hash_table_set_value (SgenHashTable *hash_table, gpointer key, gpointer new_value, gpointer old_value)
133 SgenHashTableEntry *entry;
135 entry = lookup (hash_table, key, &hash);
139 memcpy (old_value, entry->data, hash_table->data_size);
140 memcpy (entry->data, new_value, hash_table->data_size);
148 sgen_hash_table_set_key (SgenHashTable *hash_table, gpointer old_key, gpointer new_key)
151 SgenHashTableEntry *entry;
153 entry = lookup (hash_table, old_key, &hash);
156 entry->key = new_key;
164 sgen_hash_table_remove (SgenHashTable *hash_table, gpointer key, gpointer data_return)
166 SgenHashTableEntry *entry, *prev;
168 GEqualFunc equal = hash_table->equal_func;
170 rehash_if_necessary (hash_table);
171 hash = hash_table->hash_func (key) % hash_table->size;
174 for (entry = hash_table->table [hash]; entry; entry = entry->next) {
175 if ((equal && equal (entry->key, key)) || (!equal && entry->key == key)) {
177 prev->next = entry->next;
179 hash_table->table [hash] = entry->next;
181 hash_table->num_entries--;
184 memcpy (data_return, entry->data, hash_table->data_size);
186 sgen_free_internal (entry, hash_table->entry_mem_type);
197 sgen_hash_table_clean (SgenHashTable *hash_table)
201 if (!hash_table->size) {
202 SGEN_ASSERT (1, !hash_table->table, "clean should reset hash_table->table");
203 SGEN_ASSERT (1, !hash_table->num_entries, "clean should reset hash_table->num_entries");
207 for (i = 0; i < hash_table->size; ++i) {
208 SgenHashTableEntry *entry = hash_table->table [i];
210 SgenHashTableEntry *next = entry->next;
211 sgen_free_internal (entry, hash_table->entry_mem_type);
216 sgen_free_internal_dynamic (hash_table->table, hash_table->size * sizeof (SgenHashTableEntry*), hash_table->table_mem_type);
218 hash_table->table = NULL;
219 hash_table->size = 0;
220 hash_table->num_entries = 0;