From 425d9455e8307c1267a79d47d77e3dafeb4d86de Mon Sep 17 00:00:00 2001 From: Lotendan <85304370+Lotendan@users.noreply.github.com> Date: Sat, 14 Oct 2023 20:07:49 +0200 Subject: [PATCH] Add support for initializer_list to wx dynamic arrays While these array classes are deprecated in the user code, they're still used, for compatibility, in many places in wxWidgets API and allowing to create them from initializer_list makes using it more ergonomic as it's now possible to just pass an initializer list of items to fill the control with, for example, instead of appending them one by one. This is the equivalent of 4d62df488b (Add support for initializer_list to wx dynamic arrays, 2023-03-02) from master. See #23309. Closes #23966. --- docs/changes.txt | 4 ++++ include/wx/arrstr.h | 12 ++++++++++++ include/wx/defs.h | 8 ++++++++ include/wx/dynarray.h | 18 ++++++++++++++++++ interface/wx/arrstr.h | 8 ++++++++ interface/wx/dynarray.h | 8 ++++++++ tests/arrays/arrays.cpp | 25 +++++++++++++++++++++++++ 7 files changed, 83 insertions(+) diff --git a/docs/changes.txt b/docs/changes.txt index 66ec09437c..12b1dd5253 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -235,6 +235,10 @@ Changes in behaviour which may result in build errors 3.2.4: (released 2024-??-??) ---------------------------- +All: + +- Allow creating wxArrays from std::initialized_list (Lotendan, #23966). + All (GUI): - Fix refreshing multiple selection items in generic wxListCtrl. diff --git a/include/wx/arrstr.h b/include/wx/arrstr.h index 951dd16d1b..dcc1b6b557 100644 --- a/include/wx/arrstr.h +++ b/include/wx/arrstr.h @@ -18,6 +18,9 @@ #if wxUSE_STD_CONTAINERS_COMPATIBLY #include #endif +#ifdef wxHAVE_INITIALIZER_LIST + #include +#endif // these functions are only used in STL build now but we define them in any // case for compatibility with the existing code outside of the library which @@ -83,6 +86,10 @@ public: wxArrayString(size_t sz, const char** a); wxArrayString(size_t sz, const wchar_t** a); wxArrayString(size_t sz, const wxString* a); +#ifdef wxHAVE_INITIALIZER_LIST + template + wxArrayString(std::initializer_list list) : wxArrayStringBase(list) { } +#endif int Index(const wxString& str, bool bCase = true, bool bFromEnd = false) const; @@ -184,6 +191,11 @@ public: wxArrayString(size_t sz, const wxString* a); // copy ctor wxArrayString(const wxArrayString& array); +#ifdef wxHAVE_INITIALIZER_LIST + // list constructor + template + wxArrayString(std::initializer_list list) { Init(false); assign(list.begin(), list.end()); } +#endif // assignment operator wxArrayString& operator=(const wxArrayString& src); // not virtual, this class should not be derived from diff --git a/include/wx/defs.h b/include/wx/defs.h index 885793130c..804468ca86 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -505,6 +505,14 @@ typedef short int WXTYPE; #endif #endif /* HAVE_WOSTREAM */ +#ifndef wxHAVE_INITIALIZER_LIST + #if __cplusplus >= 201103L + #define wxHAVE_INITIALIZER_LIST + #elif wxCHECK_VISUALC_VERSION(11) + #define wxHAVE_INITIALIZER_LIST + #endif +#endif /* wxHAVE_INITIALIZER_LIST */ + /* ---------------------------------------------------------------------------- */ /* portable calling conventions macros */ /* ---------------------------------------------------------------------------- */ diff --git a/include/wx/dynarray.h b/include/wx/dynarray.h index 9317776aac..07729a325a 100644 --- a/include/wx/dynarray.h +++ b/include/wx/dynarray.h @@ -15,6 +15,10 @@ #include "wx/vector.h" +#ifdef wxHAVE_INITIALIZER_LIST + #include +#endif + /* This header defines legacy dynamic arrays and object arrays (i.e. arrays which own their elements) classes. @@ -105,6 +109,11 @@ public: : base_vec(first, last) { } +#ifdef wxHAVE_INITIALIZER_LIST + template + wxBaseArray(std::initializer_list list) : base_vec(list.begin(), list.end()) {} +#endif + void Empty() { this->clear(); } void Clear() { this->clear(); } void Alloc(size_t uiSize) { this->reserve(uiSize); } @@ -495,6 +504,14 @@ private: #define WX_DEFINE_USER_EXPORTED_TYPEARRAY_PTR(T, name, base, expdecl) \ WX_DEFINE_TYPEARRAY_WITH_DECL_PTR(T, name, base, class expdecl) +#ifdef wxHAVE_INITIALIZER_LIST + #define WX_DEFINE_CTOR_FROM_INIT_LIST(T, name, base, classdecl) \ + template \ + name(std::initializer_list list) : Base(list.begin(), list.end()) { } +#else + #define WX_DEFINE_CTOR_FROM_INIT_LIST(T, name, base, classdecl) // No support for initializer_list +#endif + // This is the only non-trivial macro, which actually defines the array class // with the given name containing the elements of the specified type. // @@ -519,6 +536,7 @@ private: name(size_t n, Base::const_reference v) : Base(n, v) { } \ template \ name(InputIterator first, InputIterator last) : Base(first, last) { } \ + WX_DEFINE_CTOR_FROM_INIT_LIST(T, name, base, classdecl) \ } diff --git a/interface/wx/arrstr.h b/interface/wx/arrstr.h index ebd47a5d2b..6cb1b016db 100644 --- a/interface/wx/arrstr.h +++ b/interface/wx/arrstr.h @@ -89,6 +89,14 @@ public: */ wxArrayString(size_t sz, const wxString* arr); + /** + Constructs the container with the contents of the initializer_list @a list. + + @since 3.2.4 + */ + template + wxArrayString(std::initializer_list list); + /** Destructor frees memory occupied by the array strings. For performance reasons it is not virtual, so this class should not be derived from. diff --git a/interface/wx/dynarray.h b/interface/wx/dynarray.h index a5a8680f85..80e2ef65cd 100644 --- a/interface/wx/dynarray.h +++ b/interface/wx/dynarray.h @@ -271,6 +271,14 @@ public: */ wxObjArray(const wxObjArray& array); + /** + Constructs the container with the contents of the initializer_list @a list. + + @since 3.2.4 + */ + template + wxArray(std::initializer_list list); + /** Performs a shallow array copy (i.e.\ doesn't copy the objects pointed to even if the source array contains the items of pointer type). diff --git a/tests/arrays/arrays.cpp b/tests/arrays/arrays.cpp index 7028a5d321..096bec9c0b 100644 --- a/tests/arrays/arrays.cpp +++ b/tests/arrays/arrays.cpp @@ -340,6 +340,21 @@ TEST_CASE("wxArrayString", "[dynarray]") CHECK( a7.size() == 1 ); wxCLANG_WARNING_RESTORE(self-assign-overloaded) + +#ifdef wxHAVE_INITIALIZER_LIST + wxArrayString a8( { wxT("dog"), wxT("human"), wxT("condor"), wxT("thermit"), wxT("alligator") } ); + CHECK( a8.size() == 5 ); + CHECK( a8[1] == "human" ); + CHECK( a8[4] == "alligator" ); + + a8 = { wxT("Foo") }; // Test operator= + CHECK( a8.size() == 1 ); + CHECK( a8[0] == "Foo" ); + + // Same test with std::initializer_list + wxArrayString a9( { std::string("dog"), std::string("human"), std::string("condor"), std::string("thermit"), std::string("alligator") } ); + CHECK( a9.size() == 5 ); +#endif // wxHAVE_INITIALIZER_LIST } TEST_CASE("wxSortedArrayString", "[dynarray]") @@ -584,6 +599,14 @@ TEST_CASE("wxObjArrayPtr", "[dynarray]") CHECK( barptrs.size() == 0 ); } +#ifdef wxHAVE_INITIALIZER_LIST + #define TestArrayWithInitializerListOf(name) \ + wxArray##name c({1,2,3}); \ + CHECK(c.size() == 3); +#else + #define TestArrayWithInitializerListOf(name) // No support for initializer_list +#endif + #define TestArrayOf(name) \ \ TEST_CASE("wxDynArray::" #name, "[dynarray]") \ @@ -623,6 +646,8 @@ TEST_CASE("wxDynArray::" #name, "[dynarray]") \ CHECK( b.Index( 5 ) == 2 ); \ CHECK( b.Index( 6 ) == wxNOT_FOUND ); \ CHECK( b.Index( 17 ) == 3 ); \ + \ + TestArrayWithInitializerListOf(name) \ } TestArrayOf(UShort)