#pragma once #include #include #include #include #include #include "Hash.String.hpp" #define __Utility_String_StringView__ //----------------------------------------------------------------------------- // 定义一个简单的 StringView, 设计思路来自 , 但是做了很多简化 // // !!! 如果构造函数中的 _sPtr 指向 nullptr, 内部的数据指针将指向内部的 Nil // 如果是无参数构造, 内部的数据指针也指向内部的 Nil // // 上述两个措施都是为了让 Data 永远不会指向 nullptr ! // 2022-11-18 // // 在构造函数中, m_Hash 初始化为 0, Hash () 函数体中计算真正的 Hash 值并返回 //----------------------------------------------------------------------------- namespace ECOM::Utility::String { template class StringView_Base { public: using value_type = T; using pointer = T *; using reference = T &; using size_type = unsigned int; using hash_type = size_t; using const_pointer = const T *; using const_reference = const T &; public: static constexpr auto npos { static_cast (-1) }; private: static constexpr T __nil { 0 }; public: // constexpr StringView_Base () noexcept : m_Data (nullptr), m_Count (0) {} constexpr StringView_Base () noexcept : m_Data (& __nil), m_Count (0), m_Hash (0) {} constexpr StringView_Base (const StringView_Base &) noexcept = default; constexpr StringView_Base & operator= (const StringView_Base &) noexcept = default; constexpr StringView_Base (StringView_Base &&) noexcept = default; constexpr StringView_Base & operator= (StringView_Base &&) noexcept = default; // explicit : 如果只有指针, 没有长度 explicit constexpr StringView_Base (const const_pointer _sPtr) noexcept : m_Data (_sPtr ? _sPtr : reinterpret_cast (& __nil)) , m_Count (_sPtr ? __count (_sPtr) : 0) , m_Hash (0) { } constexpr StringView_Base (const const_pointer _sPtr, const size_type _Count) noexcept : m_Data (_sPtr ? _sPtr : reinterpret_cast (& __nil)) , m_Count (_sPtr ? _Count : 0) , m_Hash (0) { } // explicit ? 避免如下默认行为 StringView f () { std::string rc; return rc; } // !!! 显式转换工作量太大 constexpr StringView_Base (const std::basic_string & str) noexcept : m_Data (str.c_str ()) , m_Count (static_cast (str.size ())) , m_Hash (0) { } constexpr StringView_Base (const const_pointer _sPtr, const size_type _Count, hash_type H) noexcept : m_Data (_sPtr ? _sPtr : reinterpret_cast (& __nil)) , m_Count (_sPtr ? _Count : 0) , m_Hash (H) { } // 从 std::string_view 构造 constexpr StringView_Base (const std::basic_string_view & str) noexcept : m_Data (str.data ()) , m_Count (static_cast (str.size ())) , m_Hash (0) { } public: constexpr const_pointer _Unchecked_begin () const noexcept { return m_Data; } constexpr const_pointer _Unchecked_end () const noexcept { return m_Data + m_Count; } [[nodiscard]] constexpr size_type Size () const noexcept { return m_Count; } [[nodiscard]] constexpr size_type Length () const noexcept { return m_Count; } [[nodiscard]] constexpr size_type GetLength () const noexcept { return m_Count; } [[nodiscard]] constexpr bool isEmpty () const noexcept { return m_Count == 0; } [[nodiscard]] constexpr const_pointer Data () const noexcept { return m_Data; } [[nodiscard]] constexpr hash_type Hash () const noexcept // 返回 Hash 值. 注意 !!! 返回值有可能是 0 !!! { //< 以下代码会导致 Hash 函数不再是 constexpr, 因此删除 // if constexpr (m_Hash == 0) // m_Hash = ECOM::Utility::Hash (m_Data, m_Count); //> return m_Hash; // 注意 !!! 返回值有可能是 0 !!! } [[nodiscard]] hash_type Hash () noexcept // 计算真正的 Hash 值并返回. 增加了是否为 0 的判断, 因此返回值一定非 0 { if (m_Hash == 0) m_Hash = ECOM::Utility::Hash (m_Data, m_Count); return m_Hash; } // 不检查 _Off 是否合理 [[nodiscard]] constexpr const_reference operator [] (const size_type _Off) const noexcept { return m_Data [_Off]; } // 检查 _Off 是否合理, 如果不正确就扔例外 [[nodiscard]] constexpr const_reference at (const size_type _Off) const { // get the character at _Off or throw if that is out of range if (_Off >= m_Count) throw std::out_of_range ("StringView_Base.at"); return m_Data [_Off]; } [[nodiscard]] constexpr const_reference Front () const noexcept { return m_Data [0]; } [[nodiscard]] constexpr const_reference Back () const noexcept { return m_Data [m_Count - 1]; } public: constexpr void RemovePrefix (const size_type _Count) noexcept { m_Data += _Count; m_Count -= _Count; } constexpr void RemoveSuffix (const size_type _Count) noexcept { m_Count -= _Count; } constexpr void Swap (StringView_Base & _Other) noexcept { const StringView_Base _Tmp { _Other }; // note: std::swap is not constexpr before C++20 _Other = *this; *this = _Tmp; } [[nodiscard]] constexpr StringView_Base Sub (const size_type _Off = 0, size_type _Count = npos) const { // return a new StringView_Base moved forward by _Off and trimmed to _Count elements if (_Off > m_Count) throw std::out_of_range ("StringView_Base.Sub"); _Count = (std::min) (_Count, m_Count - _Off); if (m_Hash == 0) // 我不是 constexpr return StringView_Base (m_Data + _Off, _Count); else // 我是 constexpr return StringView_Base (m_Data + _Off, _Count, Hash64 (m_Data + _Off, _Count)); } public: [[nodiscard]] constexpr bool isEqual (const StringView_Base _Right) const noexcept { return (m_Count == _Right.m_Count) && Compare (_Right) == 0; } [[nodiscard]] constexpr int Compare (const StringView_Base _Right) const noexcept { // if constexpr (this->Hash () == _Right.Hash ()) return 0; // 只比较 Hash, 如果 Hash 相等就认为字符串相等 return __mem_compare (m_Data, m_Count, _Right.m_Data, _Right.m_Count); } [[nodiscard]] constexpr int Compare (const size_type _Off, const size_type _Nx, const StringView_Base _Right) const { // compare [_Off, _Off + _Nx) with _Right return Sub (_Off, _Nx).Compare (_Right); } [[nodiscard]] constexpr int Compare (const size_type _Off, const size_type _Nx, const StringView_Base _Right, const size_type _Roff, const size_type _Count) const { // compare [_Off, _Off + _Nx) with _Right [_Roff, _Roff + _Count) return Sub (_Off, _Nx).Compare (_Right.substr (_Roff, _Count)); } [[nodiscard]] constexpr int Compare (const T * const _Ptr) const { // compare [0, m_Count) with [_Ptr, ) return Compare (StringView_Base (_Ptr)); } [[nodiscard]] constexpr int Compare (const size_type _Off, const size_type _Nx, const T * const _Ptr) const { // compare [_Off, _Off + _Nx) with [_Ptr, ) return Sub (_Off, _Nx).Compare (StringView_Base (_Ptr)); } [[nodiscard]] constexpr int Compare (const size_type _Off, const size_type _Nx, const T * const _Ptr, const size_type _Count) const { // compare [_Off, _Off + _Nx) with [_Ptr, _Ptr + _Count) return Sub (_Off, _Nx).Compare (StringView_Base (_Ptr, _Count)); } [[nodiscard]] constexpr bool Hash_Compare (const StringView_Base & with) const { auto H1 = this->Hash (); auto H2 = with.Hash (); if ((H1 != 0) && (H2 != 0)) return (H1 == H2); return isEqual (with); } public: [[nodiscard]] constexpr bool operator == (const StringView_Base & with) const { return (Hash_Compare (with)); } [[nodiscard]] constexpr bool operator != (const StringView_Base & with) const { return (! Hash_Compare (with)); } [[nodiscard]] constexpr bool operator < (const StringView_Base & with) const { return Compare (with) < 0; } [[nodiscard]] constexpr bool operator > (const StringView_Base & with) const { return Compare (with) > 0; } [[nodiscard]] constexpr bool operator <= (const StringView_Base & with) const { return Compare (with) <= 0; } [[nodiscard]] constexpr bool operator >= (const StringView_Base & with) const { return Compare (with) >= 0; } [[nodiscard]] constexpr bool operator == (const T * with) const { return Compare (with) == 0; } [[nodiscard]] constexpr bool operator != (const T * with) const { return Compare (with) != 0; } [[nodiscard]] constexpr bool operator < (const T * with) const { return Compare (with) < 0; } [[nodiscard]] constexpr bool operator > (const T * with) const { return Compare (with) > 0; } [[nodiscard]] constexpr bool operator <= (const T * with) const { return Compare (with) <= 0; } [[nodiscard]] constexpr bool operator >= (const T * with) const { return Compare (with) >= 0; } public: [[nodiscard]] constexpr bool StartWith (const StringView_Base _Right) const noexcept { if (m_Count < _Right.m_Count) return false; return __mem_compare (m_Data, _Right.m_Data, _Right.m_Count) == 0; } [[nodiscard]] constexpr bool StartWith (const T _Right) const noexcept { return !isEmpty () && (Front () == _Right); } [[nodiscard]] constexpr bool StartWith (const T * const _Right) const noexcept { return StartWith (StringView_Base (_Right)); } [[nodiscard]] constexpr bool EndWith (const StringView_Base _Right) const noexcept { const auto _Rightsize = _Right.m_Count; if (m_Count < _Rightsize) return false; return __mem_compare (m_Data + (m_Count - _Rightsize), _Right.m_Data, _Rightsize) == 0; } [[nodiscard]] constexpr bool EndWith (const T _Right) const noexcept { return !isEmpty () && (Back () == _Right); } [[nodiscard]] constexpr bool EndWith (const T * const _Right) const noexcept { return EndWith (StringView_Base (_Right)); } [[nodiscard]] constexpr size_type Find (const T ch, const size_type _Off = 0) const noexcept { if (_Off < m_Count) { const auto found = __mem_find (m_Data + _Off, m_Count - _Off, ch); if (found) return static_cast (found - m_Data); } return npos; } [[nodiscard]] constexpr int Count (const T ch) const { int count = 0; for (int i = 0, l = GetLength (); i < l; i++) if (m_Data [i] == ch) count++; return count; } // Cast public: // return pointer to const string constexpr operator const T * () const { return m_Data; } constexpr const T * constBuffer (void) const { return m_Data; } constexpr operator std::basic_string_view () const // 既然长度已知, 可以几乎无代价地转换成 std::string_view { return std::basic_string_view { m_Data, static_cast (GetLength ()) }; } operator bool () const = delete; public: static bool isNullOrEmpty (const StringView_Base & S) { return S.m_Count == 0; } public: // 转换函数. 因为 atof 等函数不是 constexpr, 因此这里的 constexpr 其实是无效的 template ::value>> constexpr double Double () const { return atof (m_Data); } template ::value>> constexpr double Double () const { return _wtof (m_Data); } template ::value>> constexpr int Int () const { int i = atoi (m_Data); if (i) return i; return strtol (m_Data, nullptr, 16); } template ::value>> constexpr int Int () const { int i = _wtoi (m_Data); if (i) return i; return wcstol (m_Data, nullptr, 16); } template ::value>> constexpr long Long () const { int i = atol (m_Data); if (i) return i; return strtol (m_Data, nullptr, 16); } template ::value>> constexpr long Long () const { int i = _wtol (m_Data); if (i) return i; return wcstol (m_Data, nullptr, 16); } template ::value>> constexpr __int64 Int64 () const { int i = _atoi64 (m_Data); if (i) return i; return _strtoi64 (m_Data, nullptr, 16); } template ::value>> constexpr __int64 Int64 () const { int i = _wtoi64 (m_Data); if (i) return i; return _wcstoi64 (m_Data, nullptr, 16); } template constexpr T To () const = delete; template <> constexpr int To () const { return Int (); } template <> constexpr double To () const { return Double (); } template <> constexpr float To () const { return (float) Double (); } template <> constexpr long To () const { return Long (); } template <> constexpr __int64 To () const { return Int64 (); } template <> constexpr unsigned int To () const { return Int (); } template <> constexpr unsigned __int64 To () const { return Int64 (); } template <> constexpr unsigned long To () const { return Long (); } template <> constexpr std::basic_string_view To () const // 与 operator 函数完全相同 { return std::basic_string_view { m_Data, static_cast (GetLength ()) }; } private: //< 基于内存的比较 static inline constexpr int __mem_compare (const const_pointer _l, const size_type _ls, const const_pointer _r, const size_type _rs) { auto b = __mem_compare (_l, _r, (std::min) (_ls, _rs)); if (b != 0) return b; if (_ls < _rs) return -1; if (_ls > _rs) return 1; return 0; } static inline constexpr int __mem_compare (const const_pointer _l, const const_pointer _r, const size_type _sz) { if constexpr (std::is_same_v ) return __builtin_wmemcmp (_l, _r, _sz); else if constexpr (std::is_same_v ) return __builtin_memcmp (_l, _r, _sz); assert (false); return 0; } //> static inline constexpr T * __mem_find (const const_pointer _f, const size_type _sz, const T & ch) { if constexpr (std::is_same_v ) return __builtin_wmemchr (_f, ch, _sz); else if constexpr (std::is_same_v ) return __builtin_char_memchr (_f, ch, _sz); assert (false); return nullptr; } // _f 中有多少个字符? static inline constexpr size_type __count (const const_pointer _f) { if constexpr (std::is_same_v ) return static_cast (__builtin_wcslen (_f)); else if constexpr (std::is_same_v ) return static_cast (__builtin_strlen (_f)); assert (false); return 0; } private: const_pointer m_Data; size_type m_Count; // 是字符个数, 不是 NbOfByte hash_type m_Hash; }; using StringView = StringView_Base ; using DStringView = StringView_Base ; using WStringView = StringView_Base ; inline namespace Literals { inline namespace StringViewLiterals { [[nodiscard]] constexpr StringView operator"" _sv (const char * _Str, size_t _Len) noexcept { return StringView (_Str, static_cast (_Len), Hash64 (_Str, static_cast (_Len))); } [[nodiscard]] constexpr WStringView operator"" _sv (const wchar_t * _Str, size_t _Len) noexcept { return WStringView (_Str, static_cast (_Len), Hash64 (_Str, static_cast (_Len))); } } } } //namespace eSTR = ECOM::Utility::String; //using namespace eSTR::Literals; //using namespace ECOM::Utility::String::Literals; //using constView = const ECOM::Utility::String::StringView; //using wconstView = const ECOM::Utility::String::WStringView; //using conStrView = const ECOM::Utility::String::StringView; //using conWStrView = const ECOM::Utility::String::WStringView; using CV_String = const ECOM::Utility::String::StringView; using CV_DString = const ECOM::Utility::String::StringView; using CV_WString = const ECOM::Utility::String::WStringView; //using String_CV = const ECOM::Utility::String::StringView; //using WString_CV = const ECOM::Utility::String::WStringView; //< 提供 CV_String 与 std:: string 的比较 template inline bool operator == (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) == 0; } template inline bool operator != (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) != 0; } template inline bool operator > (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) > 0; } template inline bool operator < (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) < 0; } template inline bool operator >= (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) >= 0; } template inline bool operator <= (const ECOM::Utility::String::StringView_Base & s1, const std::basic_string & s2) { return s1.Compare (ECOM::Utility::String::StringView_Base { s2.c_str (), static_cast (s2.size ()) }) <= 0; } //> //< 提供 std:: string 与 CV_String 的比较 template inline bool operator == (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) == 0; } template inline bool operator != (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) != 0; } template inline bool operator > (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) < 0; } template inline bool operator < (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) > 0; } template inline bool operator >= (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) <= 0; } template inline bool operator <= (const std::basic_string & s1, const ECOM::Utility::String::StringView_Base & s2) { return s2.Compare (ECOM::Utility::String::StringView_Base { s1.c_str (), static_cast (s1.size ()) }) >= 0; } //> //< 针对 StringView 的 Hash namespace ECOM::Utility { inline constexpr size_t Hash64 (const String::DStringView & SV) { return Hash64 (SV.Data (), SV.GetLength ()); assert (SV.Hash ()); assert (SV.Hash () == Hash64 (SV.Data (), SV.GetLength ())); // return SV.Hash (); } inline constexpr size_t Hash64 (const String::WStringView & SV) { return Hash64 (SV.Data (), SV.GetLength ()); assert (SV.Hash ()); assert (SV.Hash () == Hash64 (SV.Data (), SV.GetLength ())); // return SV.Hash (); } inline constexpr tHash32 Hash32 (const String::DStringView & SV) { return Hash32 (SV.Data (), SV.GetLength ()); assert (SV.Hash ()); assert (SV.Hash () == Hash64 (SV.Data (), SV.GetLength ())); // return SV.Hash (); } inline constexpr tHash32 Hash32 (const String::WStringView & SV) { return Hash32 (SV.Data (), SV.GetLength ()); assert (SV.Hash ()); assert (SV.Hash () == Hash64 (SV.Data (), SV.GetLength ())); // return SV.Hash (); } #ifdef _WIN64 inline constexpr size_t Hash (const String::DStringView & SV) { return Hash64 (SV); } inline constexpr size_t Hash (const String::WStringView & SV) { return Hash64 (SV); } #else inline constexpr tHash32 Hash (const String::DStringView & SV) { return Hash32 (SV); } inline constexpr tHash32 Hash (const String::WStringView & SV) { return Hash32 (SV); } #endif }