#pragma once #ifndef ASSERT #include #define ASSERT assert #endif //----------------------------------------------------------------------------- // 字符串格式化 // 思路主要来自祈宇的文章: // <实现一个简单的字符串格式化方法> // https://www.cnblogs.com/qicosmos/p/3825612.html //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include // 标准整数类型 #include // snprintf函数 #include // 字符串操作函数 #include // Linux下移除Windows特有警告禁用,替换为GCC兼容的警告处理(如需) #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif namespace ZSKK::Utility::String { template constexpr bool dependent_false = false; template inline std::string ToString(const T& value) { static_assert(dependent_false, "You must implement ToString for type T with Partial template specialization !"); return std::string(); } } // 针对 bool 的模板偏特化 namespace ZSKK::Utility::String { template <> inline std::string ToString(const bool& value) { static const auto strTrue = std::string("true"); static const auto strFalse = std::string("false"); return value ? strTrue : strFalse; } } namespace ZSKK::Utility::String { static const char __MsgOfNull_[] = "null"; static const int __LenOfNull_ = sizeof(__MsgOfNull_) - 1; template class _string_format_detail { protected: char* m_BufferOrg; char* m_Buffer; int m_NbOfChar; protected: inline int NbOfRemain() const { return m_NbOfChar - int(m_Buffer - m_BufferOrg); } private: template int _my_sprintf(char* buf, int NbOfChar, const char* fmt, arg a) { assert(false); return 22; } public: inline _string_format_detail(char* buf, int NbOfChar) // 缓冲区指针, 缓冲区长度 (字节计数) { assert(buf); m_BufferOrg = m_Buffer = buf; m_NbOfChar = NbOfChar; } protected: inline void CharFormatArg(char ch) { assert(9 <= ch && ch <= 127); // 确保非控制字符 *m_Buffer = ch; m_Buffer++; } // 有符号整数格式化 - 使用重载而非特化 inline void sDigitFormatArg(int i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%d", i); if (len > 0) m_Buffer += len; } inline void sDigitFormatArg(short i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%hd", i); if (len > 0) m_Buffer += len; } inline void sDigitFormatArg(int64_t i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%lld", i); if (len > 0) m_Buffer += len; } // 无符号整数格式化 - 使用重载而非特化 inline void uDigitFormatArg(unsigned int i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%u", i); if (len > 0) m_Buffer += len; } /* inline void uDigitFormatArg(unsigned long i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%lu", i); if (len > 0) m_Buffer += len; }*/ inline void uDigitFormatArg(unsigned short i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%hu", i); if (len > 0) m_Buffer += len; } inline void uDigitFormatArg(uint64_t i) { int len = std::snprintf(m_Buffer, NbOfRemain(), "%llu", i); if (len > 0) m_Buffer += len; } // 带格式的整数格式化 - 使用重载而非特化 inline void DigitFormatArg(int i, const char* fmt) { // 实现代码保持不变 assert(fmt && fmt[0]); auto chfmt = fmt[0]; if (chfmt == 'c' || chfmt == 'C') { CharFormatArg(static_cast(i)); return; } if (chfmt == 'D') chfmt = 'd'; // 统一为小写格式符 if (chfmt == 'U') chfmt = 'u'; auto rc = (chfmt == 'd' || chfmt == 'u' || chfmt == 'X' || chfmt == 'x'); if (!rc) { rc = (chfmt == 'f' || chfmt == 'F'); if (rc) { FormatArg(static_cast(i), fmt); return; } } assert(rc); if (!rc) return; char tofmt[8] = { '%', }; // 处理格式数字(如D023 -> %023d) if (std::isdigit(fmt[1])) { int iFmtChar = 2; for (int Index = 1; Index <= 3; ++Index) { if (std::isdigit(fmt[Index])) { tofmt[Index] = fmt[Index]; iFmtChar = Index + 1; } else break; } tofmt[iFmtChar] = chfmt; } else { tofmt[1] = chfmt; tofmt[2] = 0; } auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), tofmt, i); m_Buffer += r; } // 64位有符号整数带格式重载 inline void DigitFormatArg(int64_t i, const char* fmt) { // 实现代码保持不变 assert(fmt && fmt[0]); auto chfmt = fmt[0]; if (chfmt == 'c' || chfmt == 'C') { CharFormatArg(static_cast(i)); return; } if (chfmt == 'D') chfmt = 'd'; if (chfmt == 'U') chfmt = 'u'; auto rc = (chfmt == 'd' || chfmt == 'u' || chfmt == 'X' || chfmt == 'x'); assert(rc); if (!rc) return; // Linux下64位整数格式符为%lld/%llx,无需Windows的%I64d char tofmt[8] = { '%', }; if (chfmt == 'd' || chfmt == 'i') std::strcpy(tofmt, "%lld"); else if (chfmt == 'x') std::strcpy(tofmt, "%llx"); else if (chfmt == 'X') std::strcpy(tofmt, "%llX"); else if (chfmt == 'u') std::strcpy(tofmt, "%llu"); auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), tofmt, i); m_Buffer += r; } // 64位无符号整数带格式重载 inline void DigitFormatArg(uint64_t i, const char* fmt) { DigitFormatArg(static_cast(i), fmt); } // 字符格式化(无格式) inline void FormatArg(char ch) { CharFormatArg(ch); } inline void FormatArg(unsigned char ch) { uDigitFormatArg(static_cast(ch)); } // 字符格式化(带格式,按整数处理) inline void FormatArg(char ch, const char* fmt) { DigitFormatArg(static_cast(ch), fmt); } inline void FormatArg(unsigned char ch, const char* fmt) { DigitFormatArg(static_cast(ch), fmt); } // 各种整数类型格式化 inline void FormatArg(int i) { sDigitFormatArg(i); } //inline void FormatArg(long i) { sDigitFormatArg(i); } inline void FormatArg(short i) { sDigitFormatArg(i); } inline void FormatArg(unsigned int i) { uDigitFormatArg(i); } //inline void FormatArg(unsigned long i) { uDigitFormatArg(i); } inline void FormatArg(unsigned short i) { uDigitFormatArg(i); } // 整数带格式格式化 inline void FormatArg(int i, const char* fmt) { DigitFormatArg(i, fmt); } inline void FormatArg(unsigned int i, const char* fmt) { DigitFormatArg(i, fmt); } //inline void FormatArg(long i, const char* fmt) { DigitFormatArg(i, fmt); } //inline void FormatArg(unsigned long i, const char* fmt) { DigitFormatArg(i, fmt); } inline void FormatArg(short i, const char* fmt) { DigitFormatArg(i, fmt); } inline void FormatArg(unsigned short i, const char* fmt) { DigitFormatArg(i, fmt); } // 64位整数格式化 inline void FormatArg(int64_t i) { sDigitFormatArg(i); } inline void FormatArg(uint64_t i) { uDigitFormatArg(i); } inline void FormatArg(int64_t i, const char* fmt) { DigitFormatArg(i, fmt); } inline void FormatArg(uint64_t i, const char* fmt) { DigitFormatArg(i, fmt); } // 浮点数格式化(默认精度) inline void FormatArg(double i) { auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), "%f", i); m_Buffer += r; } // 浮点数带格式格式化(如F3 -> 保留3位小数) inline void FormatArg(double i, const char* fmt) { assert(fmt && fmt[0]); char tofmt[8] = { '%', '.', }; auto chfmt = fmt[0]; if (std::isdigit(fmt[1])) { int iFmtChar = 2; for (int Index = 1; Index <= 3; ++Index) { if (std::isdigit(fmt[Index])) { tofmt[Index + 1] = fmt[Index]; iFmtChar = Index + 2; } else break; } tofmt[iFmtChar] = chfmt; } else { tofmt[1] = chfmt; tofmt[2] = 0; } auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), tofmt, i); m_Buffer += r; } // 浮点数(float)格式化 inline void FormatArg(float f) { FormatArg(static_cast(f)); } inline void FormatArg(float f, const char* fmt) { FormatArg(static_cast(f), fmt); } // 字符串格式化(无格式) inline void FormatArg(const char* p) { if (!p) { std::memcpy(m_Buffer, __MsgOfNull_, __LenOfNull_); m_Buffer += __LenOfNull_; return; } int len = static_cast(std::strlen(p)); std::memcpy(m_Buffer, p, len); m_Buffer += len; } // 字符串带格式格式化(对齐处理) inline void FormatArg(const char* p, const char* fmt) { if (!p) { std::memcpy(m_Buffer, __MsgOfNull_, __LenOfNull_); m_Buffer += __LenOfNull_; return; } int len = static_cast(std::strlen(p)); _StringFormatArg(p, len, fmt); } inline void FormatArg(char* p) { FormatArg(static_cast(p)); } inline void FormatArg(char* p, const char* fmt) { FormatArg(static_cast(p), fmt); } // 字符串格式处理实现(对齐) inline void _StringFormatArg(const char* p, int len, const char* fmt) { if (!p) { std::memcpy(m_Buffer, __MsgOfNull_, __LenOfNull_); m_Buffer += __LenOfNull_; return; } if (fmt[0] == '-') // 左对齐 { fmt++; auto i = std::atoi(fmt); if (i > len) { std::memcpy(m_Buffer, p, len); m_Buffer += len; std::memset(m_Buffer, ' ', i - len); m_Buffer += i - len; } else { std::memcpy(m_Buffer, p, len); m_Buffer += len; } } else // 右对齐 { if (fmt[0] == '+') fmt++; auto i = std::atoi(fmt); if (i > len) { std::memset(m_Buffer, ' ', i - len); m_Buffer += i - len; std::memcpy(m_Buffer, p, len); m_Buffer += len; } else { std::memcpy(m_Buffer, p, len); m_Buffer += len; } } } // bool类型格式化 void FormatArg(bool b) { if (b) { *m_Buffer++ = 't'; *m_Buffer++ = 'r'; *m_Buffer++ = 'u'; *m_Buffer++ = 'e'; } else { *m_Buffer++ = 'f'; *m_Buffer++ = 'a'; *m_Buffer++ = 'l'; *m_Buffer++ = 's'; *m_Buffer++ = 'e'; } } // 指针类型格式化 template inline void FormatArg(const UNP* ptr) { auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), "%p", ptr); m_Buffer += r; } // 指针带格式格式化(按整数处理) template inline void FormatArg(const UNP* ptr, const char* fmt) { DigitFormatArg(static_cast(ptr), fmt); } // 非const指针格式化 template inline void FormatArg(UNP* ptr) { auto pT = static_cast(this); auto r = pT->_my_sprintf(m_Buffer, NbOfRemain(), "%p", ptr); m_Buffer += r; } // 非const指针带格式格式化 template inline void FormatArg(UNP* ptr, const char* fmt) { DigitFormatArg(static_cast(ptr), fmt); } protected: // string_view格式化 inline void FormatArg(const std::string_view& s) { std::memcpy(m_Buffer, s.data(), s.size()); m_Buffer += s.size(); } inline void FormatArg(const std::string_view& s, const char* fmt) { _StringFormatArg(s.data(), static_cast(s.size()), fmt); } // wstring_view格式化(Linux下宽字符转多字节) inline void FormatArg(const std::wstring_view& s) { std::wstring_convert> converter; auto str = converter.to_bytes(s.data(), s.data() + s.size()); FormatArg(str); } inline void FormatArg(const std::wstring_view& s, const char* fmt) { std::wstring_convert> converter; auto str = converter.to_bytes(s.data(), s.data() + s.size()); FormatArg(str, fmt); } #ifdef __Utility_String_StringView__ inline void FormatArg(const DStringView& s) { std::memcpy(m_Buffer, s.constBuffer(), s.Length()); m_Buffer += s.Length(); } inline void FormatArg(const DStringView& s, const char* fmt) { _StringFormatArg(s.constBuffer(), s.Length(), fmt); } #endif #ifdef DSTRING_API inline void FormatArg(const DString& s) { std::memcpy(m_Buffer, s.constBuffer(), s.GetLength()); m_Buffer += s.GetLength(); } inline void FormatArg(const DString& s, const char* fmt) { _StringFormatArg(s.constBuffer(), s.GetLength(), fmt); } #endif // std::string格式化 inline void FormatArg(const std::string& s) { std::memcpy(m_Buffer, s.data(), s.size()); m_Buffer += s.size(); } inline void FormatArg(const std::string& s, const char* fmt) { _StringFormatArg(s.data(), static_cast(s.size()), fmt); } #ifdef WSTRING_API inline void FormatArg(const wchar_t* p) { if (!p) { std::memcpy(m_Buffer, __MsgOfNull_, __LenOfNull_); m_Buffer += __LenOfNull_; return; } auto dp = WString(WStringView(p)).ToDString(); FormatArg(dp); } inline void FormatArg(const wchar_t* p, const char* fmt) { if (!p) { std::memcpy(m_Buffer, __MsgOfNull_, __LenOfNull_); m_Buffer += __LenOfNull_; return; } auto dp = WString(WStringView(p)).ToDString(); FormatArg(dp, fmt); } inline void FormatArg(const WString& s) { auto dp = s.ToDString(); FormatArg(dp); } inline void FormatArg(const WString& s, const char* fmt) { auto dp = s.ToDString(); FormatArg(dp, fmt); } inline void FormatArg(const std::wstring& s) { auto dp = WString(s.c_str()).ToDString(); FormatArg(dp); } inline void FormatArg(const std::wstring& s, const char* fmt) { auto dp = WString(s.c_str()).ToDString(); FormatArg(dp, fmt); } inline void FormatArg(const WStringView& ws) { auto ds = WString(ws).ToDString(); FormatArg(ds); } inline void FormatArg(const WStringView& ws, const char* fmt) { auto ds = WString(ws).ToDString(); FormatArg(ds, fmt); } #endif #if 1 template inline void FormatArg(const TO& _val) { auto dp = ZSKK::Utility::String::ToString(_val); FormatArg(dp); } template inline void FormatArg(const TO& _val, const char* fmt) { auto dp = ZSKK::Utility::String::ToString(_val); FormatArg(dp, fmt); } #endif protected: // 元组参数索引访问(无格式) template typename std::enable_if<(k == std::tuple_size::value)>::type inline GetArgByIndex(size_t, Tuple&) { #ifdef _DEBUG // throw std::invalid_argument("arg index out of range"); #endif } template typename std::enable_if<(k < std::tuple_size::value)>::type inline GetArgByIndex(size_t index, Tuple& tp) { if (k == index) { FormatArg(std::get(tp)); } else { GetArgByIndex(index, tp); } } // 元组参数索引访问(带格式) template typename std::enable_if<(k == std::tuple_size::value)>::type inline GetArgByIndex(size_t, Tuple&, const char* fmt) { #ifdef _DEBUG // throw std::invalid_argument("arg index out of range"); #endif } template typename std::enable_if<(k < std::tuple_size::value)>::type inline GetArgByIndex(size_t index, Tuple& tp, const char* fmt) { if (k == index) { FormatArg(std::get(tp), fmt); } else { GetArgByIndex(index, tp, fmt); } } // 格式解析辅助函数:查找$符号 static inline const char* FirstDollar(const char*& p) { while (*p != '}' && *p != '\0') { if ('$' == (*p)) return p; p++; } return nullptr; } // 格式解析辅助函数:查找数字 static inline const char* FirstDigit(const char*& p) { while (*p != '}' && *p != '\0') { if (std::isdigit(*p)) return p; p++; } return nullptr; } // 格式解析辅助函数:查找最后一个数字 static inline const char* LastDigit(const char*& p) { while (*p != '}' && *p != '\0') { if (!std::isdigit(*p)) return p - 1; p++; } return p - 1; } // 格式解析辅助函数:查找冒号 static inline const char* FindColon(const char*& p) { while (*p != '}' && *p != '\0') { if (*p == ':') return p; p++; } return nullptr; } // 格式解析辅助函数:查找右括号 static inline const char* FindRightBrace(const char*& p) { while (*p != '\0') { if (*p == '}') return p; p++; } return nullptr; } // 解析参数索引 static inline int GetIndex(const char*& p, const char*& fmt, int prevIndex) { auto bp = p; // 备份当前位置 auto pDollar = FirstDollar(p); if (pDollar) { auto pc = FindColon(p); auto _ = FindRightBrace(p); if (pc) fmt = pc + 1; return prevIndex + 1; } p = bp; auto pd = FirstDigit(p); auto pl = LastDigit(p); auto pc = FindColon(p); auto _ = FindRightBrace(p); if (!pd) return -1; auto ii = pl + 1 - pd; assert(ii <= 2); if (ii <= 0) return -1; char temp[3] = {}; temp[0] = *pd; pd++; temp[1] = *pd; auto index = std::atoi(temp); if (pc) fmt = pc + 1; return index; } public: // 格式化入口(const char*) template inline int Format(const char* fmt, Args&&... args) { int fmtlen = static_cast(std::strlen(fmt)); return DoFormat(fmtlen, fmt, std::forward(args)...); } #ifdef __Utility_String_StringView__ // 格式化入口(DStringView) template inline int Format(const eSTR::StringView& fmt, Args&&... args) { int fmtlen = fmt.GetLength(); return DoFormat(fmtlen, fmt, std::forward(args)...); } #endif // 格式化入口(std::string_view) template inline int Format(const std::string_view& fmt, Args&&... args) { int fmtlen = static_cast(fmt.size()); return DoFormat(fmtlen, fmt, std::forward(args)...); } protected: // 格式化实现(const char*) template inline int DoFormat(int fmtlen, const char* fmt, Args&&... args) { assert(fmt); if (!fmt) { m_Buffer[0] = 0; return 0; } if (sizeof...(args) == 0) { std::strcpy(m_Buffer, fmt); return fmtlen; } auto tp = std::tuple(std::forward(args)...); return DoFormat(fmtlen, fmt, std::move(tp)); } // 格式化实现(元组参数) template inline int DoFormat(int fmtlen, const char* fmt, std::tuple&& tp) { assert(fmt); if (!fmt) { m_Buffer[0] = 0; return 0; } m_Buffer = m_BufferOrg; const char* p = fmt; const char* original = p; int last = 0; int Index = -1; while (true) { if (*p == '{') { // 复制{之前的内容 last = static_cast(p - original); if (last) { std::memcpy(m_Buffer, original, last); m_Buffer += last; } // 解析参数索引和格式 const char* tmpfmt = nullptr; Index = GetIndex(p, tmpfmt, Index); if (Index >= 0) { if (tmpfmt) GetArgByIndex<0>(Index, tp, tmpfmt); else GetArgByIndex<0>(Index, tp); } // 跳过} original = p + 1; } else if (*p == '\0') { // 复制剩余内容 last = static_cast(p - original); if (last == 0) *m_Buffer = 0; else { std::memcpy(m_Buffer, original, last + 1); // 包含终止符 m_Buffer += last; } break; } p++; } auto delta = m_Buffer - m_BufferOrg; #ifdef _DEBUG int len = static_cast(std::strlen(m_BufferOrg)); assert((delta - len) == 0); #endif return static_cast(delta); } }; // 字符串格式化实现类(替换Windows的sprintf_s为Linux的snprintf) class StringFormat : public _string_format_detail { public: inline StringFormat(char* buf, int NbOfChar) : _string_format_detail(buf, NbOfChar) {} public: template inline int _my_sprintf(char* buf, int NbOfChar, const char* fmt, arg a) { // Linux下用snprintf替换Windows的sprintf_s return std::snprintf(buf, NbOfChar, fmt, a); } }; } //----------------------------------------------------------------------------- // 设计说明 (2021-06-18): // 1. 为什么只能支持 3 个数字 (即 最大只能是 {$:d999} 或 {$:f999}) // 1) 预留的 Buffer 一般大小是 8192, 见 DString::Format 及 TLSLog // 2) 最终会调用 snprintf (buffer, len, ...) // 3) 当 buffer 不足时, 上述函数会截断输出, 避免程序崩溃 //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // 自定义类型的格式化 (2023-05-15) /* class TestMyClass { public: TestMyClass() = default; }; namespace ZSKK::Utility::String { template <> inline std::string ToString(const TestMyClass& value) { return std::string("it is TestMyClass !"); } } */ // assert(eSTR::DString::FromFormat("{$}{$}-{$}"_sv, 11, 22, TestMyClass()) == eSTR::DString("1122-it is TestMyClass !")); //-----------------------------------------------------------------------------