123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- #pragma once
- #include <assert.h>
- #include <stdexcept>
- #include <type_traits>
- #include <string>
- #include <algorithm>
- #include "Hash.String.hpp"
- #define __Utility_String_StringView__
- //-----------------------------------------------------------------------------
- // 定义一个简单的 StringView, 设计思路来自 <xstring>, 但是做了很多简化
- //
- // !!! 如果构造函数中的 _sPtr 指向 nullptr, 内部的数据指针将指向内部的 Nil
- // 如果是无参数构造, 内部的数据指针也指向内部的 Nil
- //
- // 上述两个措施都是为了让 Data 永远不会指向 nullptr !
- // 2022-11-18
- //
- // 在构造函数中, m_Hash 初始化为 0, Hash () 函数体中计算真正的 Hash 值并返回
- //-----------------------------------------------------------------------------
- namespace ECOM::Utility::String
- {
- template <typename T>
- 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 <size_type> (-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 <const T *> (& __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 <const T *> (& __nil))
- , m_Count (_sPtr ? _Count : 0)
- , m_Hash (0) { }
- // explicit ? 避免如下默认行为 StringView f () { std::string rc; return rc; }
- // !!! 显式转换工作量太大
- constexpr StringView_Base (const std::basic_string <T> & str) noexcept
- : m_Data (str.c_str ())
- , m_Count (static_cast <size_type> (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 <const T *> (& __nil))
- , m_Count (_sPtr ? _Count : 0)
- , m_Hash (H) { }
- // 从 std::string_view 构造
- constexpr StringView_Base (const std::basic_string_view <T> & str) noexcept
- : m_Data (str.data ())
- , m_Count (static_cast <size_type> (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, <null>)
- 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, <null>)
- 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 <size_type> (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 <T> () const // 既然长度已知, 可以几乎无代价地转换成 std::string_view
- {
- return std::basic_string_view <T> { m_Data, static_cast <size_t> (GetLength ()) };
- }
- operator bool () const = delete;
- public:
- static bool isNullOrEmpty (const StringView_Base & S)
- {
- return S.m_Count == 0;
- }
- public:
- // 转换函数. 因为 atof 等函数不是 constexpr, 因此这里的 constexpr 其实是无效的
- template <typename = std::enable_if_t <std::is_same <T, char>::value>>
- constexpr double Double () const { return atof (m_Data); }
- template <typename Dummy = void, typename = std::enable_if_t <std::is_same <T, wchar_t>::value>>
- constexpr double Double () const { return _wtof (m_Data); }
- template <typename = std::enable_if_t <std::is_same <T, char>::value>>
- constexpr int Int () const { int i = atoi (m_Data); if (i) return i; return strtol (m_Data, nullptr, 16); }
- template <typename Dummy = void, typename = std::enable_if_t <std::is_same <T, wchar_t>::value>>
- constexpr int Int () const { int i = _wtoi (m_Data); if (i) return i; return wcstol (m_Data, nullptr, 16); }
- template <typename = std::enable_if_t <std::is_same <T, char>::value>>
- constexpr long Long () const { int i = atol (m_Data); if (i) return i; return strtol (m_Data, nullptr, 16); }
- template <typename Dummy = void, typename = std::enable_if_t <std::is_same <T, wchar_t>::value>>
- constexpr long Long () const { int i = _wtol (m_Data); if (i) return i; return wcstol (m_Data, nullptr, 16); }
- template <typename = std::enable_if_t <std::is_same <T, char>::value>>
- constexpr __int64 Int64 () const { int i = _atoi64 (m_Data); if (i) return i; return _strtoi64 (m_Data, nullptr, 16); }
- template <typename Dummy = void, typename = std::enable_if_t <std::is_same <T, wchar_t>::value>>
- constexpr __int64 Int64 () const { int i = _wtoi64 (m_Data); if (i) return i; return _wcstoi64 (m_Data, nullptr, 16); }
- template <typename T> 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 <T> To () const // 与 operator 函数完全相同
- {
- return std::basic_string_view <T> { m_Data, static_cast <size_t> (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 <T, wchar_t>)
- return __builtin_wmemcmp (_l, _r, _sz);
- else
- if constexpr (std::is_same_v <T, char>)
- 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 <T, wchar_t>)
- return __builtin_wmemchr (_f, ch, _sz);
- else
- if constexpr (std::is_same_v <T, char>)
- 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 <T, wchar_t>)
- return static_cast <size_type> (__builtin_wcslen (_f));
- else
- if constexpr (std::is_same_v <T, char>)
- return static_cast <size_type> (__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 <char>;
- using DStringView = StringView_Base <char>;
- using WStringView = StringView_Base <wchar_t>;
- inline namespace Literals
- {
- inline namespace StringViewLiterals
- {
- [[nodiscard]] constexpr StringView operator"" _sv (const char * _Str, size_t _Len) noexcept
- {
- return StringView (_Str, static_cast <unsigned int> (_Len), Hash64 (_Str, static_cast <unsigned int> (_Len)));
- }
- [[nodiscard]] constexpr WStringView operator"" _sv (const wchar_t * _Str, size_t _Len) noexcept
- {
- return WStringView (_Str, static_cast <unsigned int> (_Len), Hash64 (_Str, static_cast <unsigned int> (_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 <typename T>
- inline bool operator == (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) == 0;
- }
- template <typename T>
- inline bool operator != (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) != 0;
- }
- template <typename T>
- inline bool operator > (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) > 0;
- }
- template <typename T>
- inline bool operator < (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) < 0;
- }
- template <typename T>
- inline bool operator >= (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) >= 0;
- }
- template <typename T>
- inline bool operator <= (const ECOM::Utility::String::StringView_Base <T> & s1, const std::basic_string <T> & s2)
- {
- return s1.Compare (ECOM::Utility::String::StringView_Base <T> { s2.c_str (), static_cast <CV_String::size_type> (s2.size ()) }) <= 0;
- }
- //>
- //< 提供 std:: string 与 CV_String 的比较
- template <typename T>
- inline bool operator == (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (s1.size ()) }) == 0;
- }
- template <typename T>
- inline bool operator != (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (s1.size ()) }) != 0;
- }
- template <typename T>
- inline bool operator > (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (s1.size ()) }) < 0;
- }
- template <typename T>
- inline bool operator < (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (s1.size ()) }) > 0;
- }
- template <typename T>
- inline bool operator >= (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (s1.size ()) }) <= 0;
- }
- template <typename T>
- inline bool operator <= (const std::basic_string <T> & s1, const ECOM::Utility::String::StringView_Base <T> & s2)
- {
- return s2.Compare (ECOM::Utility::String::StringView_Base <T> { s1.c_str (), static_cast <CV_String::size_type> (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
- }
|