#ifndef ARBUTILS_STRINGVIEW_HPP #define ARBUTILS_STRINGVIEW_HPP #include #include #include #include #include #include "BasicStringView.hpp" #if WINDOWS #define STDSTRINGCONSTEXPR #else #define STDSTRINGCONSTEXPR constexpr #endif namespace ArbUt { class __ConstStringCharHolder { char* _value = 0; __ConstStringCharHolder(const __ConstStringCharHolder& o) = delete; __ConstStringCharHolder& operator=(const __ConstStringCharHolder& other) = delete; public: __ConstStringCharHolder(const char* value, size_t length) noexcept : _value(new char[length + 1]) { strncpy(_value, value, length + 1); } ~__ConstStringCharHolder() noexcept { delete[] _value; } inline constexpr const char* GetValue() const noexcept { return _value; } }; } inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; } static uint32_t constexpr Hash(char const* input) { return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; }; static int constexpr CalcLength(const char* str) { return *str ? 1 + CalcLength(str + 1) : 0; } namespace ArbUt { /// \ingroup Strings /// @brief A constant, non-editable string that allows copies to share the same string object. class StringView final : public BasicStringView { private: static std::shared_ptr<__ConstStringCharHolder> __emptyString; static inline const std::shared_ptr<__ConstStringCharHolder>& GetEmptyString() { return __emptyString; } std::shared_ptr<__ConstStringCharHolder> _str = GetEmptyString(); public: /// @brief Instantiate a StringView using a C string. /// @param str A null-terminated C string. StringView(const char* str) noexcept : BasicStringView(CalcLength(str), Hash(str)), _str(new __ConstStringCharHolder(str, CalcLength(str))) {} /// @brief Instantiate a StringView using a C string, as well as it's length. /// @param str A null-terminated C string. /// @param length The length of the C string StringView(const char* str, size_t length) noexcept : BasicStringView(length, Hash(str)), _str(new __ConstStringCharHolder(str, length)) {} StringView() noexcept : BasicStringView(0, Hash("")) {} /* Copy operators */ /// @brief Copy operator /// @param other Other StringView StringView(const StringView& other) noexcept : BasicStringView(other._length, other._hash), _str(other._str) {} /// @brief Special constructor of stringview, specifically designed for use of conversion from StringViewLiteral /// to StringView. /// @param other Other StringView /// @param c A null-terminated C string. /// @param length The length of the C string. StringView(const BasicStringView& other, const char* c, size_t length) noexcept : BasicStringView(length, other.GetHash()), _str(new __ConstStringCharHolder(c, length)) {} /// @brief Assignment operator. /// @param other Stringview to assign. /// @return current stringview. StringView& operator=(const StringView& other) noexcept { if (this == &other || _str == other._str) { return *this; } _str = other._str; _length = other._length; _hash = other._hash; return *this; } /// @brief Returns null-terminated C string. /// @return Null-terminated C string. [[nodiscard]] inline const char* c_str() const noexcept override { return _str->GetValue(); } /// @brief Returns std string_view of internal C string. /// @return std::string_view. [[nodiscard]] inline std::string_view std_str() const noexcept override { return _str->GetValue(); } inline constexpr bool operator==(const std::string_view& rhs) const noexcept override { return _hash == Hash(rhs.data()); } inline constexpr bool operator!=(const std::string_view& rhs) const noexcept override { return _hash != Hash(rhs.data()); } inline constexpr bool operator==(const char* rhs) const noexcept override { return _hash == Hash(rhs); } inline constexpr bool operator!=(const char* rhs) const noexcept override { return _hash != Hash(rhs); } /// @brief Calculates the hash for a given C string. /// @param val A null-terminated C string. /// @return A hash of the given string. [[maybe_unused]] [[nodiscard]] inline static constexpr uint32_t CalculateHash(const char* val) noexcept { return Hash(val); } /// @brief Calculates the hash for a given std string. /// @param val A std string. /// @return A hash of the given string. [[maybe_unused]] [[nodiscard]] inline static constexpr uint32_t CalculateHash(const std::string_view& val) noexcept { return Hash(val.data()); } /// @brief Returns an empty string. /// @return An empty string. static const StringView& EmptyString(); }; } namespace std { /// @brief Helper class for hashing string views. template <> struct hash { /// @brief Returns the hash of a stringview. /// @param s a StringView. /// @return The hash of the StringView. constexpr std::size_t operator()(ArbUt::StringView const& s) const noexcept { return s.GetHash(); } }; } #endif // ARBUTILS_STRINGVIEW_HPP