From 714d9fe433341783a381da442c7073bc87a401e3 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 7 Aug 2022 10:23:09 -0500 Subject: [PATCH] [ox/std] Add support for integral types as keys in HashMap --- deps/ox/src/ox/std/hashmap.hpp | 30 +++++++++++++++++++++--------- deps/ox/src/ox/std/test/tests.cpp | 15 ++++++++++----- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/deps/ox/src/ox/std/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp index 1b7c1877..469f0efe 100644 --- a/deps/ox/src/ox/std/hashmap.hpp +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -76,7 +76,7 @@ class HashMap { /** * K is assumed to be a null terminated string. */ - constexpr static uint64_t hash(K, int len = 0xFFFF) noexcept; + constexpr static uint64_t hash(auto) noexcept; /** * K is assumed to be a null terminated string. @@ -182,16 +182,13 @@ constexpr void HashMap::erase(const K &k) { return; } auto h = hash(k) % m_pairs.size(); - char hashStr[sizeof(h) + 1]; - ox_memcpy(hashStr, &h, sizeof(h)); - hashStr[sizeof(h)] = 0; while (true) { const auto &p = m_pairs[h]; if (p == nullptr || ox_strcmp(p->key, k) == 0) { oxIgnoreError(m_pairs.erase(h)); break; } else { - h = hash(hashStr, 8) % m_pairs.size(); + h = hash(h) % m_pairs.size(); } } oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k))); @@ -232,10 +229,18 @@ constexpr void HashMap::expand() { } template -constexpr uint64_t HashMap::hash(K k, int len) noexcept { +constexpr uint64_t HashMap::hash(auto k) noexcept { uint64_t sum = 1; - for (auto i = 0u; i < static_cast(len) && k[i]; ++i) { - sum += ((sum + static_cast(k[i])) * 7) * sum; + if constexpr(is_integral_v) { + for (auto i = 0u; i < sizeof(K); ++i) { + const auto shift = i * 8; + const auto v = static_cast(k >> shift & 0xff); + sum += (sum + v) * 7 * sum; + } + } else { + for (auto i = 0u; k[i]; ++i) { + sum += ((sum + static_cast(k[i])) * 7) * sum; + } } return sum; } @@ -258,7 +263,14 @@ constexpr typename HashMap::Pair *&HashMap::access(Vector &pa auto h = hash(k) % pairs.size(); while (true) { auto &p = pairs[h]; - if (p == nullptr || ox_strcmp(p->key, k) == 0) { + bool matches = [&] { + if constexpr (is_integral_v) { + return p == nullptr || k == p->key; + } else { + return p == nullptr || ox_strcmp(p->key, k) == 0; + } + }(); + if (matches) { return p; } else { h = (h + 1) % pairs.size(); diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index e2d17843..952e38b1 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -109,11 +109,16 @@ std::map tests = { { "HashMap", [] { - ox::HashMap v; - v["asdf"] = 42; - v["aoeu"] = 100; - oxAssert(v["asdf"] == 42, "asdf != 42"); - oxAssert(v["aoeu"] == 100, "aoeu != 100"); + ox::HashMap si; + si["asdf"] = 42; + si["aoeu"] = 100; + oxAssert(si["asdf"] == 42, "asdf != 42"); + oxAssert(si["aoeu"] == 100, "aoeu != 100"); + ox::HashMap ii; + ii[4] = 42; + ii[5] = 100; + oxAssert(ii[4] == 42, "4 != 42"); + oxAssert(ii[5] == 100, "5 != 100"); return OxError(0); } },