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 0b854a3b91..be59395409 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -44,6 +44,15 @@ #include "wx/beforestd.h" #include #include + +// Check if C++17 is available +#if wxHAS_CXX17_INCLUDE() + #include + #ifdef __cpp_lib_string_view + #define wxHAS_STD_STRING_VIEW + #endif +#endif + #include "wx/afterstd.h" // by default we cache the mapping of the positions in UTF-8 string to the byte @@ -1253,9 +1262,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 +1719,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/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/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/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 62aa30721b..f3ff37f2ee 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 // wxHAS_STD_STRING_VIEW