#pragma once #include #include #include #include "String.StringView.hpp" #ifdef DSTRING_EXPORTS #define WSTRING_API _declspec(dllexport) #else #define WSTRING_API _declspec(dllimport) #endif #ifdef _DSTRING_STATIC_ #undef WSTRING_API #define WSTRING_API #endif #ifndef DSTRING_EXPORTS #ifdef _WIN64 #ifdef _DEBUG #pragma comment (lib, "ECOM.Utility.DString64D.lib") #else #pragma comment (lib, "ECOM.Utility.DString64.lib") #endif #else // X86 #endif #endif // DSTRING_EXPORTS #ifndef _OLEAUTO_H_ typedef LPWSTR BSTR;// must (semantically) match typedef in oleauto.h #endif namespace ECOM::Utility::String { class DString; // using size_type = unsigned int; // 用 unsigned int 比较好, 但是会造成很多编译警告 using size_type = int; //----------------------------------------------------------------------------- // WStringData //----------------------------------------------------------------------------- namespace { struct WStringData { long nRefs; // reference count size_type nDataLength; // 字符数, length of data (including terminator) size_type nAllocLength; // length of allocation // wchar_t data[nAllocLength] wchar_t * data () // wchar_t* to managed data { return (wchar_t *) (this + 1); } }; } //----------------------------------------------------------------------------- // WString //----------------------------------------------------------------------------- class WSTRING_API WString { public: using value_type = WString; public: WString (); WString (const wchar_t * lpsz) = delete; WString (const wchar_t * lpsz, int nCount); WString (const BSTR bstr) = delete; explicit WString (const DString & From); explicit WString (const DStringView & From); WString (const std::wstring & Src); WString (const WString & Src); WString (WString && Src); public: ~WString (); public: // 返回的是字符数, 而不是真正的长度 ! 真正的长度要乘以 2 size_type GetLength () const; size_type GetByteLength () const { return GetLength () << 1; } size_type GetAllocLength () const { return GetData ()->nAllocLength; } size_type size () const { return GetLength (); } public: bool empty () const { return IsEmpty (); } bool IsEmpty () const { return GetLength () <= 0; } void Clear (); void Release (); public: wchar_t GetAt (int nIndex) const { return m_pchData [nIndex]; } wchar_t operator [] (int nIndex) const { return GetAt (nIndex); } void SetAt (int nIndex, wchar_t ch); int Count (wchar_t ch) const; int Count (const WStringView & Sub) const; protected: size_t _Hash () const; public: WString & operator = (const wchar_t *) = delete; WString & operator = (const WString & S); WString & operator = (const DString & S); WString & operator = (wchar_t ch); WString & operator = (const DStringView & S); WString & operator = (const WStringView & S) { return Assign (S); } WString & operator = (WString && S); WString & operator = (const std::wstring & S) { AssignCopy (static_cast (S.size ()), S.c_str ()); return *this; } WString & operator = (std::initializer_list lst) { return Assign (lst); } public: // string concatenation WString & Append (const WString & S) { ConcatInPlace (S.GetData ()->nDataLength, S.m_pchData); return *this; } WString & Append (const DString & S) { return Append (WString (S)); } WString & Append (wchar_t ch) { ConcatInPlace (1, &ch); return *this; } WString & Append (const DStringView & S); WString & Append (const WStringView & S); WString & Append (const std::wstring_view & S); WString & Append (const std::wstring & S) { ConcatInPlace (static_cast (S.length ()), S.c_str ()); return *this; } WString & Append (const char *) = delete; // 改用 L"..."_sv 代替 WString & Append (const wchar_t *) = delete; // 改用 L"..."_sv 代替 WString & operator += (const WString & S) { return Append (S); } WString & operator += (wchar_t ch) { return Append (ch); } WString & operator += (const DStringView S) { return Append (S); } WString & operator += (const WStringView S) { return Append (S); } WString & operator += (const DString & S) { return Append (S); } // WString & operator += (const std::wstring & S) { return Append (S); } WString & operator += (std::initializer_list lst) { return Append (lst); } // WString & operator += (const char *) = delete; // 改用 L"..."_sv 代替 // WString & operator += (const wchar_t *) = delete; // 改用 L"..."_sv 代替 WString & operator << (const DString & S) { return Append (WString (S)); } WString & operator << (const DStringView & S) { return Append (S); } WString & operator << (const WStringView & S) { return Append (S); } WString & operator << (const WString & S) { return Append (S); } WString & operator << (wchar_t ch) { return Append (ch); } WString & operator << (short v) { return Append (From (v)); } WString & operator << (int v) { return Append (From (v)); } WString & operator << (long v) { return Append (From (v)); } WString & operator << (UINT16 v) { return Append (From (v)); } WString & operator << (UINT32 v) { return Append (From (v)); } WString & operator << (unsigned long v) { return Append (From (v)); } // WString & operator << (const std::wstring & S) { return Append (S); } WString & operator << (std::initializer_list lst) { return Append (lst); } //< WString & operator << (const char *) = delete; // 改用 L"..."_sv 代替 // WString & operator << (const wchar_t *) = delete; // 改用 L"..."_sv 代替 // 不废除了, 某些强制赋值还是需要的. // 如果不做提前声明, 编译时发生 C2678: 无法找到匹配的运算符 // 2023-11-14 //> public: // string comparison int Compare (const wchar_t * lpsz) const; int CompareNoCase (const wchar_t * lpsz) const; int Compare (const WStringView & With) const; int Compare (const WString & With) const; //< 增加命名空间后, std::map 就需要如下内置比较函数 bool operator == (const WString & with) const { return Compare (with) == 0; } bool operator != (const WString & with) const { return Compare (with) != 0; } bool operator < (const WString & with) const { return Compare (with) < 0; } bool operator > (const WString & with) const { return Compare (with) > 0; } bool operator <= (const WString & with) const { return Compare (with) <= 0; } bool operator >= (const WString & with) const { return Compare (with) >= 0; } public: WString Mid (int nFirst, int nCount) const; WString Mid (int nFirst) const; WString Left (int nCount) const; WString Right (int nCount) const; public: void MakeUpper (); void MakeLower (); void MakeReverse (); public: int TrimLeft (); int TrimRight (); void TrimRight (wchar_t chTarget); void TrimRight (const WStringView & szTargets); void TrimLeft (wchar_t chTarget); void TrimLeft (const WStringView & szTargets); WString Trim () const { WString copy = *this; copy.TrimRight (); copy.TrimLeft (); return copy; } public: // 用指定的字符填充左边/右边/中间, 直到总长度达到指定值为止 void JustLeft (int ToLength, wchar_t ch = ' '); void JustRight (int ToLength, wchar_t ch = ' '); void JustCenter (int ToLength, wchar_t ch = ' '); public: int Replace (wchar_t chOld, wchar_t chNew); int Replace (const WString & Old, const WStringView & New); int Replace (const WStringView & Old, const WStringView & New); int Remove (const WStringView & Sub); int Remove (wchar_t chRemove); int RemoveSpace (); int RemovePunctuation (); int RemoveControl (); // 用谓词函数来判断单个字符是否应该删除, 如果返回 true 就删除 int Remove (std::function pred); int NCRemove (const WStringView & lpszSub); int NCRemove (wchar_t chRemove); void Repeat (wchar_t ch, int n); void Repeat (const WStringView & S, int n); public: // Pred 返回 true, 表明找到, 否则下一个字符 using tPred = std::function ; public: int Find (wchar_t ch, int nStart = 0) const; int Find (tPred && pred, int nStart = 0) const; int Find (const WStringView & Sub, int nStart = 0) const; int Find (const WString & Sub, int nStart = 0) const; // find at right int ReverseFind (wchar_t ch, int nStart = 0) const; int ReverseFind (const WStringView & Sub, int nStart = 0) const; bool StartWith (const WStringView & Sub, int iStart = 0) const; bool EndWith (const WStringView & Sub, int iStart = 0) const; bool StartWith (const WString & Sub, int iStart = 0) const { return StartWith (Sub.To (), iStart); } bool EndWith (const WString & Sub, int iStart = 0) const { return EndWith (Sub.To (), iStart); } bool StartWith (wchar_t ch, int iStart = 0) const; bool EndWith (wchar_t ch, int iStart = 0) const; int NCFind (wchar_t ch) const; int NCFind (const WStringView & Sub) const; public: using tvCallback = std::function ; // 如果回调返回 true, 则继续, 否则停止 using tbCallback = std::function ; int Split (wchar_t ch , tvCallback && onFound, int start = 0) const; int Split (tPred && pred, tvCallback && onFound, int start = 0) const; int SplitIf (wchar_t ch , tbCallback && onFound, int start = 0) const; int SplitIf (tPred && pred, tbCallback && onFound, int start = 0) const; // 分割成列表 auto SplitTo (wchar_t ch , int start = 0) const -> std::list ; auto SplitTo (tPred && pred, int start = 0) const -> std::list ; // 分割成数组, 最多 Max 个 auto SplitMax (int Max, wchar_t ch , int start = 0) const -> std::vector ; auto SplitMax (int Max, tPred && pred, int start = 0) const -> std::vector ; // 返回指定 Index 的某一个, 如果找不到: 当 Index=0 时返回本串, 否则返回空串 auto SplitOne (int atIndex, wchar_t ch , int start = 0) const ->WString; auto SplitOne (int atIndex, tPred && pred, int start = 0) const ->WString; // Cast public: operator const wchar_t * () const { return m_pchData; } const wchar_t * constBuffer () const { return m_pchData; } wchar_t * data () const { return m_pchData; } const wchar_t * c_str () const { return m_pchData; } DString ToDString () const; DString ToDString (UINT CodePage) const; DString ToDString (const char * LocName) const; DString ToDString (const _locale_t Loc) const; // explicit operator const DString () const { return ToDString (); } operator const DString () const = delete; operator bool () const = delete; // 用于自动判别类型 public: template bool Is () const { return false; } template <> bool Is () const { return true; } template <> bool Is () const { return false; } public: static WString From (const int i); static WString From (const long i); static WString From (const unsigned int u); static WString From (const unsigned long u); static WString From (const __int64 i); static WString From (const unsigned __int64 u); static WString From (const double d); static WString From (const std::wstring_view & Src); static WString From (CV_WString & Src) { return WString (Src); } static WString From (const WString & Src) { return WString (Src); } static WString From (const char * Src) { return FromCodePage (Src, CP_ACP); } static WString From (const wchar_t * lpsz) { return (CV_WString) lpsz; } static WString FromCodePage (const DString & from, UINT CodePage); static WString FromCodePage (const std::string & from, UINT CodePage); static WString FromCodePage (const std::string_view & from, UINT CodePage); static WString FromCodePage (const char * from, UINT CodePage); static WString FromCodePage (const char * from, int len, UINT CodePage); static WString FromLocale (const DString & from, const char * LocName); static WString FromLocale (const char * from, const char * LocName); static WString FromLocale (const char * from, int len, const char * LocName); static WString FromLocale (const DString & from, const _locale_t Loc); static WString FromLocale (const char * from, const _locale_t Loc); static WString FromLocale (const char * from, int len, const _locale_t Loc); // repeat a single character static WString FromRepeat (wchar_t ch, int nRepeat); protected: void FormatV (const wchar_t * lpszFormat, va_list argList); void AppendFormatV (const wchar_t * lpszFormat, va_list argList); protected: // 对于字符串,代码中很容易忘记 L 前缀, 导致传入的是 char *, 而期望的是 wchar_t * // 比如, 正确的写法是: Format ("%s", L"abcd"); 但是很容易写成 Format ("%s", "abcd"); // 为了避免出现这种 BUG, 把这几个函数改成 protected static WString FromFormat (const wchar_t * szFormat, ...); void Format (const wchar_t * lpszFormat, ...); void AppendFormat (const wchar_t * lpszFormat, ...); public: // get pointer to modifiable buffer at least as long as nMinBufLength wchar_t * GetBuffer (int nMinBufLength); // release buffer, setting length to nNewLength (or to first nul if -1) void ReleaseBuffer (int nNewLength = -1); // get pointer to modifiable buffer exactly as long as nNewLength wchar_t * GetBufferSetLength (int nNewLength); void Reserve (int nMinBufLength) { GetBuffer (nMinBufLength); } void reserve (int nMinBufLength) { GetBuffer (nMinBufLength); } public: double Double () const { return _wtof (m_pchData); } int Int () const { int i = _wtoi (m_pchData); if (i) return i; return wcstol (m_pchData, NULL, 16); } long Long () const { long l = _wtol (m_pchData); if (l) return l; return wcstol (m_pchData, NULL, 16); } wchar_t Char () const { return m_pchData[0]; } bool Bool () const; __int64 Int64 () const { __int64 i = _wtoi64 (m_pchData); if (i) return i; return _wcstoi64 (m_pchData, NULL, 16); } template T To () const = delete; template <> int To () const { return Int (); } template <> double To () const { return Double (); } template <> float To () const { return (float) Double (); } template <> long To () const { return Long (); } template <> bool To () const { return Bool (); } template <> __int64 To () const { return Int64 (); } template <> unsigned int To () const { return Int (); } template <> unsigned __int64 To () const { return Int64 (); } template <> unsigned long To () const { return Long (); } template <> WString To () const { return *this; } // template <> DString To () const { return this->ToDString (); } template <> std::wstring To () const { return std::wstring { m_pchData, static_cast (GetLength ()) }; } template <> std::wstring_view To () const { return std::wstring_view { m_pchData, static_cast (GetLength ()) }; } public: // 与 StringView 的转换,构造,赋值等 WString (const WStringView & Src); // WString (const std::wstring_view & Src); // 从 DStringView 显式 生成 WString, 需要程序员指定, 以明示: 这种构造是有代价的 static WString From (const StringView & Src); operator WStringView () const noexcept; operator std::wstring_view () const noexcept; template <> WStringView To () const; template <> const WStringView To () const; WString & Assign (const WStringView & _Right); WString & Assign (const std::wstring_view & _Right); WString & Append (std::initializer_list lst); WString & Append (std::initializer_list lst); WString & Append (std::initializer_list lst); WString & Assign (std::initializer_list lst); WString & Assign (std::initializer_list lst); WString & Assign (std::initializer_list lst); // 万一编译器警告: 调用不明确, 就用模板函数显式告诉编译器 template static WString From (std::initializer_list lst) { WString rc; rc.Assign (lst); return rc; } static WString From (std::initializer_list lst) { WString rc; rc.Assign (lst); return rc; } static WString From (std::initializer_list lst) { WString rc; rc.Assign (lst); return rc; } static WString From (std::initializer_list lst) { WString rc; rc.Assign (lst); return rc; } protected: static int __cdecl GetFormattedLength (const wchar_t * pszFormat, va_list argList); static int __cdecl VFormat (wchar_t * lpzBuffer, const wchar_t * pszFormat, va_list argList); public: // release memory allocated to but unused by string void FreeExtra (); protected: wchar_t * m_pchData; // pointer to ref counted string data WStringData * GetData() const { return ((WStringData *) m_pchData)-1; } bool IsNil () const; // 用来判断 m_pchData 是否等于 WStringPchNil void Init (); void AllocCopy (WString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const; void AllocBuffer (int Len); void AssignCopy (int Len, const wchar_t * S); void ConcatCopy (int L1, const wchar_t * S1, int L2, const wchar_t * S2); void ConcatInPlace (int Len, const wchar_t * S); void CopyBeforeWrite (); void AllocBeforeWrite (int nLen); // 拷贝赋值 WString & Assign (const WString & Src); void MoveAssign (WString & Src); void MoveAssign (WString && Src); static void Release (WStringData * pData); static void FreeData (WStringData * pData); }; } namespace eSTR = ECOM::Utility::String; WSTRING_API eSTR::WString operator + (const eSTR::WString & S1, const eSTR::DString & S2); WSTRING_API eSTR::WString operator + (const eSTR::DString & S1, const eSTR::WString & S2); WSTRING_API eSTR::WString operator + (const eSTR::WString & S1, const eSTR::WString & S2); WSTRING_API eSTR::WString operator + (const eSTR::WString & S, wchar_t ch); WSTRING_API eSTR::WString operator + (const eSTR::WString & S1, const eSTR::WStringView & S2); WSTRING_API eSTR::WString operator + (const eSTR::WStringView & S1, const eSTR::WString & S2); WSTRING_API eSTR::WString operator + (const eSTR::WStringView & S1, wchar_t ch); WSTRING_API eSTR::WString operator + (wchar_t ch, const eSTR::WString & S); WSTRING_API eSTR::WString operator + (const eSTR::WString & S1, const std::wstring_view & S2); WSTRING_API eSTR::WString operator + (const std::wstring_view & S1, const eSTR::WString & S2); WSTRING_API eSTR::WString operator + (const std::wstring_view & S1, wchar_t ch); WSTRING_API eSTR::WString operator + (const eSTR::WString & S1, const std::wstring & S2); WSTRING_API eSTR::WString operator + (const std::wstring & S1, const eSTR::WString & S2); WSTRING_API eSTR::WString operator + (const eSTR::WStringView & S1, const eSTR::WStringView & S2); // Compare helpers WSTRING_API inline bool operator == (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) == 0; } WSTRING_API inline bool operator != (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) != 0; } WSTRING_API inline bool operator < (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) < 0; } WSTRING_API inline bool operator > (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) > 0; } WSTRING_API inline bool operator <= (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) <= 0; } WSTRING_API inline bool operator >= (const eSTR::WString & s1, const eSTR::WStringView s2) { return s1.Compare (s2) >= 0; } #if 1 inline bool operator == (const eSTR::WString & s1, const wchar_t * s2) = delete; inline bool operator != (const eSTR::WString & s1, const wchar_t * s2) = delete; inline bool operator < (const eSTR::WString & s1, const wchar_t * s2) = delete; inline bool operator > (const eSTR::WString & s1, const wchar_t * s2) = delete; inline bool operator <= (const eSTR::WString & s1, const wchar_t * s2) = delete; inline bool operator >= (const eSTR::WString & s1, const wchar_t * s2) = delete; #else WSTRING_API inline bool operator == (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) == 0; } WSTRING_API inline bool operator != (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) != 0; } WSTRING_API inline bool operator < (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) < 0; } WSTRING_API inline bool operator > (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) > 0; } WSTRING_API inline bool operator <= (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) <= 0; } WSTRING_API inline bool operator >= (const eSTR::WString & s1, const wchar_t * s2) { return s1.Compare (s2) >= 0; } #endif WSTRING_API inline bool operator == (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) == 0; } WSTRING_API inline bool operator != (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) != 0; } WSTRING_API inline bool operator < (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) > 0; } WSTRING_API inline bool operator > (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) < 0; } WSTRING_API inline bool operator <= (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) >= 0; } WSTRING_API inline bool operator >= (const eSTR::WStringView & s1, const eSTR::WString & s2) { return s2.Compare (s1) <= 0; } #if 1 inline bool operator == (const wchar_t * s1, const eSTR::WString & s2) = delete; inline bool operator != (const wchar_t * s1, const eSTR::WString & s2) = delete; inline bool operator < (const wchar_t * s1, const eSTR::WString & s2) = delete; inline bool operator > (const wchar_t * s1, const eSTR::WString & s2) = delete; inline bool operator <= (const wchar_t * s1, const eSTR::WString & s2) = delete; inline bool operator >= (const wchar_t * s1, const eSTR::WString & s2) = delete; #else WSTRING_API inline bool operator == (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) == 0; } WSTRING_API inline bool operator != (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) != 0; } WSTRING_API inline bool operator < (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) > 0; } WSTRING_API inline bool operator > (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) < 0; } WSTRING_API inline bool operator <= (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) >= 0; } WSTRING_API inline bool operator >= (const wchar_t * s1, const eSTR::WString & s2) { return s2.Compare (s1) <= 0; } #endif template <> struct std::hash { size_t operator() (const wchar_t * pc) const noexcept { auto len = wcslen (pc); return std::_Hash_array_representation (pc, len); } size_t operator() (const eSTR::WString & from) const noexcept { auto pc = from.constBuffer (); auto len = from.GetLength (); return std::_Hash_array_representation (pc, len); } }; #include "Hash.String.hpp" //< 针对 WString 的 Hash. 目的是避免编译器的错误: 重载函数调用不明确 namespace ECOM::Utility { inline constexpr size_t Hash (const String::WString & SV) { return (Hash (SV.To ())); } }