BAN: Rewrite HashMap as a wrapper around HashSet
There is really no need to have two implementation of the same thing. Only difference now is that HashMap's value type has to be movable but this wasn't an issue
This commit is contained in:
@@ -1,49 +1,128 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Hash.h>
|
#include <BAN/HashSet.h>
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
template<typename HashSetIt, typename HashMap, typename Entry>
|
||||||
|
class HashMapIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashMapIterator() = default;
|
||||||
|
|
||||||
|
Entry& operator*()
|
||||||
|
{
|
||||||
|
return m_iterator.operator*();
|
||||||
|
}
|
||||||
|
const Entry& operator*() const
|
||||||
|
{
|
||||||
|
return m_iterator.operator*();
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* operator->()
|
||||||
|
{
|
||||||
|
return m_iterator.operator->();
|
||||||
|
}
|
||||||
|
const Entry* operator->() const
|
||||||
|
{
|
||||||
|
return m_iterator.operator->();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMapIterator& operator++()
|
||||||
|
{
|
||||||
|
++m_iterator;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
HashMapIterator operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(HashMapIterator other) const
|
||||||
|
{
|
||||||
|
return m_iterator == other.m_iterator;
|
||||||
|
}
|
||||||
|
bool operator!=(HashMapIterator other) const
|
||||||
|
{
|
||||||
|
return m_iterator != other.m_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit HashMapIterator(HashSetIt it)
|
||||||
|
: m_iterator(it)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashSetIt m_iterator;
|
||||||
|
friend HashMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>, typename COMP = BAN::equal<Key>>
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
template<typename... Args>
|
|
||||||
Entry(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
: key(key)
|
|
||||||
, value(forward<Args>(args)...)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
Entry(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
: key(BAN::move(key))
|
|
||||||
, value(forward<Args>(args)...)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Key key;
|
Key key;
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EntryHash
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const Key& a)
|
||||||
|
{
|
||||||
|
return HASH()(a);
|
||||||
|
}
|
||||||
|
constexpr bool operator()(const Entry& a)
|
||||||
|
{
|
||||||
|
return HASH()(a.key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntryComp
|
||||||
|
{
|
||||||
|
constexpr bool operator()(const Entry& a, const Key& b)
|
||||||
|
{
|
||||||
|
return COMP()(a.key, b);
|
||||||
|
}
|
||||||
|
constexpr bool operator()(const Entry& a, const Entry& b)
|
||||||
|
{
|
||||||
|
return COMP()(a.key, b.key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
using iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::iterator, HashMap, Entry>;
|
||||||
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
|
using const_iterator = HashMapIterator<typename HashSet<Entry, EntryHash, EntryComp>::const_iterator, HashMap, const Entry>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
HashMap(const HashMap<Key, T, HASH>&);
|
~HashMap() { clear(); }
|
||||||
HashMap(HashMap<Key, T, HASH>&&);
|
|
||||||
~HashMap();
|
|
||||||
|
|
||||||
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
HashMap(const HashMap<Key, T, HASH>& other) { *this = other; }
|
||||||
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>& other)
|
||||||
|
{
|
||||||
|
m_hash_set = other.m_hash_set;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap(HashMap<Key, T, HASH>&& other) { *this = BAN::move(other); }
|
||||||
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&& other)
|
||||||
|
{
|
||||||
|
m_hash_set = BAN::move(other.m_hash_set);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() { return iterator(m_hash_set.begin()); }
|
||||||
|
iterator end() { return iterator(m_hash_set.end()); }
|
||||||
|
const_iterator begin() const { return const_iterator(m_hash_set.begin()); }
|
||||||
|
const_iterator end() const { return const_iterator(m_hash_set.end()); }
|
||||||
|
|
||||||
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
ErrorOr<iterator> insert(const Key& key, const T& value) { return emplace(key, value); }
|
||||||
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
ErrorOr<iterator> insert(const Key& key, T&& value) { return emplace(key, move(value)); }
|
||||||
@@ -57,263 +136,96 @@ namespace BAN
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<iterator> emplace(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{ return emplace(Key(key), forward<Args>(args)...); }
|
{ return emplace(Key(key), BAN::forward<Args>(args)...); }
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<iterator> emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
{
|
||||||
|
ASSERT(!contains(key));
|
||||||
|
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
||||||
|
return iterator(it);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
ErrorOr<iterator> emplace_or_assign(const Key& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
{ return emplace_or_assign(Key(key), forward<Args>(args)...); }
|
{ return emplace_or_assign(Key(key), BAN::forward<Args>(args)...); }
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<iterator> emplace_or_assign(Key&&, Args&&...) requires is_constructible_v<T, Args...>;
|
ErrorOr<iterator> emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
||||||
|
|
||||||
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
|
|
||||||
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
|
|
||||||
|
|
||||||
ErrorOr<void> reserve(size_type);
|
|
||||||
|
|
||||||
void remove(const Key&);
|
|
||||||
void remove(iterator it);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
T& operator[](const Key&);
|
|
||||||
const T& operator[](const Key&) const;
|
|
||||||
|
|
||||||
iterator find(const Key& key);
|
|
||||||
const_iterator find(const Key& key) const;
|
|
||||||
bool contains(const Key&) const;
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
size_type size() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ErrorOr<void> rebucket(size_type);
|
|
||||||
LinkedList<Entry>& get_bucket(const Key&);
|
|
||||||
const LinkedList<Entry>& get_bucket(const Key&) const;
|
|
||||||
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
|
|
||||||
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vector<LinkedList<Entry>> m_buckets;
|
|
||||||
size_type m_size = 0;
|
|
||||||
|
|
||||||
friend iterator;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
|
|
||||||
{
|
{
|
||||||
*this = other;
|
if (auto it = m_hash_set.find(key); it != m_hash_set.end())
|
||||||
|
{
|
||||||
|
it->value = T(BAN::forward<Args>(args)...);
|
||||||
|
return iterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
auto it = TRY(m_hash_set.insert(Entry { BAN::move(key), T(BAN::forward<Args>(args)...) }));
|
||||||
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
|
return iterator(it);
|
||||||
{
|
|
||||||
*this = move(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
void remove(const Key& key)
|
||||||
HashMap<Key, T, HASH>::~HashMap()
|
|
||||||
{
|
{
|
||||||
clear();
|
if (auto it = find(key); it != end())
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
m_buckets = other.m_buckets;
|
|
||||||
m_size = other.m_size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
m_buckets = move(other.m_buckets);
|
|
||||||
m_size = other.m_size;
|
|
||||||
other.m_size = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
|
||||||
ASSERT(!contains(key));
|
|
||||||
TRY(rebucket(m_size + 1));
|
|
||||||
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
TRY(bucket_it->emplace_back(move(key), forward<Args>(args)...));
|
|
||||||
m_size++;
|
|
||||||
|
|
||||||
return iterator(m_buckets.end(), bucket_it, prev(bucket_it->end(), 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
template<typename... Args>
|
|
||||||
ErrorOr<typename HashMap<Key, T, HASH>::iterator> HashMap<Key, T, HASH>::emplace_or_assign(Key&& key, Args&&... args) requires is_constructible_v<T, Args...>
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return emplace(move(key), forward<Args>(args)...);
|
|
||||||
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
for (auto entry_it = bucket_it->begin(); entry_it != bucket_it->end(); entry_it++)
|
|
||||||
{
|
|
||||||
if (entry_it->key != key)
|
|
||||||
continue;
|
|
||||||
entry_it->value = T(forward<Args>(args)...);
|
|
||||||
return iterator(m_buckets.end(), bucket_it, entry_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
return emplace(move(key), forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
|
|
||||||
{
|
|
||||||
TRY(rebucket(size));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
void HashMap<Key, T, HASH>::remove(const Key& key)
|
|
||||||
{
|
|
||||||
auto it = find(key);
|
|
||||||
if (it != end())
|
|
||||||
remove(it);
|
remove(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
iterator remove(iterator it)
|
||||||
void HashMap<Key, T, HASH>::remove(iterator it)
|
|
||||||
{
|
{
|
||||||
it.outer_current()->remove(it.inner_current());
|
return iterator(m_hash_set.remove(it.m_iterator));
|
||||||
m_size--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename U> requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); }
|
||||||
void HashMap<Key, T, HASH>::clear()
|
iterator find(const U& key)
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
return iterator(m_hash_set.find(key));
|
||||||
m_size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
template<typename U> requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); }
|
||||||
T& HashMap<Key, T, HASH>::operator[](const Key& key)
|
const_iterator find(const U& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
return const_iterator(m_hash_set.find(key));
|
||||||
auto& bucket = get_bucket(key);
|
|
||||||
for (Entry& entry : bucket)
|
|
||||||
if (entry.key == key)
|
|
||||||
return entry.value;
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
void clear()
|
||||||
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
|
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
m_hash_set.clear();
|
||||||
const auto& bucket = get_bucket(key);
|
|
||||||
for (const Entry& entry : bucket)
|
|
||||||
if (entry.key == key)
|
|
||||||
return entry.value;
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
ErrorOr<void> reserve(size_type size)
|
||||||
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
|
|
||||||
{
|
{
|
||||||
if (empty())
|
return m_hash_set.reserve(size);
|
||||||
return end();
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
|
||||||
if (it->key == key)
|
|
||||||
return iterator(m_buckets.end(), bucket_it, it);
|
|
||||||
return end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
T& operator[](const Key& key)
|
||||||
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
|
|
||||||
{
|
{
|
||||||
if (empty())
|
return find(key)->value;
|
||||||
return end();
|
|
||||||
auto bucket_it = get_bucket_iterator(key);
|
|
||||||
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
|
|
||||||
if (it->key == key)
|
|
||||||
return const_iterator(m_buckets.end(), bucket_it, it);
|
|
||||||
return end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
const T& operator[](const Key& key) const
|
||||||
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
{
|
||||||
|
return find(key)->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const Key& key) const
|
||||||
{
|
{
|
||||||
return find(key) != end();
|
return find(key) != end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
size_type capacity() const
|
||||||
bool HashMap<Key, T, HASH>::empty() const
|
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_hash_set.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
size_type size() const
|
||||||
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
|
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_hash_set.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
bool empty() const
|
||||||
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
|
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
return m_hash_set.empty();
|
||||||
return {};
|
|
||||||
|
|
||||||
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
|
|
||||||
Vector<LinkedList<Entry>> new_buckets;
|
|
||||||
TRY(new_buckets.resize(new_bucket_count));
|
|
||||||
|
|
||||||
for (auto& bucket : m_buckets)
|
|
||||||
{
|
|
||||||
for (auto it = bucket.begin(); it != bucket.end();)
|
|
||||||
{
|
|
||||||
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
|
|
||||||
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buckets = move(new_buckets);
|
private:
|
||||||
return {};
|
HashSet<Entry, EntryHash, EntryComp> m_hash_set;
|
||||||
}
|
};
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
|
||||||
{
|
|
||||||
return *get_bucket_iterator(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
|
||||||
{
|
|
||||||
return *get_bucket_iterator(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
|
|
||||||
{
|
|
||||||
ASSERT(!m_buckets.empty());
|
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
|
||||||
return next(m_buckets.begin(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH>
|
|
||||||
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
|
|
||||||
{
|
|
||||||
ASSERT(!m_buckets.empty());
|
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
|
||||||
return next(m_buckets.begin(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,20 +19,14 @@
|
|||||||
namespace LibInput
|
namespace LibInput
|
||||||
{
|
{
|
||||||
|
|
||||||
struct StringViewLower
|
struct StringViewLowerComp
|
||||||
{
|
{
|
||||||
BAN::StringView value;
|
constexpr bool operator()(const BAN::StringView& a, const BAN::StringView& b) const
|
||||||
|
|
||||||
StringViewLower(BAN::StringView sv)
|
|
||||||
: value(sv)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool operator==(const StringViewLower& other) const
|
|
||||||
{
|
{
|
||||||
if (value.size() != other.value.size())
|
if (a.size() != b.size())
|
||||||
return false;
|
return false;
|
||||||
for (size_t i = 0; i < value.size(); i++)
|
for (size_t i = 0; i < a.size(); i++)
|
||||||
if (tolower(value[i]) != tolower(other.value[i]))
|
if (tolower(a[i]) != tolower(b[i]))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -40,16 +34,16 @@ namespace LibInput
|
|||||||
|
|
||||||
struct StringViewLowerHash
|
struct StringViewLowerHash
|
||||||
{
|
{
|
||||||
BAN::hash_t operator()(const StringViewLower& value) const
|
BAN::hash_t operator()(const BAN::StringView& str) const
|
||||||
{
|
{
|
||||||
constexpr BAN::hash_t FNV_offset_basis = 0x811c9dc5;
|
constexpr BAN::hash_t FNV_offset_basis = 0x811c9dc5;
|
||||||
constexpr BAN::hash_t FNV_prime = 0x01000193;
|
constexpr BAN::hash_t FNV_prime = 0x01000193;
|
||||||
|
|
||||||
BAN::hash_t hash = FNV_offset_basis;
|
BAN::hash_t hash = FNV_offset_basis;
|
||||||
for (size_t i = 0; i < value.value.size(); i++)
|
for (size_t i = 0; i < str.size(); i++)
|
||||||
{
|
{
|
||||||
hash *= FNV_prime;
|
hash *= FNV_prime;
|
||||||
hash ^= (uint8_t)tolower(value.value[i]);
|
hash ^= (uint8_t)tolower(str[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
@@ -113,7 +107,7 @@ namespace LibInput
|
|||||||
return keycode;
|
return keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BAN::HashMap<StringViewLower, Key, StringViewLowerHash> s_name_to_key;
|
static BAN::HashMap<BAN::StringView, Key, StringViewLowerHash, StringViewLowerComp> s_name_to_key;
|
||||||
static BAN::ErrorOr<void> initialize_name_to_key();
|
static BAN::ErrorOr<void> initialize_name_to_key();
|
||||||
|
|
||||||
static BAN::Optional<Key> parse_key(BAN::StringView name)
|
static BAN::Optional<Key> parse_key(BAN::StringView name)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <BAN/Endianness.h>
|
#include <BAN/Endianness.h>
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <BAN/IPv4.h>
|
#include <BAN/IPv4.h>
|
||||||
|
#include <BAN/LinkedList.h>
|
||||||
#include <BAN/String.h>
|
#include <BAN/String.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user