diff --git a/src/CaseInsensitiveConstString.hpp b/src/CaseInsensitiveConstString.hpp deleted file mode 100644 index 12f094d..0000000 --- a/src/CaseInsensitiveConstString.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef ARBUTILS_CASEINSENSITIVECONSTSTRING_HPP -#define ARBUTILS_CASEINSENSITIVECONSTSTRING_HPP - -#include -#include -#include -#include - -namespace Arbutils { - class CaseInsensitiveConstString { - private: - const char* _str; - size_t _length; - uint32_t _hash; - - inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; } - inline static uint32_t constexpr Hash(char const* input) { - return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; - } - - inline static int constexpr Length(const char* str) { return *str ? 1 + Length(str + 1) : 0; } - - public: - constexpr CaseInsensitiveConstString() : _str(""), _length(0), _hash(Hash("")){}; - constexpr explicit CaseInsensitiveConstString(const char* str) - : _str(str), _length(Length(str)), _hash(Hash(str)){}; - constexpr explicit CaseInsensitiveConstString(const std::string& str) - : _str(str.c_str()), _length(str.length()), _hash(Hash(str.c_str())){}; - constexpr explicit CaseInsensitiveConstString(const char* str, size_t size) - : _str(str), _length(size), _hash(Hash(str)){}; - - [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } - [[nodiscard]] inline std::string std_str() const { return std::string(_str, _length); } - - [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } - - [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } - - constexpr std::size_t operator()(CaseInsensitiveConstString const& s) const noexcept { return s.GetHash(); } - inline constexpr operator uint32_t() const { return _hash; } - - inline constexpr bool operator==(const CaseInsensitiveConstString& rhs) const { return _hash == rhs._hash; } - inline constexpr bool operator!=(const CaseInsensitiveConstString& rhs) const { return _hash != rhs._hash; } - inline constexpr bool operator==(const std::string& rhs) const { return _hash == Hash(rhs.c_str()); } - inline constexpr bool operator!=(const std::string& rhs) const { return _hash != Hash(rhs.c_str()); } - inline constexpr bool operator==(const char* rhs) const { return _hash == Hash(rhs); } - inline constexpr bool operator!=(const char* rhs) const { return _hash != Hash(rhs); } - }; -} - -inline constexpr Arbutils::CaseInsensitiveConstString operator"" _const_nocase(const char* c, size_t l) { - return Arbutils::CaseInsensitiveConstString(c, l); -} -inline constexpr Arbutils::CaseInsensitiveConstString operator"" _cnc(const char* c, size_t l) { - return Arbutils::CaseInsensitiveConstString(c, l); -} - -namespace std { - template <> struct hash { - constexpr std::size_t operator()(Arbutils::CaseInsensitiveConstString const& s) const noexcept { - return s.GetHash(); - } - }; -} - -#endif // ARBUTILS_CASEINSENSITIVECONSTSTRING_HPP diff --git a/src/ConstString.hpp b/src/ConstString.hpp index 4a8ea2a..cf979d5 100644 --- a/src/ConstString.hpp +++ b/src/ConstString.hpp @@ -5,61 +5,33 @@ #include #include #include +#include "__ConstStringCore.hpp" -namespace Arbutils { - class ConstString { - private: - const char* _str; - size_t _length; - uint32_t _hash; +ConstStringCore( + ConstString, + inline static uint32_t constexpr Hash(char const* input) { + return (*input) ? static_cast((*input)) + 33 * Hash(input + 1) : 5381; + };) - 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; } - - 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 std::string& str) - : _str(str.c_str()), _length(str.length()), _hash(Hash(str.c_str())){}; - constexpr explicit ConstString(const char* str, size_t size) : _str(str), _length(size), _hash(Hash(str)){}; - - [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } - [[nodiscard]] inline std::string std_str() const { return std::string(_str, _length); } - - [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } - - [[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 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 std::string& rhs) const { return _hash == Hash(rhs.c_str()); } - inline constexpr bool operator!=(const std::string& rhs) const { return _hash != Hash(rhs.c_str()); } - inline constexpr bool operator==(const char* rhs) const { return _hash == Hash(rhs); } - inline constexpr bool operator!=(const char* rhs) const { return _hash != Hash(rhs); } - }; -} - -inline constexpr Arbutils::ConstString operator"" _const(const char* c, size_t l) { + 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); } -namespace std { - template <> struct hash { - constexpr std::size_t operator()(Arbutils::ConstString const& s) const noexcept { return s.GetHash(); } - }; +ConstStringCore( + CaseInsensitiveConstString, + inline static constexpr char charToLower(const char c) { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; + } inline static uint32_t constexpr Hash(char const* input) { + return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; + };); + +inline constexpr Arbutils::CaseInsensitiveConstString operator"" _const_nocase(const char* c, size_t l) { + return Arbutils::CaseInsensitiveConstString(c, l); +} +inline constexpr Arbutils::CaseInsensitiveConstString operator"" _cnc(const char* c, size_t l) { + return Arbutils::CaseInsensitiveConstString(c, l); } #endif // ARBUTILS_CONSTSTRING_HPP diff --git a/src/__ConstStringCore.hpp b/src/__ConstStringCore.hpp new file mode 100644 index 0000000..f83f752 --- /dev/null +++ b/src/__ConstStringCore.hpp @@ -0,0 +1,57 @@ +#ifndef ARBUTILS_CONSTSTRINGCORE_HPP +#define ARBUTILS_CONSTSTRINGCORE_HPP + +#if WINDOWS +#define STDSTRINGEQUALITY \ + inline bool operator==(const std::string& rhs) const { return _hash == Hash(rhs.c_str()); } \ + inline bool operator!=(const std::string& rhs) const { return _hash != Hash(rhs.c_str()); } +#else +#define STDSTRINGEQUALITY \ + inline constexpr bool operator==(const std::string& rhs) const { return _hash == Hash(rhs.c_str()); } \ + inline constexpr bool operator!=(const std::string& rhs) const { return _hash != Hash(rhs.c_str()); } +#endif + +#define ConstStringCore(name, hashFunction) \ + namespace Arbutils { \ + class name { \ + private: \ + const char* _str; \ + size_t _length; \ + uint32_t _hash; \ + \ + hashFunction; \ + \ + inline static int constexpr Length(const char* str) { return *str ? 1 + Length(str + 1) : 0; } \ + \ + public: \ + constexpr name() : _str(""), _length(0), _hash(Hash("")){}; \ + constexpr explicit name(const char* str) : _str(str), _length(Length(str)), _hash(Hash(str)){}; \ + constexpr explicit name(const std::string& str) \ + : _str(str.c_str()), _length(str.length()), _hash(Hash(str.c_str())){}; \ + constexpr explicit name(const char* str, size_t size) : _str(str), _length(size), _hash(Hash(str)){}; \ + \ + [[nodiscard]] inline constexpr const char* c_str() const noexcept { return _str; } \ + [[nodiscard]] inline std::string std_str() const { return std::string(_str, _length); } \ + \ + [[nodiscard]] inline constexpr size_t Length() const noexcept { return _length; } \ + \ + [[nodiscard]] inline constexpr uint32_t GetHash() const noexcept { return _hash; } \ + \ + constexpr std::size_t operator()(name const& s) const noexcept { return s.GetHash(); } \ + inline constexpr operator uint32_t() const { return _hash; } \ + \ + inline constexpr bool operator==(const name& rhs) const { return _hash == rhs._hash; } \ + inline constexpr bool operator!=(const name& rhs) const { return _hash != rhs._hash; } \ + STDSTRINGEQUALITY \ + inline constexpr bool operator==(const char* rhs) const { return _hash == Hash(rhs); } \ + inline constexpr bool operator!=(const char* rhs) const { return _hash != Hash(rhs); } \ + }; \ + } \ + \ + namespace std { \ + template <> struct hash { \ + constexpr std::size_t operator()(Arbutils::name const& s) const noexcept { return s.GetHash(); } \ + }; \ + } + +#endif \ No newline at end of file diff --git a/tests/ConstStringTests.cpp b/tests/ConstStringTests.cpp index 023a04e..a4a4653 100644 --- a/tests/ConstStringTests.cpp +++ b/tests/ConstStringTests.cpp @@ -2,7 +2,6 @@ #include #include #include "../extern/catch.hpp" -#include "../src/CaseInsensitiveConstString.hpp" #include "../src/ConstString.hpp" TEST_CASE("Use const string in unordered_map", "[Utilities]") {