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
|
struct hash_table_impl
|
||||||
: Hash, Equal
|
: Hash, Equal, KeyProjector
|
||||||
{
|
{
|
||||||
template <typename H, typename K>
|
hash_table_impl(Hash && hash, Equal && equal, KeyProjector && key_projector)
|
||||||
hash_table_impl(H && h, K && k)
|
: Hash(std::move(hash))
|
||||||
: Hash(std::forward<H>(h))
|
, Equal(std::move(equal))
|
||||||
, Equal(std::forward<K>(k))
|
, 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)
|
hash_table_impl(hash_table_impl && other)
|
||||||
|
|
@ -199,12 +205,13 @@ namespace psemek::util
|
||||||
|
|
||||||
Hash const & hash() const { return *this; }
|
Hash const & hash() const { return *this; }
|
||||||
Equal const & equal() const { return *this; }
|
Equal const & equal() const { return *this; }
|
||||||
|
KeyProjector const & key_projector() const { return *this; }
|
||||||
|
|
||||||
template <typename H>
|
template <typename H>
|
||||||
std::pair<hash_table_iterator<T>, bool> insert(H && value)
|
std::pair<hash_table_iterator<T>, bool> insert(H && value)
|
||||||
{
|
{
|
||||||
ensure_capacity_for(size_ + 1);
|
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);
|
return insert_impl(std::forward<H>(value), hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,7 +339,7 @@ namespace psemek::util
|
||||||
++size_;
|
++size_;
|
||||||
return {storage_.iterator(index), true};
|
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};
|
return {storage_.iterator(index), false};
|
||||||
}
|
}
|
||||||
|
|
@ -355,7 +362,7 @@ namespace psemek::util
|
||||||
{
|
{
|
||||||
return end();
|
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);
|
return storage_.iterator(index);
|
||||||
}
|
}
|
||||||
|
|
@ -365,51 +372,21 @@ namespace psemek::util
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Hash>
|
struct id_key_projector
|
||||||
struct pair_hash
|
|
||||||
: Hash
|
|
||||||
{
|
{
|
||||||
pair_hash(Hash const & hash)
|
template <typename Key>
|
||||||
: Hash(hash)
|
Key const & operator() (Key const & key) const
|
||||||
{}
|
|
||||||
|
|
||||||
template <typename Key1>
|
|
||||||
std::size_t operator()(Key1 const & key) const
|
|
||||||
{
|
{
|
||||||
return static_cast<Hash const &>(*this)(key);
|
return 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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Equal>
|
struct pair_key_projector
|
||||||
struct pair_equal
|
|
||||||
: Equal
|
|
||||||
{
|
{
|
||||||
pair_equal(Equal const & equal)
|
template <typename Key, typename Value>
|
||||||
: Equal(equal)
|
Key const & operator() (std::pair<Key, Value> const & pair) const
|
||||||
{}
|
|
||||||
|
|
||||||
template <typename Key1, typename Key2, typename Value2>
|
|
||||||
bool operator()(Key1 const & key1, std::pair<Key2, Value2> const & pair2) const
|
|
||||||
{
|
{
|
||||||
return static_cast<Equal const &>(*this)(key1, pair2.first);
|
return pair.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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -420,12 +397,12 @@ namespace psemek::util
|
||||||
{
|
{
|
||||||
using iterator = detail::hash_table_iterator<T const>;
|
using iterator = detail::hash_table_iterator<T const>;
|
||||||
|
|
||||||
hash_set(Hash const & hash = {}, Equal const & equal = {})
|
hash_set(Hash && hash = {}, Equal && equal = {})
|
||||||
: impl_(hash, equal)
|
: impl_(hash, equal, {})
|
||||||
{}
|
{}
|
||||||
|
|
||||||
hash_set(std::initializer_list<T> init, Hash const & hash = {}, Equal const & equal = {})
|
hash_set(std::initializer_list<T> init, Hash && hash = {}, Equal && equal = {})
|
||||||
: impl_(hash, equal)
|
: impl_(hash, equal, {})
|
||||||
{
|
{
|
||||||
for (auto & value : init)
|
for (auto & value : init)
|
||||||
insert(std::move(value));
|
insert(std::move(value));
|
||||||
|
|
@ -434,7 +411,7 @@ namespace psemek::util
|
||||||
hash_set(hash_set && other) = default;
|
hash_set(hash_set && other) = default;
|
||||||
|
|
||||||
hash_set(hash_set const & other) requires std::is_copy_constructible_v<T>
|
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)
|
for (auto const & value : other)
|
||||||
insert(value);
|
insert(value);
|
||||||
|
|
@ -540,20 +517,20 @@ namespace psemek::util
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
struct hash_map
|
||||||
{
|
{
|
||||||
using iterator = detail::hash_table_iterator<std::pair<Key const, Value>>;
|
using iterator = detail::hash_table_iterator<std::pair<Key const, Value>>;
|
||||||
|
|
||||||
hash_map(Hash const & hash = {}, KeyEqual const & equal = {})
|
hash_map(KeyHash && hash = {}, KeyEqual && equal = {})
|
||||||
: impl_(hash, equal)
|
: impl_(hash, equal, {})
|
||||||
{}
|
{}
|
||||||
|
|
||||||
hash_map(std::initializer_list<std::pair<Key, Value>> init, Hash const & hash = {}, KeyEqual const & equal = {})
|
hash_map(std::initializer_list<std::pair<Key, Value>> init, KeyHash && hash = {}, KeyEqual && equal = {})
|
||||||
: impl_(hash, equal)
|
: impl_(hash, equal, {})
|
||||||
{
|
{
|
||||||
for (auto & pair : init)
|
for (auto & pair : init)
|
||||||
insert(std::move(pair));
|
insert(std::move(pair));
|
||||||
|
|
@ -562,7 +539,7 @@ namespace psemek::util
|
||||||
hash_map(hash_map && other) = default;
|
hash_map(hash_map && other) = default;
|
||||||
|
|
||||||
hash_map(hash_map const & other) requires std::is_copy_constructible_v<std::pair<Key, Value>>
|
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)
|
for (auto const & pair : other)
|
||||||
insert({pair.first, pair.second});
|
insert({pair.first, pair.second});
|
||||||
|
|
@ -715,7 +692,7 @@ namespace psemek::util
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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