AK: Support case-insensitive HashMap<String, T>.

We achieve this by allowing you to specify custom traits for the key type.
For convenience, we also provide a CaseInsensitiveStringTraits for String.
This commit is contained in:
Andreas Kling 2019-07-13 11:00:29 +02:00
parent b425de18cc
commit d9d13f2445
4 changed files with 22 additions and 6 deletions

View file

@ -219,6 +219,12 @@ struct Traits<String> : public GenericTraits<String> {
static void dump(const String& s) { kprintf("%s", s.characters()); }
};
struct CaseInsensitiveStringTraits : public AK::Traits<String> {
static unsigned hash(const String& s) { return s.impl() ? s.to_lowercase().impl()->hash() : 0; }
static bool equals(const String& a, const String& b) { return a.to_lowercase() == b.to_lowercase(); }
};
inline bool operator<(const char* characters, const String& string)
{
if (!characters)
@ -254,3 +260,4 @@ inline bool operator<=(const char* characters, const String& string)
}
using AK::String;
using AK::CaseInsensitiveStringTraits;

View file

@ -7,7 +7,7 @@
namespace AK {
template<typename K, typename V>
template<typename K, typename V, typename KeyTraits = Traits<K>>
class HashMap {
private:
struct Entry {
@ -16,12 +16,12 @@ private:
};
struct EntryTraits {
static unsigned hash(const Entry& entry) { return Traits<K>::hash(entry.key); }
static bool equals(const Entry& a, const Entry& b) { return a.key == b.key; }
static unsigned hash(const Entry& entry) { return KeyTraits::hash(entry.key); }
static bool equals(const Entry& a, const Entry& b) { return KeyTraits::equals(a.key, b.key); }
static void dump(const Entry& entry)
{
kprintf("key=");
Traits<K>::dump(entry.key);
KeyTraits::dump(entry.key);
kprintf(" value=");
Traits<V>::dump(entry.value);
}
@ -51,11 +51,11 @@ public:
IteratorType begin() { return m_table.begin(); }
IteratorType end() { return m_table.end(); }
IteratorType find(const K& key) { return m_table.find(Traits<K>::hash(key), [&](auto& entry) { return key == entry.key; }); }
IteratorType find(const K& key) { return m_table.find(KeyTraits::hash(key), [&](auto& entry) { return KeyTraits::equals(key, entry.key); }); }
ConstIteratorType begin() const { return m_table.begin(); }
ConstIteratorType end() const { return m_table.end(); }
ConstIteratorType find(const K& key) const { return m_table.find(Traits<K>::hash(key), [&](auto& entry) { return key == entry.key; }); }
ConstIteratorType find(const K& key) const { return m_table.find(KeyTraits::hash(key), [&](auto& entry) { return KeyTraits::equals(key, entry.key); }); }
void ensure_capacity(int capacity) { m_table.ensure_capacity(capacity); }

View file

@ -32,5 +32,14 @@ int main()
EXPECT(number_to_string.find(3) == number_to_string.end());
EXPECT_EQ(loop_counter, 3);
{
HashMap<String, int, CaseInsensitiveStringTraits> casemap;
EXPECT_EQ(String("nickserv").to_lowercase(), String("NickServ").to_lowercase());
casemap.set("nickserv", 3);
casemap.set("NickServ", 3);
EXPECT_EQ(casemap.size(), 1);
}
return 0;
}

0
AK/Tests/TestString.cpp Executable file → Normal file
View file