Add ability to check if hashmap key is valid
This commit is contained in:
parent
0318efe1e6
commit
a4487f29e1
@ -67,21 +67,34 @@ namespace rexy::cx{
|
|||||||
private:
|
private:
|
||||||
array<mapped_type,N> m_values; //perfect hash table
|
array<mapped_type,N> m_values; //perfect hash table
|
||||||
array<size_type,N> m_g; //'salt' values for indexing into the perfect hash table
|
array<size_type,N> m_g; //'salt' values for indexing into the perfect hash table
|
||||||
|
array<size_type,N> m_key_hashes; //full hash values for keys to verify good index values
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr hashmap(const value_type(&elements)[N]);
|
constexpr hashmap(const value_type(&elements)[N])
|
||||||
|
noexcept(std::is_nothrow_default_constructible<value_type>::value &&
|
||||||
|
std::is_nothrow_copy_constructible<value_type>::value &&
|
||||||
|
std::is_nothrow_move_assignable<mapped_type>::value &&
|
||||||
|
std::is_nothrow_invocable<Hash,Key,size_t>::value);
|
||||||
|
|
||||||
//no key checks. give a correct key or get a random answer :)
|
//no key checks. give a correct key or get a random answer :)
|
||||||
template<class U, class UHash = hash<std::decay_t<U>>>
|
template<class U, class UHash = hash<std::decay_t<U>>>
|
||||||
constexpr reference operator[](U&& u)noexcept;
|
constexpr reference operator[](U&& u)noexcept;
|
||||||
template<class U, class UHash = hash<std::decay_t<U>>>
|
template<class U, class UHash = hash<std::decay_t<U>>>
|
||||||
constexpr const_reference operator[](U&& u)const noexcept;
|
constexpr const_reference operator[](U&& u)const noexcept;
|
||||||
|
|
||||||
|
template<class U, class UHash = hash<std::decay_t<U>>>
|
||||||
|
constexpr bool is_valid(U&& u)const noexcept;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Key, class Value, size_t N, class Hash>
|
template<class Key, class Value, size_t N, class Hash>
|
||||||
constexpr hashmap<Key,Value,N,Hash>::hashmap(const value_type(&elements)[N]){
|
constexpr hashmap<Key,Value,N,Hash>::hashmap(const value_type(&elements)[N])
|
||||||
|
noexcept(std::is_nothrow_default_constructible<value_type>::value &&
|
||||||
|
std::is_nothrow_copy_constructible<value_type>::value &&
|
||||||
|
std::is_nothrow_move_assignable<mapped_type>::value &&
|
||||||
|
std::is_nothrow_invocable<Hash,Key,size_t>::value)
|
||||||
|
{
|
||||||
array<vector<value_type,N>,N> buckets;
|
array<vector<value_type,N>,N> buckets;
|
||||||
array<bool,N> slots_used;
|
|
||||||
size_type current_bucket = 0;
|
size_type current_bucket = 0;
|
||||||
|
|
||||||
//place all keys into buckets
|
//place all keys into buckets
|
||||||
@ -101,13 +114,15 @@ namespace rexy::cx{
|
|||||||
if(bucket.size() <= 1)
|
if(bucket.size() <= 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
const auto hashval = Hash{}(bucket[0].key, 0);
|
||||||
|
|
||||||
array<bool,N> pass_slots_used;
|
array<bool,N> pass_slots_used;
|
||||||
vector<size_type,N> pass_slots;
|
vector<size_type,N> pass_slots;
|
||||||
size_type d = 1;
|
size_type d = 1;
|
||||||
|
|
||||||
for(size_type i = 0;i < bucket.size();){
|
for(size_type i = 0;i < bucket.size();){
|
||||||
size_type slot = Hash{}(bucket[i].key, d) % max_size;
|
size_type slot = Hash{}(bucket[i].key, d) % max_size;
|
||||||
if(pass_slots_used[slot] || slots_used[slot]){
|
if(pass_slots_used[slot] || m_key_hashes[slot] != 0){
|
||||||
//slot already in use, try another value for 'd'
|
//slot already in use, try another value for 'd'
|
||||||
++d;
|
++d;
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -121,12 +136,12 @@ namespace rexy::cx{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//store the successful value of 'd' at index of the first hash for this bucket
|
//store the successful value of 'd' at index of the first hash for this bucket
|
||||||
m_g[Hash{}(bucket[0].key, 0) % max_size] = d;
|
m_g[hashval % max_size] = d;
|
||||||
|
|
||||||
//take the value from the temporary bucket into the permanent slot
|
//take the value from the temporary bucket into the permanent slot
|
||||||
for(size_type i = 0;i < bucket.size();++i){
|
for(size_type i = 0;i < bucket.size();++i){
|
||||||
m_values[pass_slots[i]] = std::move(bucket[i].value);
|
m_values[pass_slots[i]] = std::move(bucket[i].value);
|
||||||
slots_used[pass_slots[i]] = true;
|
m_key_hashes[pass_slots[i]] = hashval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +152,14 @@ namespace rexy::cx{
|
|||||||
auto& bucket = buckets[current_bucket];
|
auto& bucket = buckets[current_bucket];
|
||||||
if(bucket.size() == 0)
|
if(bucket.size() == 0)
|
||||||
break;
|
break;
|
||||||
for(;slots_used[next_free_slot];++next_free_slot);
|
|
||||||
|
const auto hashval = Hash{}(bucket[0].key, 0);
|
||||||
|
|
||||||
|
for(;m_key_hashes[next_free_slot] != 0;++next_free_slot);
|
||||||
|
|
||||||
m_g[Hash{}(bucket[0].key, 0) % max_size] = (next_free_slot | single_bucket_bit);
|
m_g[Hash{}(bucket[0].key, 0) % max_size] = (next_free_slot | single_bucket_bit);
|
||||||
m_values[next_free_slot] = std::move(bucket[0].value);
|
m_values[next_free_slot] = std::move(bucket[0].value);
|
||||||
slots_used[next_free_slot] = true;
|
m_key_hashes[next_free_slot] = hashval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +181,16 @@ namespace rexy::cx{
|
|||||||
return m_values[UHash{}(std::forward<U>(key), d) % max_size];
|
return m_values[UHash{}(std::forward<U>(key), d) % max_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Key, class Value, size_t N, class Hash>
|
||||||
|
template<class U, class UHash>
|
||||||
|
constexpr bool hashmap<Key,Value,N,Hash>::is_valid(U&& key)const noexcept{
|
||||||
|
const auto hashval = UHash{}(std::forward<U>(key), 0);
|
||||||
|
const auto d = m_g[hashval % max_size];
|
||||||
|
if(d & single_bucket_bit){
|
||||||
|
return m_key_hashes[d & ~single_bucket_bit] == hashval;
|
||||||
|
}
|
||||||
|
return m_key_hashes[UHash{}(std::forward<U>(key), d) % max_size] == hashval;
|
||||||
|
}
|
||||||
|
|
||||||
template<class Key, class Value, size_t N, class Hash = hash<Key>>
|
template<class Key, class Value, size_t N, class Hash = hash<Key>>
|
||||||
constexpr auto make_hashmap(const typename hashmap<Key,Value,N,Hash>::value_type(&list)[N]){
|
constexpr auto make_hashmap(const typename hashmap<Key,Value,N,Hash>::value_type(&list)[N]){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user