Merge branch 'arrstr-from-vector'
Improve interoperability between wxArrayString and std::vector. See #23434, #23036.
This commit is contained in:
commit
58a7b7b31b
6 changed files with 153 additions and 70 deletions
|
|
@ -15,9 +15,6 @@
|
|||
#include "wx/string.h"
|
||||
#include "wx/dynarray.h"
|
||||
|
||||
#include <vector>
|
||||
#include <initializer_list>
|
||||
|
||||
// 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<wxString>
|
||||
{
|
||||
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<typename U>
|
||||
wxArrayString(std::initializer_list<U> list) : wxArrayStringBase(list) { }
|
||||
wxArrayString(std::initializer_list<U> list) : wxBaseArray<wxString>(list) { }
|
||||
wxArrayString(const std::vector<wxString>& vec) : wxBaseArray<wxString>(vec) { }
|
||||
wxArrayString(std::vector<wxString>&& vec) : wxBaseArray<wxString>(std::move(vec)) { }
|
||||
template<typename U>
|
||||
wxArrayString(const std::vector<U>& vec) : wxBaseArray<wxString>(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<wxString>::Sort(function); }
|
||||
|
||||
size_t Add(const wxString& string, size_t copies = 1)
|
||||
{
|
||||
wxArrayStringBase::Add(string, copies);
|
||||
wxBaseArray<wxString>::Add(string, copies);
|
||||
return size() - copies;
|
||||
}
|
||||
|
||||
const std::vector<wxString>& 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<typename U>
|
||||
wxArrayString(std::initializer_list<U> list) { Init(false); assign(list.begin(), list.end()); }
|
||||
wxArrayString(std::initializer_list<U> list) { assign(list.begin(), list.end()); }
|
||||
// ctor from a std::vector
|
||||
template<typename U>
|
||||
wxArrayString(const std::vector<U>& 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<wxArrayString*>(this)->Last(); }
|
||||
|
||||
// get all items as a vector
|
||||
std::vector<wxString> 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 <class Iterator>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -110,6 +110,9 @@ public:
|
|||
template<typename U>
|
||||
wxBaseArray(std::initializer_list<U> list) : base_vec(list.begin(), list.end()) {}
|
||||
|
||||
wxBaseArray(const std::vector<T>& vec) : base_vec(vec) { }
|
||||
wxBaseArray(std::vector<T>&& vec) : base_vec(std::move(vec)) { }
|
||||
|
||||
void Empty() { this->clear(); }
|
||||
void Clear() { this->clear(); }
|
||||
void Alloc(size_t uiSize) { this->reserve(uiSize); }
|
||||
|
|
|
|||
|
|
@ -8,42 +8,54 @@
|
|||
/**
|
||||
@class wxArrayString
|
||||
|
||||
wxArrayString is an efficient container for storing wxString objects.
|
||||
wxArrayString is a legacy class similar to std::vector<wxString>.
|
||||
|
||||
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<std::string> 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<wxString>`, 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 <tt>std::vector<wxString></tt> 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<wxString>& vec = files.AsVector();
|
||||
@endcode
|
||||
|
||||
@library{wxbase}
|
||||
@category{containers}
|
||||
|
|
@ -97,6 +109,30 @@ public:
|
|||
template<typename T>
|
||||
wxArrayString(std::initializer_list<T> 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<typename T>
|
||||
wxArrayString(const std::vector<T>& 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<typename T>
|
||||
wxArrayString(std::vector<T>&& 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<wxString>& 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<wxString> AsVector() const;
|
||||
|
||||
/**
|
||||
Clears the array contents and frees memory.
|
||||
|
||||
|
|
|
|||
|
|
@ -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<wxString> wxArrayString::AsVector() const
|
||||
{
|
||||
if ( !m_pItems )
|
||||
return {};
|
||||
|
||||
return std::vector<wxString>{m_pItems, m_pItems + m_nCount};
|
||||
}
|
||||
|
||||
void wxArrayString::Copy(const wxArrayString& src)
|
||||
{
|
||||
if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
|
||||
|
|
|
|||
|
|
@ -355,6 +355,33 @@ TEST_CASE("wxArrayString", "[dynarray]")
|
|||
CHECK( a9.size() == 5 );
|
||||
}
|
||||
|
||||
TEST_CASE("wxArrayString::Vector", "[dynarray][vector]")
|
||||
{
|
||||
SECTION("wxString")
|
||||
{
|
||||
std::vector<wxString> vec{"first", "second"};
|
||||
wxArrayString a(vec);
|
||||
REQUIRE( a.size() == 2 );
|
||||
CHECK( a[1] == "second" );
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
std::vector<std::string> vec{"third", "fourth"};
|
||||
wxArrayString a(vec);
|
||||
REQUIRE( a.size() == 2 );
|
||||
CHECK( a[1] == "fourth" );
|
||||
}
|
||||
|
||||
SECTION("AsVector")
|
||||
{
|
||||
wxArrayString a{"five", "six", "seven"};
|
||||
const std::vector<wxString>& vec = a.AsVector();
|
||||
REQUIRE( vec.size() == 3 );
|
||||
CHECK( vec.at(2) == "seven" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("wxSortedArrayString", "[dynarray]")
|
||||
{
|
||||
wxSortedArrayString a;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue