diff --git a/libs/util/include/psemek/util/hash_table.hpp b/libs/util/include/psemek/util/hash_table.hpp index 983f1ac9..dc94a29f 100644 --- a/libs/util/include/psemek/util/hash_table.hpp +++ b/libs/util/include/psemek/util/hash_table.hpp @@ -165,14 +165,20 @@ namespace psemek::util } }; - template + template struct hash_table_impl - : Hash, Equal + : Hash, Equal, KeyProjector { - template - hash_table_impl(H && h, K && k) - : Hash(std::forward(h)) - , Equal(std::forward(k)) + hash_table_impl(Hash && hash, Equal && equal, KeyProjector && key_projector) + : Hash(std::move(hash)) + , Equal(std::move(equal)) + , KeyProjector(std::move(key_projector)) + {} + + hash_table_impl(Hash const & hash, Equal const & equal, KeyProjector const & key_projector) + : Hash(hash) + , Equal(equal) + , KeyProjector(key_projector) {} hash_table_impl(hash_table_impl && other) @@ -199,12 +205,13 @@ namespace psemek::util Hash const & hash() const { return *this; } Equal const & equal() const { return *this; } + KeyProjector const & key_projector() const { return *this; } template std::pair, bool> insert(H && value) { ensure_capacity_for(size_ + 1); - std::size_t hash = this->hash()(value); + std::size_t hash = this->hash()(this->key_projector()(value)); return insert_impl(std::forward(value), hash); } @@ -332,7 +339,7 @@ namespace psemek::util ++size_; return {storage_.iterator(index), true}; } - else if (entry.hash_equal(hash) && equal()(value, entry.value())) + else if (entry.hash_equal(hash) && equal()(key_projector()(value), key_projector()(entry.value()))) { return {storage_.iterator(index), false}; } @@ -355,7 +362,7 @@ namespace psemek::util { return end(); } - else if (entry.hash_equal(hash) && equal()(key, entry.value())) + else if (entry.hash_equal(hash) && equal()(key, key_projector()(entry.value()))) { return storage_.iterator(index); } @@ -365,51 +372,21 @@ namespace psemek::util } }; - template - struct pair_hash - : Hash + struct id_key_projector { - pair_hash(Hash const & hash) - : Hash(hash) - {} - - template - std::size_t operator()(Key1 const & key) const + template + Key const & operator() (Key const & key) const { - return static_cast(*this)(key); - } - - template - std::size_t operator()(std::pair const & pair) const - { - return static_cast(*this)(pair.first); + return key; } }; - template - struct pair_equal - : Equal + struct pair_key_projector { - pair_equal(Equal const & equal) - : Equal(equal) - {} - - template - bool operator()(Key1 const & key1, std::pair const & pair2) const + template + Key const & operator() (std::pair const & pair) const { - return static_cast(*this)(key1, pair2.first); - } - - template - bool operator()(std::pair const & pair1, Key2 const & key2) const - { - return static_cast(*this)(pair1.first, key2); - } - - template - bool operator()(std::pair const & pair1, std::pair const & pair2) const - { - return static_cast(*this)(pair1.first, pair2.first); + return pair.first; } }; @@ -420,12 +397,12 @@ namespace psemek::util { using iterator = detail::hash_table_iterator; - hash_set(Hash const & hash = {}, Equal const & equal = {}) - : impl_(hash, equal) + hash_set(Hash && hash = {}, Equal && equal = {}) + : impl_(hash, equal, {}) {} - hash_set(std::initializer_list init, Hash const & hash = {}, Equal const & equal = {}) - : impl_(hash, equal) + hash_set(std::initializer_list init, Hash && hash = {}, Equal && equal = {}) + : impl_(hash, equal, {}) { for (auto & value : init) insert(std::move(value)); @@ -434,7 +411,7 @@ namespace psemek::util hash_set(hash_set && other) = default; hash_set(hash_set const & other) requires std::is_copy_constructible_v - : impl_(other.impl_.hash(), other.impl_.equal()) + : impl_(other.impl_.hash(), other.impl_.equal(), other.impl_.key_projector()) { for (auto const & value : other) insert(value); @@ -540,20 +517,20 @@ namespace psemek::util } private: - detail::hash_table_impl impl_; + detail::hash_table_impl impl_; }; - template , typename KeyEqual = std::equal_to> + template , typename KeyEqual = std::equal_to> struct hash_map { using iterator = detail::hash_table_iterator>; - hash_map(Hash const & hash = {}, KeyEqual const & equal = {}) - : impl_(hash, equal) + hash_map(KeyHash && hash = {}, KeyEqual && equal = {}) + : impl_(hash, equal, {}) {} - hash_map(std::initializer_list> init, Hash const & hash = {}, KeyEqual const & equal = {}) - : impl_(hash, equal) + hash_map(std::initializer_list> init, KeyHash && hash = {}, KeyEqual && equal = {}) + : impl_(hash, equal, {}) { for (auto & pair : init) insert(std::move(pair)); @@ -562,7 +539,7 @@ namespace psemek::util hash_map(hash_map && other) = default; hash_map(hash_map const & other) requires std::is_copy_constructible_v> - : impl_(other.impl_.hash(), other.impl_.equal()) + : impl_(other.impl_.hash(), other.impl_.equal(), other.impl_.key_projector()) { for (auto const & pair : other) insert({pair.first, pair.second}); @@ -715,7 +692,7 @@ namespace psemek::util } private: - detail::hash_table_impl, detail::pair_hash, detail::pair_equal> impl_; + detail::hash_table_impl, KeyHash, KeyEqual, detail::pair_key_projector> impl_; }; }