diff --git a/deps/ox/src/ox/model/types.hpp b/deps/ox/src/ox/model/types.hpp index bf178810..323279b9 100644 --- a/deps/ox/src/ox/model/types.hpp +++ b/deps/ox/src/ox/model/types.hpp @@ -79,9 +79,6 @@ static_assert(isBasicString_v>); static_assert(isBasicString_v>); static_assert(isBasicString_v); -template -constexpr bool isOxString_v = isBString_v || isBasicString_v; - template consteval bool isOxVector(const T*) noexcept { return false; diff --git a/deps/ox/src/ox/std/concepts.hpp b/deps/ox/src/ox/std/concepts.hpp index d4667963..6b9f32be 100644 --- a/deps/ox/src/ox/std/concepts.hpp +++ b/deps/ox/src/ox/std/concepts.hpp @@ -23,35 +23,10 @@ concept CommonRefWith = ox::is_same_v, template concept same_as = ox::is_same_v; -template -class BasicString; -template -class BString; -class StringView; - -namespace detail { - -constexpr auto isOxString(const auto*) noexcept { - return false; -} - -template -constexpr auto isOxString(const BasicString*) noexcept { - return true; -} - -template -constexpr auto isOxString(const BString*) noexcept { - return true; -} - -constexpr auto isOxString(const StringView*) noexcept { - return true; -} - -} +template +concept OxString_c = isOxString_v; template -concept OxString_c = detail::isOxString(static_cast(nullptr)); +concept Integral_c = ox::is_integral_v; } diff --git a/deps/ox/src/ox/std/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp index 589e49fb..4cbab67f 100644 --- a/deps/ox/src/ox/std/hashmap.hpp +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -9,6 +9,7 @@ #pragma once #include "algorithm.hpp" +#include "stringview.hpp" #include "strops.hpp" #include "vector.hpp" @@ -21,6 +22,21 @@ class HashMap { using value_t = T; private: + // Maybe StringView. If K (or KK for MaybeSV) is a string type, + // MaybeSV::type/MaybeSV_t is a StringView. + // This avoids creating unnecessary Strings when taking a StringView or C + // string in lookups. + template> + struct MaybeSV { + using type = KK; + }; + template + struct MaybeSV { + using type = ox::StringView; + }; + template + using MaybeSV_t = MaybeSV::type; + struct Pair { K key = {}; T value{}; @@ -31,62 +47,55 @@ class HashMap { public: explicit constexpr HashMap(std::size_t size = 100); - constexpr HashMap(const HashMap &other); + constexpr HashMap(HashMap const&other); constexpr HashMap(HashMap &&other) noexcept; constexpr ~HashMap(); - constexpr bool operator==(const HashMap &other) const; + constexpr bool operator==(HashMap const&other) const; - constexpr HashMap &operator=(const HashMap &other); + constexpr HashMap &operator=(HashMap const&other); constexpr HashMap &operator=(HashMap &&other) noexcept; - /** - * K is assumed to be a null terminated string. - */ - constexpr T &operator[](const K &key); + constexpr T &operator[](MaybeSV_t const&key); - /** - * K is assumed to be a null terminated string. - */ - constexpr Result at(const K &key) noexcept; + constexpr Result at(MaybeSV_t const&key) noexcept; - /** - * K is assumed to be a null terminated string. - */ - constexpr Result at(const K &key) const noexcept; + constexpr Result at(MaybeSV_t const&key) const noexcept; - constexpr void erase(const K &key); + constexpr void erase(MaybeSV_t const&key); - constexpr bool contains(const K &key) const noexcept; + [[nodiscard]] + constexpr bool contains(MaybeSV_t const&key) const noexcept; [[nodiscard]] constexpr std::size_t size() const noexcept; [[nodiscard]] - constexpr const Vector &keys() const noexcept; + constexpr Vector const&keys() const noexcept; constexpr void clear(); private: constexpr void expand(); - /** - * K is assumed to be a null terminated string. - */ - constexpr static uint64_t hash(auto) noexcept; + constexpr static uint64_t hash(Integral_c auto) noexcept; + + constexpr static uint64_t hash(StringView const&) noexcept; /** * K is assumed to be a null terminated string. */ - constexpr Pair *const&access(const Vector &pairs, const K &key) const; + template + constexpr Pair *const&access(Vector const&pairs, KK const&key) const; /** * K is assumed to be a null terminated string. */ - constexpr Pair *&access(Vector &pairs, const K &key); + template + constexpr Pair *&access(Vector &pairs, KK const&key); }; @@ -95,7 +104,7 @@ constexpr HashMap::HashMap(std::size_t size): m_pairs(size) { } template -constexpr HashMap::HashMap(const HashMap &other) { +constexpr HashMap::HashMap(HashMap const&other) { m_pairs = other.m_pairs; } @@ -111,7 +120,7 @@ constexpr HashMap::~HashMap() { } template -constexpr bool HashMap::operator==(const HashMap &other) const { +constexpr bool HashMap::operator==(HashMap const&other) const { if (m_keys != other.m_keys) { return false; } @@ -125,7 +134,7 @@ constexpr bool HashMap::operator==(const HashMap &other) const { } template -constexpr HashMap &HashMap::operator=(const HashMap &other) { +constexpr HashMap &HashMap::operator=(HashMap const&other) { if (this != &other) { clear(); m_keys = other.m_keys; @@ -145,7 +154,7 @@ constexpr HashMap &HashMap::operator=(HashMap &&other) noexcep } template -constexpr T &HashMap::operator[](const K &k) { +constexpr T &HashMap::operator[](MaybeSV_t const&k) { auto &p = access(m_pairs, k); if (p == nullptr) { if (static_cast(m_pairs.size()) * 0.7 < @@ -154,13 +163,13 @@ constexpr T &HashMap::operator[](const K &k) { } p = new Pair; p->key = k; - m_keys.push_back(k); + m_keys.emplace_back(k); } return p->value; } template -constexpr Result HashMap::at(const K &k) noexcept { +constexpr Result HashMap::at(MaybeSV_t const&k) noexcept { auto p = access(m_pairs, k); if (!p) { return {nullptr, OxError(1, "value not found for given key")}; @@ -169,7 +178,7 @@ constexpr Result HashMap::at(const K &k) noexcept { } template -constexpr Result HashMap::at(const K &k) const noexcept { +constexpr Result HashMap::at(MaybeSV_t const&k) const noexcept { auto p = access(m_pairs, k); if (!p) { return {nullptr, OxError(1, "value not found for given key")}; @@ -178,7 +187,7 @@ constexpr Result HashMap::at(const K &k) const noexcept { } template -constexpr void HashMap::erase(const K &k) { +constexpr void HashMap::erase(MaybeSV_t const&k) { if (!contains(k)) { return; } @@ -196,7 +205,7 @@ constexpr void HashMap::erase(const K &k) { } template -constexpr bool HashMap::contains(const K &k) const noexcept { +constexpr bool HashMap::contains(MaybeSV_t const&k) const noexcept { return access(m_pairs, k) != nullptr; } @@ -206,7 +215,7 @@ constexpr std::size_t HashMap::size() const noexcept { } template -constexpr const Vector &HashMap::keys() const noexcept { +constexpr Vector const&HashMap::keys() const noexcept { return m_keys; } @@ -230,24 +239,28 @@ constexpr void HashMap::expand() { } template -constexpr uint64_t HashMap::hash(auto k) noexcept { +constexpr uint64_t HashMap::hash(Integral_c auto k) noexcept { uint64_t sum = 1; - 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; - } + 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; } return sum; } template -constexpr typename HashMap::Pair *const&HashMap::access(const Vector &pairs, const K &k) const { +constexpr uint64_t HashMap::hash(StringView const&k) noexcept { + uint64_t sum = 1; + for (auto i = 0u; i < k.len(); ++i) { + sum += ((sum + static_cast(k[i])) * 7) * sum; + } + return sum; +} + +template +template +constexpr typename HashMap::Pair *const&HashMap::access(Vector const&pairs, KK const&k) const { auto h = static_cast(hash(k) % pairs.size()); while (true) { const auto &p = pairs[h]; @@ -260,12 +273,13 @@ constexpr typename HashMap::Pair *const&HashMap::access(const Vector } template -constexpr typename HashMap::Pair *&HashMap::access(Vector &pairs, const K &k) { +template +constexpr typename HashMap::Pair *&HashMap::access(Vector &pairs, KK const&k) { auto h = static_cast(hash(k) % pairs.size()); while (true) { auto &p = pairs[h]; bool matches = [&] { - if constexpr (is_integral_v) { + if constexpr (is_integral_v) { return p == nullptr || k == p->key; } else { return p == nullptr || ox_strcmp(p->key, k) == 0; diff --git a/deps/ox/src/ox/std/typetraits.hpp b/deps/ox/src/ox/std/typetraits.hpp index 068ca274..ec0f33e5 100644 --- a/deps/ox/src/ox/std/typetraits.hpp +++ b/deps/ox/src/ox/std/typetraits.hpp @@ -266,4 +266,43 @@ constexpr bool is_move_constructible(bool) { template constexpr bool is_move_constructible_v = detail::is_move_constructible(0); + +// is String? + +template +class BasicString; +template +class BString; +class StringLiteral; +class StringView; + +namespace detail { + +constexpr auto isOxString(const auto*) noexcept { + return false; +} + +template +constexpr auto isOxString(const BasicString*) noexcept { + return true; +} + +template +constexpr auto isOxString(const BString*) noexcept { + return true; +} + +constexpr auto isOxString(const StringLiteral*) noexcept { + return true; +} + +constexpr auto isOxString(const StringView*) noexcept { + return true; +} + +} + +template +constexpr auto isOxString_v = detail::isOxString(static_cast(nullptr)); + }