Fix util::hash_map with std::pair as keys
This commit is contained in:
parent
8a21e53ee1
commit
a49be3b253
1 changed files with 37 additions and 60 deletions
|
|
@ -165,14 +165,20 @@ namespace psemek::util
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Hash, typename Equal>
|
||||
template <typename T, typename Hash, typename Equal, typename KeyProjector>
|
||||
struct hash_table_impl
|
||||
: Hash, Equal
|
||||
: Hash, Equal, KeyProjector
|
||||
{
|
||||
template <typename H, typename K>
|
||||
hash_table_impl(H && h, K && k)
|
||||
: Hash(std::forward<H>(h))
|
||||
, Equal(std::forward<K>(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 <typename H>
|
||||
std::pair<hash_table_iterator<T>, 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<H>(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 <typename Key, typename Value, typename Hash>
|
||||
struct pair_hash
|
||||
: Hash
|
||||
struct id_key_projector
|
||||
{
|
||||
pair_hash(Hash const & hash)
|
||||
: Hash(hash)
|
||||
{}
|
||||
|
||||
template <typename Key1>
|
||||
std::size_t operator()(Key1 const & key) const
|
||||
template <typename Key>
|
||||
Key const & operator() (Key const & key) const
|
||||
{
|
||||
return static_cast<Hash const &>(*this)(key);
|
||||
}
|
||||
|
||||
template <typename Key1, typename Value1>
|
||||
std::size_t operator()(std::pair<Key1, Value1> const & pair) const
|
||||
{
|
||||
return static_cast<Hash const &>(*this)(pair.first);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Value, typename Equal>
|
||||
struct pair_equal
|
||||
: Equal
|
||||
struct pair_key_projector
|
||||
{
|
||||
pair_equal(Equal const & equal)
|
||||
: Equal(equal)
|
||||
{}
|
||||
|
||||
template <typename Key1, typename Key2, typename Value2>
|
||||
bool operator()(Key1 const & key1, std::pair<Key2, Value2> const & pair2) const
|
||||
template <typename Key, typename Value>
|
||||
Key const & operator() (std::pair<Key, Value> const & pair) const
|
||||
{
|
||||
return static_cast<Equal const &>(*this)(key1, pair2.first);
|
||||
}
|
||||
|
||||
template <typename Key1, typename Value1, typename Key2>
|
||||
bool operator()(std::pair<Key1, Value1> const & pair1, Key2 const & key2) const
|
||||
{
|
||||
return static_cast<Equal const &>(*this)(pair1.first, key2);
|
||||
}
|
||||
|
||||
template <typename Key1, typename Value1, typename Key2, typename Value2>
|
||||
bool operator()(std::pair<Key1, Value1> const & pair1, std::pair<Key2, Value2> const & pair2) const
|
||||
{
|
||||
return static_cast<Equal const &>(*this)(pair1.first, pair2.first);
|
||||
return pair.first;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -420,12 +397,12 @@ namespace psemek::util
|
|||
{
|
||||
using iterator = detail::hash_table_iterator<T const>;
|
||||
|
||||
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<T> init, Hash const & hash = {}, Equal const & equal = {})
|
||||
: impl_(hash, equal)
|
||||
hash_set(std::initializer_list<T> 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<T>
|
||||
: 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<T, Hash, Equal> impl_;
|
||||
detail::hash_table_impl<T, Hash, Equal, detail::id_key_projector> impl_;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>>
|
||||
template <typename Key, typename Value, typename KeyHash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>>
|
||||
struct hash_map
|
||||
{
|
||||
using iterator = detail::hash_table_iterator<std::pair<Key const, Value>>;
|
||||
|
||||
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<std::pair<Key, Value>> init, Hash const & hash = {}, KeyEqual const & equal = {})
|
||||
: impl_(hash, equal)
|
||||
hash_map(std::initializer_list<std::pair<Key, Value>> 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<std::pair<Key, Value>>
|
||||
: 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<std::pair<Key const, Value>, detail::pair_hash<Key, Value, Hash>, detail::pair_equal<Key, Value, KeyEqual>> impl_;
|
||||
detail::hash_table_impl<std::pair<Key const, Value>, KeyHash, KeyEqual, detail::pair_key_projector> impl_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue