From b90066a69b0ba1aac867ee99250200882b069ede Mon Sep 17 00:00:00 2001 From: vladislavbelov Date: Tue, 7 Sep 2021 21:01:34 +0000 Subject: [PATCH] Moves macro-defined methods of CStr to templates. Differential Revision: https://code.wildfiregames.com/D4251 This was SVN commit r25900. --- source/ps/CStr.cpp | 258 +++++++++++++++++++++++------------------ source/ps/CStr.h | 13 ++- source/ps/UniDoubler.h | 12 +- 3 files changed, 155 insertions(+), 128 deletions(-) diff --git a/source/ps/CStr.cpp b/source/ps/CStr.cpp index 674064260a..6bba5c42df 100644 --- a/source/ps/CStr.cpp +++ b/source/ps/CStr.cpp @@ -15,10 +15,6 @@ * along with 0 A.D. If not, see . */ -/** - * Description : Controls compilation of CStr class and - * : includes some function implementations. - **/ #include "precompiled.h" #ifndef CStr_CPP_FIRST @@ -30,8 +26,137 @@ #include "network/Serialization.h" #include +#include #include #include +#include + +namespace +{ + // Use a knowingly false expression, as we can't use + // static_assert(false, ...) directly, because it's an ill-formed program + // with a value (false) which doesn't depend on any input parameter. + // We don't use constexpr bool AlwaysFalse = false, because some compilers + // complain about an unused constant. + template + struct AlwaysFalse : std::false_type + {}; + + template + using tstringstream = std::basic_stringstream; + + template + bool istspace(const Char chr) + { + if constexpr (std::is_same_v) + return static_cast(std::isspace(chr)); + else + return static_cast(std::iswspace(chr)); + } + + template + Char totlower(const Char chr) + { + if constexpr (std::is_same_v) + return std::tolower(chr); + else + return std::towlower(chr); + } + + template + Char totupper(const Char chr) + { + if constexpr (std::is_same_v) + return std::toupper(chr); + else + return std::towupper(chr); + } + + template + u8* SerializeImpl(const StrBase& str, u8* buffer) + { + using Char = typename StrBase::value_type; + ENSURE(buffer); + if constexpr (std::is_same_v) + { + // CStr8 is always serialized to / from ASCII(or whatever 8 - bit codepage stored + // in the CStr). + size_t len = str.length(); + Serialize_int_4(buffer, (u32)len); + size_t i = 0; + for (i = 0; i < len; i++) + buffer[i] = str[i]; + return buffer + len; + } + else if constexpr (std::is_same_v) + { + // CStrW is always serialized to / from UTF - 16. + size_t len = str.length(); + size_t i = 0; + for (i = 0; i < len; i++) + { + const u16 bigEndian = to_be16(str[i]); + *(u16 *)(buffer + i * 2) = bigEndian; + } + *(u16 *)(buffer + i * 2) = 0; + return buffer + len * 2 + 2; + } + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + + template + const u8* DeserializeImpl(const u8* buffer, const u8* bufferend, StrBase& str) + { + using Char = typename StrBase::value_type; + ENSURE(buffer); + ENSURE(bufferend); + if constexpr (std::is_same_v) + { + u32 len; + Deserialize_int_4(buffer, len); + if (buffer + len > bufferend) + return NULL; + str = StrBase(buffer, buffer + len); + return buffer + len; + } + else if constexpr (std::is_same_v) + { + const u16 *strend = (const u16 *)buffer; + while ((const u8 *)strend < bufferend && *strend) + strend++; + if ((const u8 *)strend >= bufferend) + return nullptr; + + str.resize(strend - (const u16 *)buffer); + const u16 *ptr = (const u16 *)buffer; + + typename StrBase::iterator it = str.begin(); + while (ptr < strend) + { + const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same + *(it++) = (Char)native; + } + + return (const u8 *)(strend + 1); + } + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + + template + size_t GetSerializedLengthImpl(const StrBase& str) + { + using Char = typename StrBase::value_type; + if constexpr (std::is_same_v) + return str.length() + 4; + else if constexpr (std::is_same_v) + return str.length() * 2 + 2; + else + static_assert(AlwaysFalse::value, "Not implemented."); + } + +} // anonymous namespace #define UNIDOUBLER_HEADER "CStr.cpp" #include "UniDoubler.h" @@ -67,26 +192,6 @@ CStrW CStr8::FromUTF8() const #include "CStr.h" -#include - -#ifdef _UNICODE - #define _istspace iswspace - #define _totlower towlower - #define _totupper towupper -#else - #define _istspace isspace - #define _totlower tolower - #define _totupper toupper -#endif - -namespace -{ - -template -using tstringstream = std::basic_stringstream; - -} // anonymous namespace - CStr CStr::Repeat(const CStr& str, size_t reps) { CStr ret; @@ -166,7 +271,7 @@ unsigned long CStr::ToULong() const */ CStr ParseableAsNumber(CStr cleaned_copy) { - for (tchar& c : cleaned_copy) + for (CStr::Char& c : cleaned_copy) if (!std::isdigit(c) && c != '.' && c != '-' && c != '+') c = ' '; @@ -201,7 +306,7 @@ long CStr::Find(const CStr& str) const } // Search the string for another string -long CStr::Find(const tchar chr) const +long CStr::Find(const Char chr) const { size_t pos = find(chr, 0); @@ -212,7 +317,7 @@ long CStr::Find(const tchar chr) const } // Search the string for another string -long CStr::Find(const int start, const tchar chr) const +long CStr::Find(const int start, const Char chr) const { size_t pos = find(chr, start); @@ -222,8 +327,8 @@ long CStr::Find(const int start, const tchar chr) const return -1; } -long CStr::FindInsensitive(const int start, const tchar chr) const { return LowerCase().Find(start, _totlower(chr)); } -long CStr::FindInsensitive(const tchar chr) const { return LowerCase().Find(_totlower(chr)); } +long CStr::FindInsensitive(const int start, const Char chr) const { return LowerCase().Find(start, totlower(chr)); } +long CStr::FindInsensitive(const Char chr) const { return LowerCase().Find(totlower(chr)); } long CStr::FindInsensitive(const CStr& str) const { return LowerCase().Find(str.LowerCase()); } long CStr::ReverseFind(const CStr& str) const @@ -241,7 +346,7 @@ CStr CStr::LowerCase() const { StrBase newStr = *this; for (size_t i = 0; i < length(); i++) - newStr[i] = (tchar)_totlower((*this)[i]); + newStr[i] = (Char)totlower((*this)[i]); return newStr; } @@ -250,7 +355,7 @@ CStr CStr::UpperCase() const { StrBase newStr = *this; for (size_t i = 0; i < length(); i++) - newStr[i] = (tchar)_totupper((*this)[i]); + newStr[i] = (Char)totupper((*this)[i]); return newStr; } @@ -348,7 +453,7 @@ std::string CStr::EscapeToPrintableASCII() const std::string newStr; for (size_t i = 0; i < length(); i++) { - tchar ch = (*this)[i]; + Char ch = (*this)[i]; if (ch == '"') newStr += "\\\""; else if (ch == '\\') newStr += "\\\\"; @@ -379,7 +484,7 @@ CStr CStr::Trim(PS_TRIM_MODE mode) const case PS_TRIM_LEFT: { for (left = 0; left < length(); left++) - if (_istspace((*this)[left]) == false) + if (istspace((*this)[left]) == false) break; // end found, trim 0 to Left-1 inclusive } break; @@ -387,19 +492,19 @@ CStr CStr::Trim(PS_TRIM_MODE mode) const { right = length(); while (right--) - if (_istspace((*this)[right]) == false) + if (istspace((*this)[right]) == false) break; // end found, trim len-1 to Right+1 inclusive } break; case PS_TRIM_BOTH: { for (left = 0; left < length(); left++) - if (_istspace((*this)[left]) == false) + if (istspace((*this)[left]) == false) break; // end found, trim 0 to Left-1 inclusive right = length(); while (right--) - if (_istspace((*this)[right]) == false) + if (istspace((*this)[right]) == false) break; // end found, trim len-1 to Right+1 inclusive } break; @@ -439,7 +544,7 @@ CStr CStr::Pad(PS_TRIM_MODE mode, size_t len) const debug_warn(L"CStr::Trim: invalid Mode"); } - return StrBase(left, _T(' ')) + *this + StrBase(right, _T(' ')); + return StrBase(left, ' ') + *this + StrBase(right, ' '); } size_t CStr::GetHashCode() const @@ -449,88 +554,19 @@ size_t CStr::GetHashCode() const // the result was truncated down to 32 anyway. } -#ifdef _UNICODE -/* - CStrW is always serialized to/from UTF-16 -*/ - -u8* CStrW::Serialize(u8* buffer) const +u8* CStr::Serialize(u8* buffer) const { - size_t len = length(); - size_t i = 0; - for (i = 0; i < len; i++) - { - const u16 bigEndian = to_be16((*this)[i]); - *(u16 *)(buffer + i*2) = bigEndian; - } - *(u16 *)(buffer + i*2) = 0; - return buffer + len*2 + 2; + return SerializeImpl(*this, buffer); } -const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend) +const u8* CStr::Deserialize(const u8* buffer, const u8* bufferend) { - ENSURE(buffer); - ENSURE(bufferend); - const u16 *strend = (const u16 *)buffer; - while ((const u8 *)strend < bufferend && *strend) strend++; - if ((const u8 *)strend >= bufferend) return NULL; - - resize(strend - (const u16 *)buffer); - const u16 *ptr = (const u16 *)buffer; - - std::wstring::iterator str = begin(); - while (ptr < strend) - { - const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same - *(str++) = (tchar)native; - } - - return (const u8 *)(strend+1); + return DeserializeImpl(buffer, bufferend, *this); } size_t CStr::GetSerializedLength() const { - return size_t(length()*2 + 2); + return GetSerializedLengthImpl(*this); } -#else -/* - CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored - in the CStr) -*/ - -u8* CStr8::Serialize(u8* buffer) const -{ - size_t len = length(); - Serialize_int_4(buffer, (u32)len); - size_t i = 0; - for (i = 0; i < len; i++) - buffer[i] = (*this)[i]; - return buffer + len; -} - -const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend) -{ - ENSURE(buffer); - ENSURE(bufferend); - u32 len; - Deserialize_int_4(buffer, len); - if (buffer + len > bufferend) - return NULL; - *this = std::string(buffer, buffer + len); - return buffer + len; -} - -size_t CStr::GetSerializedLength() const -{ - return length() + 4; -} - -#endif // _UNICODE - -// Clean up, to keep the second pass through unidoubler happy -#undef _istspace -#undef _totlower -#undef _totupper - #endif // CStr_CPP_FIRST diff --git a/source/ps/CStr.h b/source/ps/CStr.h index 26f19f8821..47158c85bc 100644 --- a/source/ps/CStr.h +++ b/source/ps/CStr.h @@ -63,10 +63,11 @@ class CStr : public std::tstring { public: using StrBase = std::tstring; + using Char = typename std::tstring::value_type; CStr() {} - CStr(const tchar* str) : StrBase(str) {} - CStr(const tchar* str, size_t len) : StrBase(str, len) {} + CStr(const Char* str) : StrBase(str) {} + CStr(const Char* str, size_t len) : StrBase(str, len) {} CStr(const StrBase& str) : StrBase(str) {} template CStr (InputIterator first, InputIterator last) : StrBase(first, last) {} @@ -163,7 +164,7 @@ public: * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long Find(const tchar chr) const; + long Find(const Char chr) const; /** * Search the CStr for another string with starting offset. * The search is case-sensitive. @@ -173,7 +174,7 @@ public: * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long Find(const int start, const tchar chr) const; + long Find(const int start, const Char chr) const; /** * Search the CStr for another string. @@ -192,7 +193,7 @@ public: * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long FindInsensitive(const tchar chr) const; + long FindInsensitive(const Char chr) const; /** * Search the CStr for another string with starting offset. * The search is case-insensitive. @@ -202,7 +203,7 @@ public: * @return long offset into the CStr of the first occurrence of the search string * -1 if the search string is not found **/ - long FindInsensitive(const int start, const tchar chr) const; + long FindInsensitive(const int start, const Char chr) const; /** * Search the CStr for another string. diff --git a/source/ps/UniDoubler.h b/source/ps/UniDoubler.h index 8b8ac3f22b..ed77cb1783 100644 --- a/source/ps/UniDoubler.h +++ b/source/ps/UniDoubler.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,8 +32,6 @@ #endif #define CStr CStrW #define tstring wstring -#define tchar wchar_t -#define _T(t) L ## t // Include the unidoubled file #include UNIDOUBLER_HEADER @@ -42,24 +40,16 @@ #undef _UNICODE #undef CStr #undef tstring -#undef tchar -#undef _T - // Now include the 8-bit version under the name CStr8 #define CStr CStr8 #define tstring string -#define tchar char -#define _T(t) t #include UNIDOUBLER_HEADER // Clean up the macros again, to minimise namespace pollution #undef CStr #undef tstring -#undef tchar -#undef _T - // To please the file that originally include CStr.h, make CStr an alias for CStr8: #define CStr CStr8