diff options
Diffstat (limited to 'src/binding-hash.cc')
-rw-r--r-- | src/binding-hash.cc | 191 |
1 files changed, 47 insertions, 144 deletions
diff --git a/src/binding-hash.cc b/src/binding-hash.cc index f39168c9..1e87ad5b 100644 --- a/src/binding-hash.cc +++ b/src/binding-hash.cc @@ -16,164 +16,67 @@ #include "binding-hash.h" -#define INITIAL_HASH_CAPACITY 8 +#include <algorithm> +#include <vector> namespace wabt { -static size_t hash_name(const StringSlice* name) { - // FNV-1a hash - const uint32_t fnv_prime = 0x01000193; - const uint8_t* bp = reinterpret_cast<const uint8_t*>(name->start); - const uint8_t* be = bp + name->length; - uint32_t hval = 0x811c9dc5; - while (bp < be) { - hval ^= static_cast<uint32_t>(*bp++); - hval *= fnv_prime; +void BindingHash::find_duplicates(DuplicateCallback callback, + void* user_data) const { + if (size() > 0) { + ValueTypeVector duplicates; + create_duplicates_vector(&duplicates); + sort_duplicates_vector_by_location(&duplicates); + call_callbacks(duplicates, callback, user_data); } - return hval; } -static BindingHashEntry* hash_main_entry(const BindingHash* hash, - const StringSlice* name) { - return &hash->entries.data[hash_name(name) % hash->entries.capacity]; -} - -bool hash_entry_is_free(const BindingHashEntry* entry) { - return !entry->binding.name.start; -} - -static BindingHashEntry* hash_new_entry(BindingHash* hash, - const StringSlice* name) { - BindingHashEntry* entry = hash_main_entry(hash, name); - if (!hash_entry_is_free(entry)) { - assert(hash->free_head); - BindingHashEntry* free_entry = hash->free_head; - hash->free_head = free_entry->next; - if (free_entry->next) - free_entry->next->prev = nullptr; - - /* our main position is already claimed. Check to see if the entry in that - * position is in its main position */ - BindingHashEntry* other_entry = hash_main_entry(hash, &entry->binding.name); - if (other_entry == entry) { - /* yes, so add this new entry to the chain, even if it is already there */ - /* add as the second entry in the chain */ - free_entry->next = entry->next; - entry->next = free_entry; - entry = free_entry; +void BindingHash::create_duplicates_vector( + ValueTypeVector* out_duplicates) const { + // This relies on the fact that in an unordered_multimap, all values with the + // same key are adjacent in iteration order. + auto first = begin(); + bool is_first = true; + for (auto iter = std::next(first); iter != end(); ++iter) { + if (first->first == iter->first) { + if (is_first) + out_duplicates->push_back(&*first); + out_duplicates->push_back(&*iter); + is_first = false; } else { - /* no, move the entry to the free entry */ - assert(!hash_entry_is_free(other_entry)); - while (other_entry->next != entry) - other_entry = other_entry->next; - - other_entry->next = free_entry; - *free_entry = *entry; - entry->next = nullptr; + is_first = true; + first = iter; } - } else { - /* remove from the free list */ - if (entry->next) - entry->next->prev = entry->prev; - if (entry->prev) - entry->prev->next = entry->next; - else - hash->free_head = entry->next; - entry->next = nullptr; } - - WABT_ZERO_MEMORY(entry->binding); - entry->binding.name = *name; - entry->prev = nullptr; - /* entry->next is set above */ - return entry; } -static void hash_resize(BindingHash* hash, size_t desired_capacity) { - BindingHash new_hash; - WABT_ZERO_MEMORY(new_hash); - /* TODO(binji): better plural */ - reserve_binding_hash_entrys(&new_hash.entries, desired_capacity); - - /* update the free list */ - for (size_t i = 0; i < new_hash.entries.capacity; ++i) { - BindingHashEntry* entry = &new_hash.entries.data[i]; - if (new_hash.free_head) - new_hash.free_head->prev = entry; - - WABT_ZERO_MEMORY(entry->binding.name); - entry->next = new_hash.free_head; - new_hash.free_head = entry; - } - new_hash.free_head->prev = nullptr; - - /* copy from the old hash to the new hash */ - for (size_t i = 0; i < hash->entries.capacity; ++i) { - BindingHashEntry* old_entry = &hash->entries.data[i]; - if (hash_entry_is_free(old_entry)) - continue; - - StringSlice* name = &old_entry->binding.name; - BindingHashEntry* new_entry = hash_new_entry(&new_hash, name); - new_entry->binding = old_entry->binding; - } - - /* we are sharing the StringSlices, so we only need to destroy the old - * binding vector */ - destroy_binding_hash_entry_vector(&hash->entries); - *hash = new_hash; +void BindingHash::sort_duplicates_vector_by_location( + ValueTypeVector* duplicates) const { + std::sort( + duplicates->begin(), duplicates->end(), + [](const value_type* lhs, const value_type* rhs) -> bool { + return lhs->second.loc.line < rhs->second.loc.line || + (lhs->second.loc.line == rhs->second.loc.line && + lhs->second.loc.first_column < rhs->second.loc.first_column); + }); } -Binding* insert_binding(BindingHash* hash, const StringSlice* name) { - if (hash->entries.size == 0) - hash_resize(hash, INITIAL_HASH_CAPACITY); - - if (!hash->free_head) { - /* no more free space, allocate more */ - hash_resize(hash, hash->entries.capacity * 2); +void BindingHash::call_callbacks(const ValueTypeVector& duplicates, + DuplicateCallback callback, + void* user_data) const { + // Loop through all duplicates in order, and call callback with first + // occurrence. + for (auto iter = duplicates.begin(), end = duplicates.end(); iter != end; + ++iter) { + auto first = std::find_if(duplicates.begin(), duplicates.end(), + [iter](const value_type* x) -> bool { + return x->first == (*iter)->first; + }); + if (first == iter) + continue; + assert(first != duplicates.end()); + callback(**first, **iter, user_data); } - - BindingHashEntry* entry = hash_new_entry(hash, name); - assert(entry); - hash->entries.size++; - return &entry->binding; -} - -int find_binding_index_by_name(const BindingHash* hash, - const StringSlice* name) { - if (hash->entries.capacity == 0) - return -1; - - BindingHashEntry* entry = hash_main_entry(hash, name); - do { - if (string_slices_are_equal(&entry->binding.name, name)) - return entry->binding.index; - - entry = entry->next; - } while (entry && !hash_entry_is_free(entry)); - return -1; -} - -void remove_binding(BindingHash* hash, const StringSlice* name) { - int index = find_binding_index_by_name(hash, name); - if (index == -1) - return; - - BindingHashEntry* entry = &hash->entries.data[index]; - destroy_string_slice(&entry->binding.name); - WABT_ZERO_MEMORY(*entry); -} - -static void destroy_binding_hash_entry(BindingHashEntry* entry) { - destroy_string_slice(&entry->binding.name); -} - -void destroy_binding_hash(BindingHash* hash) { - /* Can't use WABT_DESTROY_VECTOR_AND_ELEMENTS, because it loops over size, not - * capacity. */ - for (size_t i = 0; i < hash->entries.capacity; ++i) - destroy_binding_hash_entry(&hash->entries.data[i]); - destroy_binding_hash_entry_vector(&hash->entries); } } // namespace wabt |