diff --git a/include/wx/arrstr.h b/include/wx/arrstr.h index 3d10040349..cb5f986b35 100644 --- a/include/wx/arrstr.h +++ b/include/wx/arrstr.h @@ -15,9 +15,6 @@ #include "wx/string.h" #include "wx/dynarray.h" -#include -#include - // 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 // could be using them @@ -68,10 +65,8 @@ inline int wxCMPFUNC_CONV wxNaturalStringSortDescending(const wxString& s1, cons #if wxUSE_STD_CONTAINERS typedef int (wxCMPFUNC_CONV *CMPFUNCwxString)(wxString*, wxString*); -WX_DEFINE_USER_EXPORTED_TYPEARRAY(wxString, wxArrayStringBase, - wxARRAY_DUMMY_BASE, WXDLLIMPEXP_BASE); -class WXDLLIMPEXP_BASE wxArrayString : public wxArrayStringBase +class WXDLLIMPEXP_BASE wxArrayString : public wxBaseArray { public: // type of function used by wxArrayString::Sort() @@ -83,19 +78,25 @@ public: wxArrayString(size_t sz, const wchar_t** a); wxArrayString(size_t sz, const wxString* a); template - wxArrayString(std::initializer_list list) : wxArrayStringBase(list) { } + wxArrayString(std::initializer_list list) : wxBaseArray(list) { } + wxArrayString(const std::vector& vec) : wxBaseArray(vec) { } + wxArrayString(std::vector&& vec) : wxBaseArray(std::move(vec)) { } + template + wxArrayString(const std::vector& vec) : wxBaseArray(vec.begin(), vec.end()) { } int Index(const wxString& str, bool bCase = true, bool bFromEnd = false) const; void Sort(bool reverseOrder = false); void Sort(CompareFunction function); - void Sort(CMPFUNCwxString function) { wxArrayStringBase::Sort(function); } + void Sort(CMPFUNCwxString function) { wxBaseArray::Sort(function); } size_t Add(const wxString& string, size_t copies = 1) { - wxArrayStringBase::Add(string, copies); + wxBaseArray::Add(string, copies); return size() - copies; } + + const std::vector& AsVector() const { return *this; } }; // Unlike all the other sorted arrays, this one uses a comparison function @@ -168,7 +169,7 @@ public: // constructors and destructor // default ctor - wxArrayString() { Init(false); } + wxArrayString() = default; // if autoSort is true, the array is always sorted (in alphabetical order) // // NB: the reason for using int and not bool is that like this we can avoid @@ -177,7 +178,11 @@ public: // wouldn't be needed if the 'explicit' keyword was supported by all // compilers, or if this was protected ctor for wxSortedArrayString, // but we're stuck with it now. - explicit wxArrayString(int autoSort) { Init(autoSort != 0); } + explicit wxArrayString(int autoSort) + { + if ( autoSort ) + m_autoSort = true; + } // C string array ctor wxArrayString(size_t sz, const char** a); wxArrayString(size_t sz, const wchar_t** a); @@ -187,7 +192,10 @@ public: wxArrayString(const wxArrayString& array); // list constructor template - wxArrayString(std::initializer_list list) { Init(false); assign(list.begin(), list.end()); } + wxArrayString(std::initializer_list list) { assign(list.begin(), list.end()); } + // ctor from a std::vector + template + wxArrayString(const std::vector& vec) { assign(vec.begin(), vec.end()); } // assignment operator wxArrayString& operator=(const wxArrayString& src); // not virtual, this class should not be derived from @@ -234,6 +242,8 @@ public: } const wxString& Last() const { return const_cast(this)->Last(); } + // get all items as a vector + std::vector AsVector() const; // item management // Search the element in the array, starting from the beginning if @@ -333,8 +343,8 @@ public: }; wxArrayString(const_iterator first, const_iterator last) - { Init(false); assign(first, last); } - wxArrayString(size_type n, const_reference v) { Init(false); assign(n, v); } + { assign(first, last); } + wxArrayString(size_type n, const_reference v) { assign(n, v); } template void assign(Iterator first, Iterator last) @@ -391,10 +401,9 @@ public: } protected: - void Init(bool autoSort); // common part of all ctors void Copy(const wxArrayString& src); // copies the contents of another array - CompareFunction m_compareFunction; // set only from wxSortedArrayString + CompareFunction m_compareFunction = nullptr; // set only from wxSortedArrayString private: // Allocate the new buffer big enough to hold m_nCount + nIncrement items and @@ -407,12 +416,12 @@ private: // the string should be inserted and if it's false return wxNOT_FOUND. size_t BinarySearch(const wxString& str, bool lowerBound) const; - size_t m_nSize, // current size of the array - m_nCount; // current number of elements + size_t m_nSize = 0, // current size of the array + m_nCount = 0; // current number of elements - wxString *m_pItems; // pointer to data + wxString *m_pItems = nullptr; // pointer to data - bool m_autoSort; // if true, keep the array always sorted + bool m_autoSort = false; // if true, keep the array always sorted }; class WXDLLIMPEXP_BASE wxSortedArrayString : public wxArrayString diff --git a/include/wx/dynarray.h b/include/wx/dynarray.h index 02cc4b2faf..226f17dc07 100644 --- a/include/wx/dynarray.h +++ b/include/wx/dynarray.h @@ -110,6 +110,9 @@ public: template wxBaseArray(std::initializer_list list) : base_vec(list.begin(), list.end()) {} + wxBaseArray(const std::vector& vec) : base_vec(vec) { } + wxBaseArray(std::vector&& vec) : base_vec(std::move(vec)) { } + void Empty() { this->clear(); } void Clear() { this->clear(); } void Alloc(size_t uiSize) { this->reserve(uiSize); } diff --git a/interface/wx/arrstr.h b/interface/wx/arrstr.h index ec7d80c7f9..a817eda4cf 100644 --- a/interface/wx/arrstr.h +++ b/interface/wx/arrstr.h @@ -8,42 +8,54 @@ /** @class wxArrayString - wxArrayString is an efficient container for storing wxString objects. + wxArrayString is a legacy class similar to std::vector. - It has the same features as all wxArray classes, i.e. it dynamically expands - when new items are added to it (so it is as easy to use as a linked list), - but the access time to the elements is constant, instead of being linear in - number of elements as in the case of linked lists. It is also very size - efficient and doesn't take more space than a C array @e wxString[] type - (wxArrayString uses its knowledge of internals of wxString class to achieve this). - - This class is used in the same way as other dynamic arrays(), except that no - ::WX_DEFINE_ARRAY declaration is needed for it. - When a string is added or inserted in the array, a copy of the string is created, - so the original string may be safely deleted (e.g. if it was a @e wxChar * - pointer the memory it was using can be freed immediately after this). - In general, there is no need to worry about string memory deallocation when using - this class - it will always free the memory it uses itself. - - The references returned by wxArrayString::Item, wxArrayString::Last or - wxArrayString::operator[] are not constant, so the array elements may - be modified in place like this: + This class shouldn't normally be used in the new code, but is still needed + when passing multiple items to various functions in wxWidgets API, notably + the constructors of various GUI control classes. Usually, even in this case + it doesn't need to be used explicitly, as wxArrayString will be implicitly + created if you use either an initializer list or a vector of strings, e.g. + you can just pass either of those instead of wxArrayString, for example @code - array.Last().MakeUpper(); + // wxListBox ctor is documented as taking wxArrayString but you can + // pass an initializer_list to it directly: + auto listbox = new wxListBox(parent, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + { "some", "items", "for", "the", "listbox" }); + + // Similarly, if you already have a vector filled with strings + // elsewhere in your program, you can just pass it instead: + std::vector countries = GetListOfCountries(); + auto choices = new wxChoice(parent, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + countries); @endcode - @note None of the methods of wxArrayString is virtual including its - destructor, so this class should not be used as a base class. + When using a wxWidgets function returning an object of this class, you can + either use it as if it were a `std::vector`, as this class has + all vector methods, or actually convert it to such vector using its + AsVector(), e.g. - Although this is not true strictly speaking, this class may be considered as - a specialization of wxArray class for the wxString member data: it is not - implemented like this, but it does have all of the wxArray functions. + @code + wxArrayString files; + wxDir::GetAllFiles("/some/path", &files); - It also has the full set of std::vector compatible - methods, including nested @c iterator and @c const_iterator classes which - should be used in the new code for forward compatibility with the future - wxWidgets versions. + // Can use the usual accessors: + if ( !files.empty() ) { + auto first = files[0]; + auto total = files.size(); + ... + } + + // Can iterate over it like over a vector, too. + for ( const wxString& file: files ) { + ... + } + + // Or can just convert it to the "real" vector: + const std::vector& vec = files.AsVector(); + @endcode @library{wxbase} @category{containers} @@ -97,6 +109,30 @@ public: template wxArrayString(std::initializer_list list); + /** + Constructs the container with the contents of the vector @a vec. + + Template parameter `T` must be convertible to wxString, i.e. it can be + wxString itself or `std::string`, `std::wstring` etc. + + @since 3.3.0 + */ + template + wxArrayString(const std::vector& vec); + + /** + Constructs the container with the contents of the vector @a vec. + + When using @ref overview_container_std, this constructor is more + efficient than the overload taking const reference to the vector. + Otherwise it is identical to the other overload, see its documentation + for more details. + + @since 3.3.0 + */ + template + wxArrayString(std::vector&& vec); + /** Destructor frees memory occupied by the array strings. For performance reasons it is not virtual, so this class should not be derived from. @@ -119,6 +155,25 @@ public: */ void Alloc(size_t nCount); + /** + Constructs a std::vector containing the same strings as this array. + + In @ref overview_container_std, this function actually returns a const + reference to this object itself, without making a copy, but in the + default/compatible build, it has to copy all the strings, making it + expensive to call for big arrays. + + Note that using it like this: + @code + const std::vector& vec = array.AsVector(); + @endcode + works in all builds as long as you don't need to modify the returned + vector and doesn't impose any extra overhead in the STL build. + + @since 3.3.0 + */ + std::vector AsVector() const; + /** Clears the array contents and frees memory. diff --git a/src/common/arrstr.cpp b/src/common/arrstr.cpp index 1c41258f53..0d9600e29e 100644 --- a/src/common/arrstr.cpp +++ b/src/common/arrstr.cpp @@ -31,25 +31,16 @@ wxArrayString::wxArrayString(size_t sz, const char** a) { -#if !wxUSE_STD_CONTAINERS - Init(false); -#endif assign(a, a + sz); } wxArrayString::wxArrayString(size_t sz, const wchar_t** a) { -#if !wxUSE_STD_CONTAINERS - Init(false); -#endif assign(a, a + sz); } wxArrayString::wxArrayString(size_t sz, const wxString* a) { -#if !wxUSE_STD_CONTAINERS - Init(false); -#endif assign(a, a + sz); } @@ -130,20 +121,11 @@ int wxSortedArrayString::Index(const wxString& str, #define ARRAY_DEFAULT_INITIAL_SIZE (16) #endif -// ctor -void wxArrayString::Init(bool autoSort) -{ - m_nSize = - m_nCount = 0; - m_pItems = nullptr; - m_compareFunction = nullptr; - m_autoSort = autoSort; -} - // copy ctor wxArrayString::wxArrayString(const wxArrayString& src) { - Init(src.m_autoSort); + if ( src.m_autoSort ) + m_autoSort = true; *this = src; } @@ -168,6 +150,14 @@ wxArrayString& wxArrayString::operator=(const wxArrayString& src) return *this; } +std::vector wxArrayString::AsVector() const +{ + if ( !m_pItems ) + return {}; + + return std::vector{m_pItems, m_pItems + m_nCount}; +} + void wxArrayString::Copy(const wxArrayString& src) { if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) diff --git a/tests/arrays/arrays.cpp b/tests/arrays/arrays.cpp index c5547b6747..c133a9245d 100644 --- a/tests/arrays/arrays.cpp +++ b/tests/arrays/arrays.cpp @@ -355,6 +355,33 @@ TEST_CASE("wxArrayString", "[dynarray]") CHECK( a9.size() == 5 ); } +TEST_CASE("wxArrayString::Vector", "[dynarray][vector]") +{ + SECTION("wxString") + { + std::vector vec{"first", "second"}; + wxArrayString a(vec); + REQUIRE( a.size() == 2 ); + CHECK( a[1] == "second" ); + } + + SECTION("string") + { + std::vector vec{"third", "fourth"}; + wxArrayString a(vec); + REQUIRE( a.size() == 2 ); + CHECK( a[1] == "fourth" ); + } + + SECTION("AsVector") + { + wxArrayString a{"five", "six", "seven"}; + const std::vector& vec = a.AsVector(); + REQUIRE( vec.size() == 3 ); + CHECK( vec.at(2) == "seven" ); + } +} + TEST_CASE("wxSortedArrayString", "[dynarray]") { wxSortedArrayString a; diff --git a/utils/ifacecheck/src/xmlparser.cpp b/utils/ifacecheck/src/xmlparser.cpp index 5f16cfb053..942c6f355a 100644 --- a/utils/ifacecheck/src/xmlparser.cpp +++ b/utils/ifacecheck/src/xmlparser.cpp @@ -79,7 +79,6 @@ void wxType::SetTypeFromString(const wxString& t) m_strType.Replace(" ,", ","); // ADHOC-FIX - m_strType.Replace("_wxArraywxArrayStringBase", "wxString"); m_strType.Replace("ExitCode", "void*"); // used in wxThread stuff m_strType = m_strType.Strip(wxString::both);