From 3dfb2a5ac1c260b9259fd5fc284346d76ca4777d Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Thu, 13 Jul 2023 10:26:40 +0100 Subject: [PATCH 1/2] Add std::string_view constructors to wxString --- include/wx/string.h | 29 +++++++++++++++++++++++++++++ interface/wx/string.h | 34 ++++++++++++++++++++++++++++++++++ tests/strings/stdstrings.cpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/include/wx/string.h b/include/wx/string.h index 0b854a3b91..6b950af8d1 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -44,6 +44,17 @@ #include "wx/beforestd.h" #include #include + +// Check if C++17 is available +#ifdef __has_include + #if __has_include() + #include + #ifdef __cpp_lib_string_view + #define wxHAS_STD_STRING_VIEW + #endif + #endif +#endif + #include "wx/afterstd.h" // by default we cache the mapping of the positions in UTF-8 string to the byte @@ -1253,9 +1264,19 @@ public: { assign(str.c_str(), str.length()); } #endif +#ifdef wxHAS_STD_STRING_VIEW + wxString(std::wstring_view view) + { assign(view.data(), view.length()); } +#endif // wxHAS_STD_STRING_VIEW + #ifndef wxNO_IMPLICIT_WXSTRING_ENCODING wxString(const std::string& str) { assign(str.c_str(), str.length()); } + + #ifdef wxHAS_STD_STRING_VIEW + wxString(std::string_view view) + { assign(view.data(), view.length()); } + #endif // wxHAS_STD_STRING_VIEW #endif // wxNO_IMPLICIT_WXSTRING_ENCODING // Also always provide explicit conversions to std::[w]string in any case, @@ -1700,6 +1721,14 @@ public: const wxScopedCharBuffer utf8_str() const { return mb_str(wxMBConvUTF8()); } #endif // wxUSE_UNICODE_UTF8/wxUSE_UNICODE_WCHAR +// Conversion from std::string_view is the same for both of the two cases above +#ifdef wxHAS_STD_STRING_VIEW + static wxString FromUTF8Unchecked(std::string_view view) + { return FromUTF8Unchecked(view.data(), view.length()); } + static wxString FromUTF8(std::string_view view) + { return FromUTF8(view.data(), view.length()); } +#endif // wxHAS_STD_STRING_VIEW + const wxScopedCharBuffer ToUTF8() const { return utf8_str(); } // functions for storing binary data in wxString: diff --git a/interface/wx/string.h b/interface/wx/string.h index 48641a121a..7608c49658 100644 --- a/interface/wx/string.h +++ b/interface/wx/string.h @@ -68,10 +68,17 @@ Notice that this constructor supposes that the string contains data in the current locale encoding, use FromUTF8() if the string contains UTF-8-encoded data instead. + - Standard @c std::string_view using implicit wxString::wxString(std::string_view) + constructor. + Notice that this constructor supposes that the string contains data in + the current locale encoding, use FromUTF8() if the string contains + UTF-8-encoded data instead. - Wide @c wchar_t* string using implicit wxString::wxString(const wchar_t*) constructor. - Standard @c std::wstring using implicit wxString::wxString(const std::wstring&) constructor. + - Standard @c std::wstring_view using implicit + wxString::wxString(std::wstring_view) constructor. Notice that many of the constructors are implicit, meaning that you don't even need to write them at all to pass the existing string to some @@ -477,6 +484,16 @@ public: */ wxString(const std::string& str); + /** + Constructs a string from @a str using the using the current locale encoding + to convert it to Unicode (wxConvLibc). + + @note Requires the application to be compiled with C++17 + + @since 3.3.0 + */ + wxString(std::string_view str); + /** Constructs a string from @a str. @@ -484,6 +501,15 @@ public: */ wxString(const std::wstring& str); + /** + Constructs a string from @a str. + + @note Requires the application to be compiled with C++17 + + @since 3.3.0 + */ + wxString(std::wstring_view str); + /** String destructor. @@ -1931,11 +1957,15 @@ public: The overload taking @c std::string is only available starting with wxWidgets 3.1.1. + The overload taking @c std::string_view is only available starting with + wxWidgets 3.3.0 and requires the consumer application to use C++17. + @since 2.8.4 */ static wxString FromUTF8(const char* s); static wxString FromUTF8(const char* s, size_t len); static wxString FromUTF8(const std::string& s); + static wxString FromUTF8(std::string_view s); ///@} ///@{ @@ -1955,11 +1985,15 @@ public: The overload taking @c std::string is only available starting with wxWidgets 3.1.1. + The overload taking @c std::string_view is only available starting with + wxWidgets 3.3.0 and requires the consumer application to use C++17. + @since 2.8.9 */ static wxString FromUTF8Unchecked(const char* s); static wxString FromUTF8Unchecked(const char* s, size_t len); static wxString FromUTF8Unchecked(const std::string& s); + static wxString FromUTF8Unchecked(std::string_view s); ///@} }; diff --git a/tests/strings/stdstrings.cpp b/tests/strings/stdstrings.cpp index 62aa30721b..a87f6962ef 100644 --- a/tests/strings/stdstrings.cpp +++ b/tests/strings/stdstrings.cpp @@ -657,3 +657,38 @@ TEST_CASE("StdString::Algo", "[stdstring]") std::reverse(s.begin(), s.end()); CHECK( s == "BA" ); } + +#ifdef wxHAS_STD_STRING_VIEW +TEST_CASE("StdString::View", "[stdstring]") +{ + std::string strStd("std::string value"); + std::wstring strStdWide(L"std::wstring value"); + + std::string_view strStdView(strStd); + std::wstring_view strStdWideView(strStdWide); + + wxString s1(strStdView); + CHECK( s1 == "std::string value" ); + + wxString s2(strStdWideView); + CHECK( s2 == "std::wstring value" ); + + wxString s3; + s3 = strStdView; + CHECK( s3 == "std::string value" ); + s3 = strStdWideView; + CHECK( s3 == "std::wstring value" ); + + std::string strUTF("\xF0\x9F\x90\xB1\0\xE7\x8C\xAB", 9); /* U+1F431 U+0000 U+732B */ + std::string_view strViewUTF(strUTF); + + wxString wxstrUTF = wxString::FromUTF8(strViewUTF); + CHECK( wxstrUTF.ToStdString(wxConvUTF8) == strUTF ); + CHECK( wxstrUTF.utf8_string() == strUTF ); + + std::string strInvalidUTF("xyz\0\xFF", 5); /* an invalid UTF-8 sequence */ + std::string_view strViewInvalidUTF(strInvalidUTF); + + CHECK( "" == wxString::FromUTF8(strViewInvalidUTF) ); +} +#endif From b8d3b37c9efb0e49906bf2af6b61cf37e314db4e Mon Sep 17 00:00:00 2001 From: Ian McInerney Date: Mon, 24 Jul 2023 10:33:10 +0100 Subject: [PATCH 2/2] Add new macro for standard library header inclusion Newer standard library headers should only be included when the compiler is targetting that standard, otherwise some compilers (like MSVC) will warn that you are using a newer C++ include on an older version. --- include/wx/defs.h | 9 +++++++++ include/wx/string.h | 10 ++++------ interface/wx/defs.h | 11 +++++++++++ src/common/string.cpp | 8 +++----- tests/benchmarks/strings.cpp | 4 ++-- tests/strings/stdstrings.cpp | 2 +- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/wx/defs.h b/include/wx/defs.h index 01e30314cb..ed4ab0770e 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -205,6 +205,15 @@ #define wxCHECK_CXX_STD(ver) 0 #endif +/** + * C++ header checks + */ +#if defined(__has_include) + #define wxHAS_CXX17_INCLUDE(header) (wxCHECK_CXX_STD(201703L) && __has_include(header)) +#else + #define wxHAS_CXX17_INCLUDE(header) 0 +#endif + /* ---------------------------------------------------------------------------- */ /* check for native bool type and TRUE/FALSE constants */ /* ---------------------------------------------------------------------------- */ diff --git a/include/wx/string.h b/include/wx/string.h index 6b950af8d1..be59395409 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -46,12 +46,10 @@ #include // Check if C++17 is available -#ifdef __has_include - #if __has_include() - #include - #ifdef __cpp_lib_string_view - #define wxHAS_STD_STRING_VIEW - #endif +#if wxHAS_CXX17_INCLUDE() + #include + #ifdef __cpp_lib_string_view + #define wxHAS_STD_STRING_VIEW #endif #endif diff --git a/interface/wx/defs.h b/interface/wx/defs.h index 2e16245f3e..3cde43201a 100644 --- a/interface/wx/defs.h +++ b/interface/wx/defs.h @@ -1545,6 +1545,17 @@ typedef double wxDouble; */ #define wxCHECK_CXX_STD(stdver) +/** + Returns @true if the compiler is using the C++17 standard and the header @a header exists. + This is designed to guard inclusion of C++17 standard library headers, since MSVC will warn + if a header for a newer C++ standard is included when compiling for an older standard. + + @since 3.3.0 + + @header{wx/defs.h} +*/ +#define wxHAS_CXX17_INCLUDE(header) + /** This macro can be used in a class declaration to disable the generation of default assignment operator. diff --git a/src/common/string.cpp b/src/common/string.cpp index c2ab467f87..9f166a874d 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1569,11 +1569,9 @@ bool wxString::ToDouble(double *pVal) const // Check if C++17 is available: even though normally it should be // available in any compiler claiming C++17 support, there are actually some // compilers (e.g. gcc 7) that don't have it, so do it in this way instead: -#ifdef __has_include - #if __has_include() - // This should define __cpp_lib_to_chars checked below. - #include - #endif +#if wxHAS_CXX17_INCLUDE() + // This should define __cpp_lib_to_chars checked below. + #include #endif // Now check if the functions we need are present in it (normally they ought diff --git a/tests/benchmarks/strings.cpp b/tests/benchmarks/strings.cpp index 7c03ff7688..a3c48113bc 100644 --- a/tests/benchmarks/strings.cpp +++ b/tests/benchmarks/strings.cpp @@ -663,7 +663,7 @@ BENCHMARK_FUNC(PrintfDouble) return true; } -#if wxCHECK_CXX_STD(201703L) +#if wxHAS_CXX17_INCLUDE() #include @@ -715,4 +715,4 @@ BENCHMARK_FUNC(StdToChars) } #endif // __cpp_lib_to_chars -#endif // C++17 +#endif // wxHAS_CXX17_INCLUDE() diff --git a/tests/strings/stdstrings.cpp b/tests/strings/stdstrings.cpp index a87f6962ef..f3ff37f2ee 100644 --- a/tests/strings/stdstrings.cpp +++ b/tests/strings/stdstrings.cpp @@ -691,4 +691,4 @@ TEST_CASE("StdString::View", "[stdstring]") CHECK( "" == wxString::FromUTF8(strViewInvalidUTF) ); } -#endif +#endif // wxHAS_STD_STRING_VIEW