Add wxString::AssignFromUTF8() function

This can be used to optimize repeated conversions from UTF-8 by reusing
the string buffer.

See #25740.
This commit is contained in:
Vadim Zeitlin
2025-08-30 16:33:39 +02:00
parent ae6fd7562c
commit fd0c23ee24
3 changed files with 120 additions and 0 deletions
+72
View File
@@ -1745,6 +1745,20 @@ public:
return FromImpl(std::move(utf8));
}
void AssignFromUTF8Unchecked(const char *utf8, size_t len = npos)
{
m_impl.assign(utf8, len == npos ? strlen(utf8) : len);
}
void AssignFromUTF8(const char *utf8, size_t len = npos)
{
if ( !utf8 || !wxStringOperations::IsValidUtf8String(utf8) )
{
clear();
return;
}
AssignFromUTF8Unchecked(utf8, len);
}
std::string utf8_string() const { return m_impl; }
const wxScopedCharBuffer utf8_str() const
@@ -1768,6 +1782,56 @@ public:
static wxString FromUTF8Unchecked(const std::string& utf8)
{ return FromUTF8Unchecked(utf8.c_str(), utf8.length()); }
void AssignFromUTF8Unchecked(const char *utf8, size_t len = npos)
{
if ( len == npos )
len = strlen(utf8);
wxMBConvStrictUTF8 conv;
if ( m_impl.size() > len )
{
// We can be sure that the conversion result fits into the
// existing buffer, so use it directly.
m_impl.resize(conv.ToWChar(ImplData(), m_impl.size(), utf8, len));
}
else
{
// We can't be sure that the conversion result fits into the
// existing buffer, so compute the length we need.
m_impl.resize(conv.ToWChar(nullptr, 0, utf8, len));
conv.ToWChar(ImplData(), m_impl.size(), utf8, len);
}
}
void AssignFromUTF8(const char *utf8, size_t len = npos)
{
if ( !utf8 )
{
clear();
return;
}
if ( len == npos )
len = strlen(utf8);
wxMBConvStrictUTF8 conv;
if ( m_impl.size() > len )
{
m_impl.resize(conv.ToWChar(ImplData(), m_impl.size(), utf8, len));
}
else
{
const auto needed = conv.ToWChar(nullptr, 0, utf8, len);
if ( needed == wxCONV_FAILED )
{
clear();
return;
}
m_impl.resize(needed);
conv.ToWChar(ImplData(), m_impl.size(), utf8, len);
}
}
std::string utf8_string() const { return ToStdString(wxMBConvUTF8()); }
const wxScopedCharBuffer utf8_str() const { return mb_str(wxMBConvUTF8()); }
#endif // wxUSE_UNICODE_UTF8/wxUSE_UNICODE_WCHAR
@@ -3656,6 +3720,14 @@ private:
private:
wxStringImpl m_impl;
// Get access to the string buffer: we assume that we can always rely on
// C++17 semantics of data(), even when not using C++17, which seems
// reasonable as C++17 mostly standardized existing practice.
wxStringCharType* ImplData()
{
return const_cast<wxStringCharType*>(m_impl.data());
}
// buffers for compatibility conversion from (char*)c_str() and
// (wchar_t*)c_str(): the pointers returned by these functions should remain
// valid until the string itself is modified for compatibility with the
+32
View File
@@ -527,6 +527,34 @@ public:
*/
wxString operator =(wxUniChar c);
/**
Assignment from UTF-8 string.
Calling `s.AssignFromUTF8(utf8, len) is equivalent to doing
`s = wxString::FromUTF8(utf8, len)` but may be more efficient as it can
reuse the existing string buffer instead of always having to allocate a
new one.
This function can be useful in performance-sensitive loops or with
static variables (retaining their buffer between calls) in often called
functions.
@since 3.3.2
*/
void AssignFromUTF8(const char *utf8, size_t len = npos);
/**
Assignment from UTF-8 string.
This function is the same as AssignFromUTF8() but doesn't check that
@a utf8 is a valid pointer to a valid UTF-8 string. It must not be
called if @a utf8 is @NULL or its contents is not already known to be
correct UTF-8.
@since 3.3.2
*/
void AssignFromUTF8Unchecked(const char *utf8, size_t len = npos);
///@}
@@ -2018,6 +2046,8 @@ public:
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.
@see AssignFromUTF8()
@since 2.8.4
*/
static wxString FromUTF8(const char* s);
@@ -2046,6 +2076,8 @@ public:
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.
@see AssignFromUTF8Unchecked()
@since 2.8.9
*/
static wxString FromUTF8Unchecked(const char* s);
+16
View File
@@ -192,6 +192,22 @@ TEST_CASE("StringStaticConstructors", "[wxString]")
//CHECK( wxString::FromUTF8("", 1).length() == 1 );
}
TEST_CASE("StringAssignUTF8", "[wxString]")
{
wxString s;
s.AssignFromUTF8("Oberfläche");
CHECK( s == wxString::FromUTF8("Oberfläche") );
s.AssignFromUTF8("fläche");
CHECK( s == wxString::FromUTF8("fläche") );
s.AssignFromUTF8("Even longer than Oberfläche");
CHECK( s == wxString::FromUTF8("Even longer than Oberfläche") );
s.AssignFromUTF8(nullptr);
CHECK( s == wxString() );
}
TEST_CASE("StringExtraction", "[wxString]")
{
wxString s(wxT("Hello, world!"));