Index: ps/trunk/source/ps/CStr.cpp =================================================================== --- ps/trunk/source/ps/CStr.cpp (revision 25899) +++ ps/trunk/source/ps/CStr.cpp (revision 25900) @@ -1,536 +1,572 @@ /* 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 * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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 #define CStr_CPP_FIRST #include "lib/fnv_hash.h" #include "lib/utf8.h" #include "lib/byte_order.h" #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" // Only include these function definitions in the first instance of CStr.cpp: /** * Convert CStr to UTF-8 * * @return CStr8 converted string **/ CStr8 CStrW::ToUTF8() const { Status err; return utf8_from_wstring(*this, &err); } /** * Convert UTF-8 to CStr * * @return CStrW converted string **/ CStrW CStr8::FromUTF8() const { Status err; return wstring_from_utf8(*this, &err); } #else // The following code is compiled twice, as CStrW then as CStr8: #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; ret.reserve(str.length() * reps); while (reps--) ret += str; return ret; } // Construction from numbers: CStr CStr::FromInt(int n) { tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromUInt(unsigned int n) { tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromInt64(i64 n) { tstringstream ss; ss << n; return ss.str(); } CStr CStr::FromDouble(double n) { tstringstream ss; ss << n; return ss.str(); } // Conversion to numbers: int CStr::ToInt() const { int ret = 0; tstringstream str(*this); str >> ret; return ret; } unsigned int CStr::ToUInt() const { unsigned int ret = 0; tstringstream str(*this); str >> ret; return ret; } long CStr::ToLong() const { long ret = 0; tstringstream str(*this); str >> ret; return ret; } unsigned long CStr::ToULong() const { unsigned long ret = 0; tstringstream str(*this); str >> ret; return ret; } /** * libc++ and libstd++ differ on how they handle string-to-number parsing for floating-points numbers. * See https://trac.wildfiregames.com/ticket/2780#comment:4 for details. * To prevent this, only consider [0-9.-+], replace the others in-place with a neutral character. */ CStr ParseableAsNumber(CStr cleaned_copy) { - for (tchar& c : cleaned_copy) + for (CStr::Char& c : cleaned_copy) if (!std::isdigit(c) && c != '.' && c != '-' && c != '+') c = ' '; return cleaned_copy; } float CStr::ToFloat() const { float ret = 0; tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } double CStr::ToDouble() const { double ret = 0; tstringstream str(ParseableAsNumber(*this)); str >> ret; return ret; } // Search the string for another string long CStr::Find(const CStr& str) const { size_t pos = find(str, 0); if (pos != npos) return static_cast(pos); return -1; } // 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); if (pos != npos) return static_cast(pos); return -1; } // 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); if (pos != npos) return static_cast(pos); 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 { size_t pos = rfind(str, length() ); if (pos != npos) return static_cast(pos); return -1; } // Lowercase and uppercase 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; } 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; } // Retrieve the substring of the first n characters CStr CStr::Left(size_t len) const { ENSURE(len <= length()); return substr(0, len); } // Retrieve the substring of the last n characters CStr CStr::Right(size_t len) const { ENSURE(len <= length()); return substr(length()-len, len); } // Retrieve the substring following the last occurrence of Str // (or the whole string if it doesn't contain Str) CStr CStr::AfterLast(const CStr& str, size_t startPos) const { size_t pos = rfind(str, startPos); if (pos == npos) return *this; else return substr(pos + str.length()); } // Retrieve the substring preceding the last occurrence of Str // (or the whole string if it doesn't contain Str) CStr CStr::BeforeLast(const CStr& str, size_t startPos) const { size_t pos = rfind(str, startPos); if (pos == npos) return *this; else return substr(0, pos); } // Retrieve the substring following the first occurrence of Str // (or the whole string if it doesn't contain Str) CStr CStr::AfterFirst(const CStr& str, size_t startPos) const { size_t pos = find(str, startPos); if (pos == npos) return *this; else return substr(pos + str.length()); } // Retrieve the substring preceding the first occurrence of Str // (or the whole string if it doesn't contain Str) CStr CStr::BeforeFirst(const CStr& str, size_t startPos) const { size_t pos = find(str, startPos); if (pos == npos) return *this; else return substr(0, pos); } // Remove all occurrences of some character or substring void CStr::Remove(const CStr& str) { size_t foundAt = 0; while (foundAt != npos) { foundAt = find(str, 0); if (foundAt != npos) erase(foundAt, str.length()); } } // Replace all occurrences of some substring by another void CStr::Replace(const CStr& toReplace, const CStr& replaceWith) { size_t pos = 0; while (pos != npos) { pos = find(toReplace, pos); if (pos != npos) { erase(pos, toReplace.length()); insert(pos, replaceWith); pos += replaceWith.length(); } } } 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 += "\\\\"; else if (ch == '\b') newStr += "\\b"; else if (ch == '\f') newStr += "\\f"; else if (ch == '\n') newStr += "\\n"; else if (ch == '\r') newStr += "\\r"; else if (ch == '\t') newStr += "\\t"; else if (ch >= 32 && ch <= 126) newStr += ch; else { std::stringstream ss; ss << "\\u" << std::hex << std::setfill('0') << std::setw(4) << (int)(unsigned char)ch; newStr += ss.str(); } } return newStr; } // Returns a trimmed string, removes whitespace from the left/right/both CStr CStr::Trim(PS_TRIM_MODE mode) const { size_t left = 0, right = 0; switch (mode) { 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; case PS_TRIM_RIGHT: { 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; default: debug_warn(L"CStr::Trim: invalid Mode"); } return substr(left, right - left + 1); } CStr CStr::Pad(PS_TRIM_MODE mode, size_t len) const { size_t left = 0, right = 0; if (len <= length()) return *this; // From here: Length-length() >= 1 switch (mode) { case PS_TRIM_LEFT: left = len - length(); break; case PS_TRIM_RIGHT: right = len - length(); break; case PS_TRIM_BOTH: left = (len - length() + 1) / 2; right = (len - length() - 1) / 2; // cannot be negative break; default: 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 { return (size_t)fnv_hash(data(), length()*sizeof(value_type)); // janwas 2005-03-18: now use 32-bit version; 64 is slower and // 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 Index: ps/trunk/source/ps/CStr.h =================================================================== --- ps/trunk/source/ps/CStr.h (revision 25899) +++ ps/trunk/source/ps/CStr.h (revision 25900) @@ -1,353 +1,354 @@ /* 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 * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /** * Description : Contains CStr class which is a versatile class for making string use easy. * : The class implements a series of string manipulation/formatting functions. **/ #ifndef INCLUDED_CSTR #define INCLUDED_CSTR /** * Whitespace trim identifier for Trim and Pad functions **/ enum PS_TRIM_MODE { PS_TRIM_LEFT, /// Trim all white space from the beginning of the string PS_TRIM_RIGHT, /// Trim all white space from the end of the string PS_TRIM_BOTH /// Trim all white space from the beginning and end of the string }; #ifndef IN_UNIDOUBLER #define UNIDOUBLER_HEADER "CStr.h" #include "UniDoubler.h" #endif #endif // Include this section when in unidoubler mode, and when this unicode/ascii // version has not already been included. #if defined(IN_UNIDOUBLER) && ( (defined(_UNICODE) && !defined(CSTR_H_U)) || (!defined(_UNICODE) && !defined(CSTR_H_A)) ) #ifdef _UNICODE #define CSTR_H_U #else #define CSTR_H_A #endif #include #include "ps/utf16string.h" class CStr8; class CStrW; /** * The base class of all strings **/ 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) {} /** * Repeat: Named constructor, to avoid overload overload. * * @param const CStr & str reference to another CStr object to be repeated for initialization * @param size_t Reps number of times to repeat the initialization * @return CStr new CStr object **/ static CStr Repeat(const CStr& str, size_t reps); /** * Construction from utf16strings. * * @param utf16string String utf16string to be used for initialization. **/ explicit CStr(const utf16string& str) : StrBase(str.begin(), str.end()) {} // Conversion to/from UTF-8, encoded in a CStr8. // Invalid bytes/characters (e.g. broken UTF-8, and Unicode characters // above U+FFFF) are silently replaced with U+FFFD. #ifdef _UNICODE CStr8 ToUTF8() const; #else CStrW FromUTF8() const; #endif // Conversions: static CStr FromInt(int n); static CStr FromUInt(unsigned int n); static CStr FromInt64(i64 n); static CStr FromDouble(double n); /** * Return CStr as Integer. * Conversion is from the beginning of CStr. * * @return int CStr represented as an integer. **/ int ToInt() const; /** * Return CStr as Unsigned Integer. * Conversion is from the beginning of CStr. * * @return unsigned int CStr represented as an unsigned integer. **/ unsigned int ToUInt() const; /** * Return CStr as Long. * Conversion is from the beginning of CStr. * * @return long CStr represented as a long. **/ long ToLong() const; /** * Return CStr as Unsigned Long. * Conversion is from the beginning of CStr. * * @return unsigned long CStr represented as an unsigned long. **/ unsigned long ToULong() const; /** * Return CStr as Float. * Conversion is from the beginning of CStr. * * @return float CStr represented as a float. **/ float ToFloat() const; /** * Return CStr as Double. * Conversion is from the beginning of CStr. * * @return double CStr represented as a double. **/ double ToDouble() const; /** * Search the CStr for another string. * The search is case-sensitive. * * @param const CStr & str reference to the search string * @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 CStr& str) const; /** * Search the CStr for another string. * The search is case-sensitive. * * @param const {t|w}char_t & chr reference to the search string * @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. * * @param const int & start character offset into CStr to begin search * @param const {t|w}char_t & chr reference to the search string * @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. * The search is case-insensitive. * * @param const CStr & str reference to the search string * @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 CStr& str) const; /** * Search the CStr for another string. * The search is case-insensitive. * * @param const {t|w}char_t & chr reference to the search string * @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. * * @param const int & start character offset into CStr to begin search * @param const {t|w}char_t & chr reference to the search string * @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. * The search is case-sensitive. * * @param const CStr & str reference to the search string * @return long offset into the CStr of the last occurrence of the search string * -1 if the search string is not found **/ long ReverseFind(const CStr& str) const; /** * Make a copy of the CStr in lower-case. * * @return CStr converted copy of CStr. **/ CStr LowerCase() const; /** * Make a copy of the CStr in upper-case. * * @return CStr converted copy of CStr. **/ CStr UpperCase() const; /** * Retrieve first n characters of the CStr. * * @param size_t len the number of characters to retrieve. * @return CStr retrieved substring. **/ CStr Left(size_t len) const; /** * Retrieve last n characters of the CStr. * * @param size_t len the number of characters to retrieve. * @return CStr retrieved substring. **/ CStr Right(size_t len) const; /** * Retrieve substring of the CStr after last occurrence of a string. * Return substring of the CStr after the last occurrence of the search string. * * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring remaining after match * the CStr if no match is found **/ CStr AfterLast(const CStr& str, size_t startPos = npos) const; /** * Retrieve substring of the CStr preceding last occurrence of a string. * Return substring of the CStr preceding the last occurrence of the search string. * * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring preceding before match * the CStr if no match is found **/ CStr BeforeLast(const CStr& str, size_t startPos = npos) const; /** * Retrieve substring of the CStr after first occurrence of a string. * Return substring of the CStr after the first occurrence of the search string. * * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring remaining after match * the CStr if no match is found **/ CStr AfterFirst(const CStr& str, size_t startPos = 0) const; /** * Retrieve substring of the CStr preceding first occurrence of a string. * Return substring of the CStr preceding the first occurrence of the search string. * * @param const CStr & str reference to search string * @param size_t startPos character position to start searching from * @return CStr substring preceding before match * the CStr if no match is found **/ CStr BeforeFirst(const CStr& str, size_t startPos = 0) const; /** * Remove all occurrences of a string from the CStr. * * @param const CStr & str reference to search string to remove. **/ void Remove(const CStr& str); /** * Replace all occurrences of one string by another string in the CStr. * * @param const CStr & strToReplace reference to search string. * @param const CStr & replaceWith reference to replace string. **/ void Replace(const CStr& toReplace, const CStr& replaceWith); /** * Convert strings to printable ASCII characters with JSON-style escapes. */ std::string EscapeToPrintableASCII() const; /** * Return a trimmed copy of the CStr. * * @param PS_TRIM_MODE Mode value from trim mode enumeration. * @return CStr copy of trimmed CStr. **/ CStr Trim(PS_TRIM_MODE mode) const; /** * Return a space padded copy of the CStr. * * @param PS_TRIM_MODE Mode value from trim mode enumeration. * @param size_t Length number of pad spaces to add * @return CStr copy of padded CStr. **/ CStr Pad(PS_TRIM_MODE mode, size_t len) const; // Conversion to utf16string utf16string utf16() const { return utf16string(begin(), end()); } // Calculates a hash of the string's contents size_t GetHashCode() const; // Serialization functions // (These are not virtual or inherited from ISerializable, to avoid // adding a vtable and making the strings larger than std::string) size_t GetSerializedLength() const; u8* Serialize(u8* buffer) const; const u8* Deserialize(const u8* buffer, const u8* bufferend); }; namespace std { template <> struct hash { std::size_t operator()(const CStr& str) const { return str.GetHashCode(); } }; } #endif Index: ps/trunk/source/ps/UniDoubler.h =================================================================== --- ps/trunk/source/ps/UniDoubler.h (revision 25899) +++ ps/trunk/source/ps/UniDoubler.h (revision 25900) @@ -1,70 +1,60 @@ -/* 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 * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ // Make sure we have the argument (UNIDOUBLER_HEADER), and that we're not // called from within another unidoubler execution (now that's just asking for // trouble) #if defined(UNIDOUBLER_HEADER) && !defined(IN_UNIDOUBLER) #define IN_UNIDOUBLER // When compiling CStr.cpp with PCH, the unidoubler stuff gets rather // confusing because of all the nested inclusions, but this makes it work: #undef CStr // First, set up the environment for the Unicode version #ifndef _UNICODE #define _UNICODE #endif #define CStr CStrW #define tstring wstring -#define tchar wchar_t -#define _T(t) L ## t // Include the unidoubled file #include UNIDOUBLER_HEADER // Clean up all the macros #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 #undef IN_UNIDOUBLER #undef UNIDOUBLER_HEADER #endif