diff --git a/src/ConstString.hpp b/src/ConstString.hpp index 5e7ca24..4486a96 100644 --- a/src/ConstString.hpp +++ b/src/ConstString.hpp @@ -16,13 +16,29 @@ namespace Arbutils { inline static uint32_t constexpr Hash(char const* input) { return (*input) ? static_cast((*input)) + 33 * Hash(input + 1) : 5381; } + + inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; } + inline static uint32_t constexpr LowercaseHash(char const* input) { + return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * LowercaseHash(input + 1) : 5381; + } + inline static int constexpr Length(const char* str) { return *str ? 1 + Length(str + 1) : 0; } + constexpr explicit ConstString(const char* str, bool) + : _str(str), _length(Length(str)), _hash(LowercaseHash(str)){}; + constexpr explicit ConstString(const char* str, size_t size, bool) + : _str(str), _length(size), _hash(LowercaseHash(str)){}; + public: constexpr ConstString() : _str(""), _length(0), _hash(Hash("")){}; constexpr explicit ConstString(const char* str) : _str(str), _length(Length(str)), _hash(Hash(str)){}; constexpr explicit ConstString(const char* str, size_t size) : _str(str), _length(size), _hash(Hash(str)){}; + static constexpr inline ConstString CaseInsensitive(const char* str) { return ConstString(str, true); } + static constexpr inline ConstString CaseInsensitive(const char* str, size_t size) { + return ConstString(str, size, true); + } + [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } [[nodiscard]] inline std::string std_str() const { return std::string(_str, _length); } @@ -31,22 +47,22 @@ namespace Arbutils { [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } constexpr std::size_t operator()(ConstString const& s) const noexcept { return s.GetHash(); } - inline constexpr operator uint32_t() const{ return _hash; } + inline constexpr operator uint32_t() const { return _hash; } - inline constexpr bool operator==(const ConstString& rhs) const{ - return _hash == rhs._hash; - } - inline constexpr bool operator!=(const ConstString& rhs) const{ - return _hash != rhs._hash; - } + inline constexpr bool operator==(const ConstString& rhs) const { return _hash == rhs._hash; } + inline constexpr bool operator!=(const ConstString& rhs) const { return _hash != rhs._hash; } }; } inline constexpr Arbutils::ConstString operator"" _const(const char* c, size_t l) { return Arbutils::ConstString(c, l); } -inline constexpr Arbutils::ConstString operator"" _c(const char* c, size_t l) { - return Arbutils::ConstString(c, l); +inline constexpr Arbutils::ConstString operator"" _c(const char* c, size_t l) { return Arbutils::ConstString(c, l); } +inline constexpr Arbutils::ConstString operator"" _const_nocase(const char* c, size_t l) { + return Arbutils::ConstString::CaseInsensitive(c, l); +} +inline constexpr Arbutils::ConstString operator"" _cnc(const char* c, size_t l) { + return Arbutils::ConstString::CaseInsensitive(c, l); } namespace std { diff --git a/tests/ConstStringTests.cpp b/tests/ConstStringTests.cpp index 7ed588a..29b4435 100644 --- a/tests/ConstStringTests.cpp +++ b/tests/ConstStringTests.cpp @@ -23,4 +23,24 @@ TEST_CASE("Use const string in switch case", "[Utilities]") { } } +TEST_CASE("Use insensitive const string in unordered_map", "[Utilities]") { + std::unordered_map map; + map.insert({"foO"_cnc, 1}); + map.insert({"bAR"_cnc, 5}); + + CHECK(map["bar"_cnc] == 5); + CHECK(map["foo"_cnc] == 1); +} + +TEST_CASE("Use case insensitive const string in switch case", "[Utilities]") { + auto val = Arbutils::ConstString::CaseInsensitive("foobar"); + switch (val){ + case "foo"_cnc: FAIL(); break; + case "bar"_cnc: FAIL(); break; + case "FOObAr"_cnc: SUCCEED(); break; + default: FAIL(); break; + } +} + + #endif \ No newline at end of file