From 6456ddac57fc4f840bcf3b8d60227a740815394b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 20 Nov 2022 23:42:43 +0100 Subject: [PATCH] Reimplement wxString::Printf() as variadic template This implementation uses std::index_sequence which is C++14-only, so we'll need to increase the minimum C++ version requirements if we use it. --- include/wx/string.h | 62 +++++++++++++++++++++++++++++++++--------- include/wx/strvararg.h | 20 ++++++++++++++ src/common/string.cpp | 32 ---------------------- 3 files changed, 69 insertions(+), 45 deletions(-) diff --git a/include/wx/string.h b/include/wx/string.h index cc8f0abc51..3beb74b7dd 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -43,6 +43,8 @@ #include "wx/beforestd.h" #include +#include +#include #include "wx/afterstd.h" // by default we cache the mapping of the positions in UTF-8 string to the byte @@ -2195,17 +2197,27 @@ public: // formatted input/output // as sprintf(), returns the number of characters written or < 0 on error - // (take 'this' into account in attribute parameter count) - // int Printf(const wxString& format, ...); - WX_DEFINE_VARARG_FUNC(int, Printf, 1, (const wxFormatString&), - DoPrintfWchar, DoPrintfUtf8) + template + int Printf(const wxString& format, Targs... args) + { + // Package the arguments into a tuple to pass them on together with the + // indices that are needed by the implementation. + return DoPrintf(format, + std::make_tuple(args...), + std::index_sequence_for{}); + } + // as vprintf(), returns the number of characters written or < 0 on error int PrintfV(const wxString& format, va_list argptr); // returns the string containing the result of Printf() to it - // static wxString Format(const wxString& format, ...) WX_ATTRIBUTE_PRINTF_1; - WX_DEFINE_VARARG_FUNC(static wxString, Format, 1, (const wxFormatString&), - DoFormatWchar, DoFormatUtf8) + template + static wxString Format(const wxString& format, Targs... args) + { + wxString s; + s.Printf(format, args...); + return s; + } // the same as above, but takes a va_list static wxString FormatV(const wxString& format, va_list argptr); @@ -2228,10 +2240,11 @@ public: enum stripType {leading = 0x1, trailing = 0x2, both = 0x3}; // use Printf() - // (take 'this' into account in attribute parameter count) - // int sprintf(const wxString& format, ...) WX_ATTRIBUTE_PRINTF_2; - WX_DEFINE_VARARG_FUNC(int, sprintf, 1, (const wxFormatString&), - DoPrintfWchar, DoPrintfUtf8) + template + int sprintf(const wxString& format, Targs... args) + { + return Printf(format, args...); + } // use Cmp() int CompareTo(const wxChar* psz, caseCompare cmp = exact) const @@ -3373,13 +3386,36 @@ public: wxString& operator+=(wchar_t ch) { return *this += wxUniChar(ch); } private: + template + int DoPrintf(const wxFormatString& format, + const ArgsTuple& args, + std::index_sequence) + { +#if wxUSE_UNICODE_UTF8 + #if !wxUSE_UTF8_LOCALE_ONLY + if ( wxLocaleIsUtf8 ) + #endif + return DoPrintfUtf8 + ( + format, + wxNormalizeArgUtf8(std::get(args), &format, Ns).get()... + ); +#endif // wxUSE_UNICODE_UTF8 + +#if !wxUSE_UTF8_LOCALE_ONLY + return DoPrintfWchar + ( + format, + wxNormalizeArgWchar(std::get(args), &format, Ns).get()... + ); +#endif // !wxUSE_UTF8_LOCALE_ONLY + } + #if !wxUSE_UTF8_LOCALE_ONLY int DoPrintfWchar(const wxChar *format, ...); - static wxString DoFormatWchar(const wxChar *format, ...); #endif #if wxUSE_UNICODE_UTF8 int DoPrintfUtf8(const char *format, ...); - static wxString DoFormatUtf8(const char *format, ...); #endif private: diff --git a/include/wx/strvararg.h b/include/wx/strvararg.h index 8e319d18e0..617ce50549 100644 --- a/include/wx/strvararg.h +++ b/include/wx/strvararg.h @@ -467,6 +467,18 @@ struct wxArgNormalizerWchar : public wxArgNormalizer const wxFormatString *fmt, unsigned index) : wxArgNormalizer(value, fmt, index) {} }; + +// Helper function for creating a wxArgNormalizerWchar with type deduced +// from the type of the argument. +// +// NB: Unlike the class ctor, which uses 1-based indices, it takes 0-based +// index which makes it more convenient to use in pack expansions. +template +wxArgNormalizerWchar +wxNormalizeArgWchar(T value, const wxFormatString *fmt, unsigned indexFrom0) +{ + return wxArgNormalizerWchar(value, fmt, indexFrom0 + 1); +} #endif // !wxUSE_UTF8_LOCALE_ONLY // normalizer for passing arguments to functions working with UTF-8 encoded @@ -480,6 +492,14 @@ struct wxArgNormalizerWchar : public wxArgNormalizer : wxArgNormalizer(value, fmt, index) {} }; + // Same type-deducing helper as above, but for wxArgNormalizerUtf8 + template + wxArgNormalizerUtf8 + wxNormalizeArgUtf8(T value, const wxFormatString *fmt, unsigned indexFrom0) + { + return wxArgNormalizerUtf8(value, fmt, indexFrom0 + 1); + } + #define wxArgNormalizerNative wxArgNormalizerUtf8 #else // wxUSE_UNICODE_WCHAR #define wxArgNormalizerNative wxArgNormalizerWchar diff --git a/src/common/string.cpp b/src/common/string.cpp index b763b65f4e..0c1b2c9107 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1679,38 +1679,6 @@ wxString wxString::FromCDouble(double val, int precision) // formatted output // --------------------------------------------------------------------------- -#if !wxUSE_UTF8_LOCALE_ONLY -/* static */ -wxString wxString::DoFormatWchar(const wxChar *format, ...) -{ - va_list argptr; - va_start(argptr, format); - - wxString s; - s.PrintfV(format, argptr); - - va_end(argptr); - - return s; -} -#endif // !wxUSE_UTF8_LOCALE_ONLY - -#if wxUSE_UNICODE_UTF8 -/* static */ -wxString wxString::DoFormatUtf8(const char *format, ...) -{ - va_list argptr; - va_start(argptr, format); - - wxString s; - s.PrintfV(format, argptr); - - va_end(argptr); - - return s; -} -#endif // wxUSE_UNICODE_UTF8 - /* static */ wxString wxString::FormatV(const wxString& format, va_list argptr) {