/*++ Copyright (c) 2006 Microsoft Corporation Module Name: obj_hashtable.h Abstract: Author: Leonardo de Moura (leonardo) 2008-02-16. Revision History: --*/ #pragma once #include "util/hash.h" #include "util/hashtable.h" /** \brief Special entry for a hashtable of obj pointers (i.e., objects that have a hash() method). This entry uses 0x0 and 0x1 to represent HT_FREE and HT_DELETED. */ template class obj_hash_entry { T * m_ptr = nullptr; public: typedef T * data; unsigned get_hash() const { return m_ptr->hash(); } bool is_free() const { return m_ptr == nullptr; } bool is_deleted() const { return m_ptr == reinterpret_cast(1); } bool is_used() const { return m_ptr != reinterpret_cast(0) && m_ptr != reinterpret_cast(1); } T * get_data() const { return m_ptr; } T * & get_data() { return m_ptr; } void set_data(T * d) { m_ptr = d; } void set_hash(unsigned h) { SASSERT(h == m_ptr->hash()); } void mark_as_deleted() { m_ptr = reinterpret_cast(1); } void mark_as_free() { m_ptr = nullptr; } }; template class obj_hashtable : public core_hashtable, obj_ptr_hash, ptr_eq > { public: obj_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY): core_hashtable, obj_ptr_hash, ptr_eq >(initial_capacity) {} }; template class obj_map { public: struct key_data { Key * m_key; Value m_value; key_data():m_key(nullptr), m_value() { } key_data(Key * k): m_key(k), m_value() { } key_data(Key * k, Value const & v): m_key(k), m_value(v) { } key_data(Key * k, Value && v) : m_key(k), m_value(std::move(v)) { } Value const & get_value() const { return m_value; } Key & get_key () const { return *m_key; } unsigned hash() const { return m_key->hash(); } bool operator==(key_data const & other) const { return m_key == other.m_key; } }; class obj_map_entry { key_data m_data; public: typedef key_data data; unsigned get_hash() const { return m_data.hash(); } bool is_free() const { return m_data.m_key == nullptr; } bool is_deleted() const { return m_data.m_key == reinterpret_cast(1); } bool is_used() const { return m_data.m_key != reinterpret_cast(0) && m_data.m_key != reinterpret_cast(1); } key_data const & get_data() const { return m_data; } key_data & get_data() { return m_data; } void set_data(key_data && d) { m_data = std::move(d); } void set_hash(unsigned h) { SASSERT(h == m_data.hash()); } void mark_as_deleted() { m_data.m_key = reinterpret_cast(1); } void mark_as_free() { m_data.m_key = nullptr; } }; typedef core_hashtable, default_eq > table; table m_table; public: obj_map(): m_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY) {} typedef typename table::iterator iterator; typedef typename table::data data; typedef typename table::entry entry; typedef Key key; typedef Value value; void reset() { m_table.reset(); } void finalize() { m_table.finalize(); } bool empty() const { return m_table.empty(); } unsigned size() const { return m_table.size(); } unsigned capacity() const { return m_table.capacity(); } iterator begin() const { return m_table.begin(); } iterator end() const { return m_table.end(); } void insert(Key * const k, Value const & v) { m_table.insert(key_data(k, v)); } void insert(Key * const k, Value && v) { m_table.insert(key_data(k, std::move(v))); } Value& insert_if_not_there(Key * k, Value const & v) { return m_table.insert_if_not_there2(key_data(k, v))->get_data().m_value; } obj_map_entry * insert_if_not_there3(Key * k, Value const & v) { return m_table.insert_if_not_there2(key_data(k, v)); } obj_map_entry * find_core(Key * k) const { return m_table.find_core(key_data(k)); } bool find(Key * const k, Value & v) const { obj_map_entry * e = find_core(k); if (e) { v = e->get_data().m_value; } return (nullptr != e); } value const & find(key * k) const { obj_map_entry * e = find_core(k); SASSERT(e); return e->get_data().m_value; } value & find(key * k) { obj_map_entry * e = find_core(k); SASSERT(e); return e->get_data().m_value; } value const & operator[](key * k) const { return find(k); } value & operator[](key * k) { return find(k); } iterator find_iterator(Key * k) const { return m_table.find(key_data(k)); } bool contains(Key * k) const { return find_core(k) != nullptr; } void remove(Key * k) { m_table.remove(key_data(k)); } void erase(Key * k) { remove(k); } unsigned long long get_num_collision() const { return m_table.get_num_collision(); } void get_collisions(Key * k, vector& collisions) { vector cs; m_table.get_collisions(key_data(k), cs); for (key_data const& kd : cs) { collisions.push_back(kd.m_key); } } void swap(obj_map & other) { m_table.swap(other.m_table); } }; /** \brief Reset and deallocate the values stored in a mapping of the form obj_map */ template void reset_dealloc_values(obj_map & m) { for (auto & kv : m) { dealloc(kv.m_value); } m.reset(); } /** \brief Remove the key k from the mapping m, and delete the value associated with k. */ template void erase_dealloc_value(obj_map & m, Key * k) { Value * v = 0; bool contains = m.find(k, v); m.erase(k); if (contains) { dealloc(v); } }