Add move ctor and assignment operator to wxString
This results in noticeable speed up in wxArrayString operations, as shown by the new benchmark. See #23224.
This commit is contained in:
parent
2922fa0fa2
commit
74512dbc57
@ -235,6 +235,10 @@ Changes in behaviour which may result in build errors
|
||||
3.2.3: (released 2023-??-??)
|
||||
----------------------------
|
||||
|
||||
All:
|
||||
|
||||
- Add move ctor and assignment to wxString (Pavel Tyunin, #23224).
|
||||
|
||||
|
||||
3.2.2: (released 2023-02-08)
|
||||
----------------------------
|
||||
|
@ -304,6 +304,10 @@ typedef short int WXTYPE;
|
||||
#if __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(14)
|
||||
#define wxHAS_MEMBER_DEFAULT
|
||||
|
||||
// Rvalue references are supported since MSVS 2010, but enabling them
|
||||
// causes compilation errors on versions before 2015
|
||||
#define wxHAS_RVALUE_REF
|
||||
|
||||
#define wxHAS_NOEXCEPT
|
||||
#define wxNOEXCEPT noexcept
|
||||
#else
|
||||
|
@ -1140,12 +1140,25 @@ private:
|
||||
|
||||
static wxString FromImpl(const wxStringImpl& src)
|
||||
{ return wxString((CtorFromStringImplTag*)NULL, src); }
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString(CtorFromStringImplTag* WXUNUSED(dummy), wxStringImpl&& src) wxNOEXCEPT
|
||||
: m_impl(std::move(src)) {}
|
||||
|
||||
static wxString FromImpl(wxStringImpl&& src) wxNOEXCEPT
|
||||
{
|
||||
return wxString((CtorFromStringImplTag*)NULL, std::move(src));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if !wxUSE_STL_BASED_WXSTRING
|
||||
wxString(const wxStringImpl& src) : m_impl(src) { }
|
||||
// else: already defined as wxString(wxStdString) below
|
||||
#endif
|
||||
static wxString FromImpl(const wxStringImpl& src) { return wxString(src); }
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
static wxString FromImpl(wxStringImpl&& src) wxNOEXCEPT { return wxString(std::move(src)); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
@ -1156,6 +1169,16 @@ public:
|
||||
// copy ctor
|
||||
wxString(const wxString& stringSrc) : m_impl(stringSrc.m_impl) { }
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
// move ctor
|
||||
wxString(wxString&& stringSrc) wxNOEXCEPT : m_impl(std::move(stringSrc.m_impl))
|
||||
{
|
||||
#if wxUSE_STRING_POS_CACHE
|
||||
stringSrc.InvalidateCache();
|
||||
#endif // wxUSE_STRING_POS_CACHE
|
||||
}
|
||||
#endif
|
||||
|
||||
// string containing nRepeat copies of ch
|
||||
wxString(wxUniChar ch, size_t nRepeat = 1 )
|
||||
{ assign(nRepeat, ch); }
|
||||
@ -1243,6 +1266,10 @@ public:
|
||||
// we also need to provide this one
|
||||
wxString(const wxString& str, size_t nLength)
|
||||
{ assign(str, nLength); }
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString(wxString&& str, size_t nLength)
|
||||
{ assign(std::move(str), nLength); }
|
||||
#endif
|
||||
|
||||
|
||||
#if wxUSE_STRING_POS_CACHE
|
||||
@ -1265,6 +1292,9 @@ public:
|
||||
#if wxUSE_STD_STRING
|
||||
#if wxUSE_UNICODE_WCHAR
|
||||
wxString(const wxStdWideString& str) : m_impl(str) {}
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString(wxStdWideString&& str) wxNOEXCEPT : m_impl(std::move(str)) {}
|
||||
#endif
|
||||
#else // UTF-8 or ANSI
|
||||
wxString(const wxStdWideString& str)
|
||||
{ assign(str.c_str(), str.length()); }
|
||||
@ -1274,6 +1304,9 @@ public:
|
||||
#if !wxUSE_UNICODE // ANSI build
|
||||
// FIXME-UTF8: do this in UTF8 build #if wxUSE_UTF8_LOCALE_ONLY, too
|
||||
wxString(const std::string& str) : m_impl(str) {}
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString(std::string&& str) wxNOEXCEPT : m_impl(std::move(str)) {}
|
||||
#endif
|
||||
#else // Unicode
|
||||
wxString(const std::string& str)
|
||||
{ assign(str.c_str(), str.length()); }
|
||||
@ -1716,6 +1749,20 @@ public:
|
||||
return FromImpl(utf8);
|
||||
}
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
static wxString FromUTF8Unchecked(std::string&& utf8) wxNOEXCEPT
|
||||
{
|
||||
wxASSERT(wxStringOperations::IsValidUtf8String(utf8.c_str(), utf8.length()));
|
||||
return FromImpl(std::move(utf8));
|
||||
}
|
||||
static wxString FromUTF8(std::string&& utf8)
|
||||
{
|
||||
if (utf8.empty() || !wxStringOperations::IsValidUtf8String(utf8.c_str(), utf8.length()))
|
||||
return wxString();
|
||||
return FromImpl(std::move(utf8));
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string utf8_string() const { return m_impl; }
|
||||
#endif
|
||||
|
||||
@ -1895,6 +1942,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
// move from another wxString
|
||||
wxString& operator=(wxString&& stringSrc) wxNOEXCEPT
|
||||
{
|
||||
m_impl = std::move(stringSrc.m_impl);
|
||||
#if wxUSE_STRING_POS_CACHE
|
||||
InvalidateCache();
|
||||
stringSrc.InvalidateCache();
|
||||
#endif // wxUSE_STRING_POS_CACHE
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
wxString& operator=(const wxCStrData& cstr)
|
||||
{ return *this = cstr.AsString(); }
|
||||
// from a character
|
||||
@ -2596,6 +2657,19 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString& assign(wxString&& str) wxNOEXCEPT
|
||||
{
|
||||
#if wxUSE_STRING_POS_CACHE
|
||||
wxSTRING_SET_CACHED_LENGTH(str.length());
|
||||
str.InvalidateCache();
|
||||
#endif
|
||||
m_impl = std::move(str.m_impl);
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This is a non-standard-compliant overload taking the first "len"
|
||||
// characters of the source string.
|
||||
wxString& assign(const wxString& str, size_t len)
|
||||
@ -2617,6 +2691,14 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString& assign(wxString&& str, size_t len)
|
||||
{
|
||||
str.Truncate(len);
|
||||
return assign(std::move(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
// same as ` = str[pos..pos + n]
|
||||
wxString& assign(const wxString& str, size_t pos, size_t n)
|
||||
{
|
||||
@ -3111,7 +3193,7 @@ public:
|
||||
{ replace(first, last, first1, last1 - first1); return *this; }
|
||||
|
||||
// swap two strings
|
||||
void swap(wxString& str)
|
||||
void swap(wxString& str) wxNOEXCEPT
|
||||
{
|
||||
#if wxUSE_STRING_POS_CACHE
|
||||
// we modify not only this string but also the other one directly so we
|
||||
@ -3124,6 +3206,12 @@ public:
|
||||
m_impl.swap(str.m_impl);
|
||||
}
|
||||
|
||||
// non-member swap for ADL
|
||||
friend void swap(wxString& s1, wxString& s2) wxNOEXCEPT
|
||||
{
|
||||
s1.swap(s2);
|
||||
}
|
||||
|
||||
// find a substring
|
||||
size_t find(const wxString& str, size_t nStart = 0) const
|
||||
{ return PosFromImpl(m_impl.find(str.m_impl, PosToImpl(nStart))); }
|
||||
|
@ -1637,6 +1637,7 @@ wxString& wxString::Truncate(size_t uiLen)
|
||||
if ( uiLen < length() )
|
||||
{
|
||||
erase(begin() + uiLen, end());
|
||||
wxSTRING_SET_CACHED_LENGTH(uiLen);
|
||||
}
|
||||
//else: nothing to do, string is already short enough
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "wx/string.h"
|
||||
#include "wx/ffile.h"
|
||||
#include "wx/arrstr.h"
|
||||
|
||||
#include "bench.h"
|
||||
#include "htmlparser/htmlpars.h"
|
||||
@ -292,6 +293,74 @@ BENCHMARK_FUNC(ReplaceShorter)
|
||||
return str.Replace("xx", "y") != 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// string arrays
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
BENCHMARK_FUNC(ArrStrPushBack)
|
||||
{
|
||||
wxArrayString a;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
a.push_back(wxString(asciistr));
|
||||
a.push_back(wxString(utf8str));
|
||||
}
|
||||
return !a.empty();
|
||||
}
|
||||
|
||||
BENCHMARK_FUNC(ArrStrInsert)
|
||||
{
|
||||
wxArrayString a;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
a.insert(a.begin(), wxString(asciistr));
|
||||
a.insert(a.begin(), wxString(utf8str));
|
||||
}
|
||||
return !a.empty();
|
||||
}
|
||||
|
||||
BENCHMARK_FUNC(ArrStrSort)
|
||||
{
|
||||
wxArrayString a;
|
||||
a.reserve(100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
a.push_back(wxString(asciistr + i));
|
||||
a.Sort();
|
||||
return !a.empty();
|
||||
}
|
||||
|
||||
BENCHMARK_FUNC(VectorStrPushBack)
|
||||
{
|
||||
std::vector<wxString> v;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
v.push_back(wxString(asciistr));
|
||||
v.push_back(wxString(utf8str));
|
||||
}
|
||||
return !v.empty();
|
||||
}
|
||||
|
||||
BENCHMARK_FUNC(VectorStrInsert)
|
||||
{
|
||||
std::vector<wxString> v;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
v.insert(v.begin(), wxString(asciistr));
|
||||
v.insert(v.begin(), wxString(utf8str));
|
||||
}
|
||||
return !v.empty();
|
||||
}
|
||||
|
||||
BENCHMARK_FUNC(VectorStrSort)
|
||||
{
|
||||
std::vector<wxString> v;
|
||||
v.reserve(100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
v.push_back(wxString(asciistr + i));
|
||||
std::sort(v.begin(), v.end());
|
||||
return !v.empty();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// string case conversion
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -43,6 +43,13 @@ TEST_CASE("StdString::Constructors", "[stdstring]")
|
||||
|
||||
const wchar_t *pw = s2.c_str();
|
||||
CHECK( wxString(pw, pw + 1) == "a" );
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
wxString s9(std::move(s1));
|
||||
CHECK( s9 == wxT("abcdefgh"));
|
||||
wxString s10(std::move(s3), 8);
|
||||
CHECK( s10 == wxT("abcdefgh"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("StdString::Iterators", "[stdstring]")
|
||||
@ -118,9 +125,9 @@ TEST_CASE("StdString::Append", "[stdstring]")
|
||||
|
||||
TEST_CASE("StdString::Assign", "[stdstring]")
|
||||
{
|
||||
wxString s1, s2, s3, s4, s5, s6, s7, s8;
|
||||
wxString s1, s2, s3, s4, s5, s6, s7, s8, s9;
|
||||
|
||||
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = wxT("abc");
|
||||
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = wxT("abc");
|
||||
s1.assign(wxT("def"));
|
||||
s2.assign(wxT("defgh"), 3);
|
||||
s3.assign(wxString(wxT("abcdef")), 3, 6);
|
||||
@ -145,6 +152,85 @@ TEST_CASE("StdString::Assign", "[stdstring]")
|
||||
|
||||
s1.assign(s1, 1, 1);
|
||||
CHECK( s1 == "e" );
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
s9.assign(std::move(s2));
|
||||
CHECK(s9 == wxT("def"));
|
||||
s2 = wxT("qwerty");
|
||||
CHECK(s2 == wxT("qwerty"));
|
||||
#endif
|
||||
|
||||
// Self-assignment
|
||||
s9 = wxT("def");
|
||||
wxString& s9ref = s9;
|
||||
s9ref.assign(s9);
|
||||
CHECK(s9 == wxT("def"));
|
||||
// Self-move may change the value, but shouldn't crash
|
||||
// and reassignment should work
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
s9ref.assign(std::move(s9));
|
||||
s9 = "qwerty";
|
||||
CHECK(s9 == wxT("qwerty"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("StdString::AssignOp", "[stdstring]")
|
||||
{
|
||||
wxString s1, s2, s3, s4, s5, s6, s7, s8;
|
||||
s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = wxT("abc");
|
||||
|
||||
// operator=
|
||||
s1 = wxT("def");
|
||||
CHECK(s1 == wxT("def"));
|
||||
|
||||
s2 = s1;
|
||||
CHECK(s2 == wxT("def"));
|
||||
|
||||
const char* pc = s1.c_str();
|
||||
s3 = pc;
|
||||
CHECK(s3 == wxT("def"));
|
||||
|
||||
const wchar_t* pw = s1.c_str();
|
||||
s4 = pw;
|
||||
CHECK(s4 == wxT("def"));
|
||||
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
s5 = std::move(s1);
|
||||
CHECK(s5 == wxT("def"));
|
||||
s1 = wxT("qwerty");
|
||||
CHECK(s1 == wxT("qwerty"));
|
||||
#endif
|
||||
|
||||
// swap
|
||||
s6 = wxT("def");
|
||||
std::swap(s6, s7);
|
||||
CHECK(s6 == wxT("abc"));
|
||||
CHECK(s7 == wxT("def"));
|
||||
swap(s6, s7);
|
||||
CHECK(s6 == wxT("def"));
|
||||
CHECK(s7 == wxT("abc"));
|
||||
s6.swap(s7);
|
||||
CHECK(s6 == wxT("abc"));
|
||||
CHECK(s7 == wxT("def"));
|
||||
|
||||
// Self-assignment
|
||||
wxString& s8ref = s8;
|
||||
s8ref = s8;
|
||||
CHECK(s8 == wxT("abc"));
|
||||
// Self-move may change the value, but shouldn't crash
|
||||
// and reassignment should work
|
||||
#ifdef wxHAS_RVALUE_REF
|
||||
s8ref = std::move(s8);
|
||||
#endif
|
||||
s8 = "qwerty";
|
||||
CHECK(s8 == wxT("qwerty"));
|
||||
// Self-swap
|
||||
std::swap(s8, s8ref);
|
||||
CHECK(s8 == wxT("qwerty"));
|
||||
swap(s8, s8ref);
|
||||
CHECK(s8 == wxT("qwerty"));
|
||||
s8.swap(s8ref);
|
||||
CHECK(s8 == wxT("qwerty"));
|
||||
}
|
||||
|
||||
TEST_CASE("StdString::Compare", "[stdstring]")
|
||||
|
Loading…
Reference in New Issue
Block a user