Add std::string_view constructors to wxString.

Also improve C++17 standard headers detection for MSVS.

See #23711.
This commit is contained in:
Vadim Zeitlin 2023-07-24 18:16:39 +02:00
commit f03ea82be8
7 changed files with 121 additions and 7 deletions

View file

@ -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 */
/* ---------------------------------------------------------------------------- */

View file

@ -44,6 +44,15 @@
#include "wx/beforestd.h"
#include <string>
#include <utility>
// Check if C++17 <string_view> is available
#if wxHAS_CXX17_INCLUDE(<string_view>)
#include <string_view>
#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:

View file

@ -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.

View file

@ -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);
///@}
};

View file

@ -1569,11 +1569,9 @@ bool wxString::ToDouble(double *pVal) const
// Check if C++17 <charconv> 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(<charconv>)
// This should define __cpp_lib_to_chars checked below.
#include <charconv>
#endif
#if wxHAS_CXX17_INCLUDE(<charconv>)
// This should define __cpp_lib_to_chars checked below.
#include <charconv>
#endif
// Now check if the functions we need are present in it (normally they ought

View file

@ -663,7 +663,7 @@ BENCHMARK_FUNC(PrintfDouble)
return true;
}
#if wxCHECK_CXX_STD(201703L)
#if wxHAS_CXX17_INCLUDE(<charconv>)
#include <charconv>
@ -715,4 +715,4 @@ BENCHMARK_FUNC(StdToChars)
}
#endif // __cpp_lib_to_chars
#endif // C++17
#endif // wxHAS_CXX17_INCLUDE(<charconv>)

View file

@ -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