Always use wxVector<> for dynamic arrays implementation
Dramatically simplify dynamic array macros by keeping only the implementation previously used in wxUSE_STD_CONTAINERS case and dropping the other one, as we can use the std::vector-based implementation on top of our own wxVector<>, which is available whether wxUSE_STD_CONTAINERS is 0 or 1. This allows to get rid of tons of ugly macro-based code without breaking compatibility.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "wx/defs.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/dynarray.h"
|
||||
|
||||
#if wxUSE_STD_CONTAINERS_COMPATIBLY
|
||||
#include <vector>
|
||||
@@ -49,15 +50,9 @@ wxDictionaryStringSortDescending(const wxString& s1, const wxString& s2)
|
||||
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
|
||||
#include "wx/dynarray.h"
|
||||
|
||||
typedef int (wxCMPFUNC_CONV *CMPFUNCwxString)(wxString*, wxString*);
|
||||
typedef wxString _wxArraywxBaseArrayStringBase;
|
||||
_WX_DECLARE_BASEARRAY_2(_wxArraywxBaseArrayStringBase, wxBaseArrayStringBase,
|
||||
wxArray_SortFunction<wxString>,
|
||||
class WXDLLIMPEXP_BASE);
|
||||
WX_DEFINE_USER_EXPORTED_TYPEARRAY(wxString, wxArrayStringBase,
|
||||
wxBaseArrayStringBase, WXDLLIMPEXP_BASE);
|
||||
wxARRAY_DUMMY_BASE, WXDLLIMPEXP_BASE);
|
||||
|
||||
class WXDLLIMPEXP_BASE wxArrayString : public wxArrayStringBase
|
||||
{
|
||||
@@ -86,7 +81,7 @@ public:
|
||||
};
|
||||
|
||||
_WX_DEFINE_SORTED_TYPEARRAY_2(wxString, wxSortedArrayStringBase,
|
||||
wxBaseArrayStringBase, = wxStringSortAscending,
|
||||
wxArrayStringBase, = wxStringSortAscending,
|
||||
class WXDLLIMPEXP_BASE, wxArrayString::CompareFunction);
|
||||
|
||||
class WXDLLIMPEXP_BASE wxSortedArrayString : public wxSortedArrayStringBase
|
||||
|
@@ -13,46 +13,16 @@
|
||||
|
||||
#include "wx/defs.h"
|
||||
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
#include "wx/beforestd.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "wx/afterstd.h"
|
||||
#endif
|
||||
#include "wx/vector.h"
|
||||
|
||||
/*
|
||||
This header defines the dynamic arrays and object arrays (i.e. arrays which
|
||||
own their elements). Dynamic means that the arrays grow automatically as
|
||||
needed.
|
||||
This header defines legacy dynamic arrays and object arrays (i.e. arrays
|
||||
which own their elements) classes.
|
||||
|
||||
These macros are ugly (especially if you look in the sources ;-), but they
|
||||
allow us to define "template" classes without actually using templates and so
|
||||
this works with all compilers (and may be also much faster to compile even
|
||||
with a compiler which does support templates). The arrays defined with these
|
||||
macros are type-safe.
|
||||
|
||||
Range checking is performed in debug build for both arrays and objarrays but
|
||||
not in release build - so using an invalid index will just lead to a crash
|
||||
then.
|
||||
|
||||
Note about memory usage: arrays never shrink automatically (although you may
|
||||
use Shrink() function explicitly), they only grow, so loading 10 millions in
|
||||
an array only to delete them 2 lines below might be a bad idea if the array
|
||||
object is not going to be destroyed soon. However, as it does free memory
|
||||
when destroyed, it is ok if the array is a local variable.
|
||||
Do *NOT* use them in the new code, these classes exist for compatibility
|
||||
only. Simply use standard container, e.g. std::vector<>, in your own code.
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
The initial size by which an array grows when an element is added default
|
||||
value avoids allocate one or two bytes when the array is created which is
|
||||
rather inefficient
|
||||
*/
|
||||
#define WX_ARRAY_DEFAULT_INITIAL_SIZE (16)
|
||||
|
||||
#define _WX_ERROR_REMOVE "removing inexistent element in wxArray::Remove"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -71,17 +41,9 @@ typedef int (wxCMPFUNC_CONV *CMPFUNC)(const void* pItem1, const void* pItem2);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Base class managing data having size of type 'long' (not used directly)
|
||||
//
|
||||
// NB: for efficiency this often used class has no virtual functions (hence no
|
||||
// virtual table), even dtor is *not* virtual. If used as expected it
|
||||
// won't create any problems because ARRAYs from DEFINE_ARRAY have no dtor
|
||||
// at all, so it's not too important if it's not called (this happens when
|
||||
// you cast "SomeArray *" as "BaseArray *" and then delete it)
|
||||
// Array class providing legacy dynamic arrays API on top of wxVector<>
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
|
||||
template<class T>
|
||||
class wxArray_SortFunction
|
||||
{
|
||||
@@ -108,35 +70,16 @@ private:
|
||||
CMPFUNC m_f;
|
||||
};
|
||||
|
||||
#define _WX_DECLARE_BASEARRAY(T, name, classexp) \
|
||||
_WX_DECLARE_BASEARRAY_2(T, name, wxSortedArray_SortFunction<T>, classexp)
|
||||
|
||||
// Note that "name" must be a class and not just a typedef because it can be
|
||||
// (and is) forward declared in the existing code.
|
||||
#define _WX_DECLARE_BASEARRAY_2(T, name, predicate, classexp) \
|
||||
class name : public wxBaseArray<T, predicate> \
|
||||
{ \
|
||||
typedef wxBaseArray<T, predicate> base; \
|
||||
\
|
||||
public: \
|
||||
name() : base() { } \
|
||||
explicit name(size_t n) : base(n) { } \
|
||||
name(size_t n, \
|
||||
typename std::vector<T>::const_reference v) : base(n, v) { } \
|
||||
template <class InputIterator> \
|
||||
name(InputIterator first, InputIterator last) : base(first, last) { } \
|
||||
}
|
||||
|
||||
template <typename T, typename predicate>
|
||||
class wxBaseArray : public std::vector<T>
|
||||
template <typename T>
|
||||
class wxBaseArray : public wxVector<T>
|
||||
{
|
||||
typedef predicate Predicate;
|
||||
typedef typename predicate::CMPFUNC SCMPFUNC;
|
||||
typedef wxSortedArray_SortFunction<T> Predicate;
|
||||
typedef int (wxCMPFUNC_CONV *SCMPFUNC)(T, T);
|
||||
|
||||
public:
|
||||
typedef typename wxArray_SortFunction<T>::CMPFUNC CMPFUNC;
|
||||
|
||||
typedef std::vector<T> base_vec;
|
||||
typedef wxVector<T> base_vec;
|
||||
|
||||
typedef typename base_vec::value_type value_type;
|
||||
typedef typename base_vec::reference reference;
|
||||
@@ -150,24 +93,25 @@ public:
|
||||
public:
|
||||
typedef T base_type;
|
||||
|
||||
wxBaseArray() : std::vector<T>() { }
|
||||
explicit wxBaseArray(size_t n) : std::vector<T>(n) { }
|
||||
wxBaseArray(size_t n, const_reference v) : std::vector<T>(n, v) { }
|
||||
wxBaseArray() : base_vec() { }
|
||||
explicit wxBaseArray(size_t n) : base_vec(n) { }
|
||||
wxBaseArray(size_t n, const_reference v) : base_vec(n, v) { }
|
||||
|
||||
template <class InputIterator>
|
||||
wxBaseArray(InputIterator first, InputIterator last)
|
||||
: std::vector<T>(first, last)
|
||||
: base_vec(first, last)
|
||||
{ }
|
||||
|
||||
void Empty() { this->clear(); }
|
||||
void Clear() { this->clear(); }
|
||||
void Alloc(size_t uiSize) { this->reserve(uiSize); }
|
||||
|
||||
void Shrink()
|
||||
{
|
||||
#if !wxUSE_STD_CONTAINERS || __cplusplus >= 201103L || wxCHECK_VISUALC_VERSION(10)
|
||||
this->shrink_to_fit();
|
||||
#else
|
||||
std::vector<T> tmp(*this);
|
||||
base_vec tmp(*this);
|
||||
this->swap(tmp);
|
||||
#endif
|
||||
}
|
||||
@@ -258,315 +202,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#else // if !wxUSE_STD_CONTAINERS
|
||||
|
||||
#define _WX_DECLARE_BASEARRAY(T, name, classexp) \
|
||||
classexp name \
|
||||
{ \
|
||||
typedef CMPFUNC SCMPFUNC; /* for compatibility wuth wxUSE_STD_CONTAINERS */ \
|
||||
public: \
|
||||
name(); \
|
||||
name(const name& array); \
|
||||
name& operator=(const name& src); \
|
||||
~name(); \
|
||||
\
|
||||
void Empty() { m_nCount = 0; } \
|
||||
void Clear(); \
|
||||
void Alloc(size_t n) { if ( n > m_nSize ) Realloc(n); } \
|
||||
void Shrink(); \
|
||||
\
|
||||
size_t GetCount() const { return m_nCount; } \
|
||||
void SetCount(size_t n, T defval = T()); \
|
||||
bool IsEmpty() const { return m_nCount == 0; } \
|
||||
size_t Count() const { return m_nCount; } \
|
||||
\
|
||||
typedef T base_type; \
|
||||
\
|
||||
protected: \
|
||||
T& Item(size_t uiIndex) const \
|
||||
{ wxASSERT( uiIndex < m_nCount ); return m_pItems[uiIndex]; } \
|
||||
T& operator[](size_t uiIndex) const { return Item(uiIndex); } \
|
||||
\
|
||||
int Index(T lItem, bool bFromEnd = false) const; \
|
||||
int Index(T lItem, CMPFUNC fnCompare) const; \
|
||||
size_t IndexForInsert(T lItem, CMPFUNC fnCompare) const; \
|
||||
void Add(T lItem, size_t nInsert = 1); \
|
||||
size_t Add(T lItem, CMPFUNC fnCompare); \
|
||||
void Insert(T lItem, size_t uiIndex, size_t nInsert = 1); \
|
||||
void Remove(T lItem); \
|
||||
void RemoveAt(size_t uiIndex, size_t nRemove = 1); \
|
||||
\
|
||||
void Sort(CMPFUNC fnCompare); \
|
||||
\
|
||||
/* *minimal* STL-ish interface, for derived classes */ \
|
||||
typedef T value_type; \
|
||||
typedef value_type* iterator; \
|
||||
typedef const value_type* const_iterator; \
|
||||
typedef value_type& reference; \
|
||||
typedef const value_type& const_reference; \
|
||||
typedef ptrdiff_t difference_type; \
|
||||
typedef size_t size_type; \
|
||||
\
|
||||
void assign(const_iterator first, const_iterator last); \
|
||||
void assign(size_type n, const_reference v); \
|
||||
size_type capacity() const { return m_nSize; } \
|
||||
iterator erase(iterator first, iterator last) \
|
||||
{ \
|
||||
size_type idx = first - begin(); \
|
||||
RemoveAt(idx, last - first); \
|
||||
return begin() + idx; \
|
||||
} \
|
||||
iterator erase(iterator it) { return erase(it, it + 1); } \
|
||||
void insert(iterator it, size_type n, const value_type& v) \
|
||||
{ Insert(v, it - begin(), n); } \
|
||||
iterator insert(iterator it, const value_type& v = value_type()) \
|
||||
{ \
|
||||
size_type idx = it - begin(); \
|
||||
Insert(v, idx); \
|
||||
return begin() + idx; \
|
||||
} \
|
||||
void insert(iterator it, const_iterator first, const_iterator last);\
|
||||
void pop_back() { RemoveAt(size() - 1); } \
|
||||
void push_back(const value_type& v) { Add(v); } \
|
||||
void reserve(size_type n) { Alloc(n); } \
|
||||
void resize(size_type count, value_type defval = value_type()) \
|
||||
{ \
|
||||
if ( count < m_nCount ) \
|
||||
m_nCount = count; \
|
||||
else \
|
||||
SetCount(count, defval); \
|
||||
} \
|
||||
\
|
||||
iterator begin() { return m_pItems; } \
|
||||
iterator end() { return m_pItems + m_nCount; } \
|
||||
const_iterator begin() const { return m_pItems; } \
|
||||
const_iterator end() const { return m_pItems + m_nCount; } \
|
||||
\
|
||||
void swap(name& other) \
|
||||
{ \
|
||||
wxSwap(m_nSize, other.m_nSize); \
|
||||
wxSwap(m_nCount, other.m_nCount); \
|
||||
wxSwap(m_pItems, other.m_pItems); \
|
||||
} \
|
||||
\
|
||||
/* the following functions may be made directly public because */ \
|
||||
/* they don't use the type of the elements at all */ \
|
||||
public: \
|
||||
void clear() { Clear(); } \
|
||||
bool empty() const { return IsEmpty(); } \
|
||||
size_type max_size() const { return INT_MAX; } \
|
||||
size_type size() const { return GetCount(); } \
|
||||
\
|
||||
private: \
|
||||
void Grow(size_t nIncrement = 0); \
|
||||
bool Realloc(size_t nSize); \
|
||||
\
|
||||
size_t m_nSize, \
|
||||
m_nCount; \
|
||||
\
|
||||
T *m_pItems; \
|
||||
}
|
||||
|
||||
#endif // !wxUSE_STD_CONTAINERS
|
||||
|
||||
// ============================================================================
|
||||
// The private helper macros containing the core of the array classes
|
||||
// ============================================================================
|
||||
|
||||
// Implementation notes:
|
||||
//
|
||||
// JACS: Salford C++ doesn't like 'var->operator=' syntax, as in:
|
||||
// { ((wxBaseArray *)this)->operator=((const wxBaseArray&)src);
|
||||
// so using a temporary variable instead.
|
||||
//
|
||||
// The classes need a (even trivial) ~name() to link under Mac X
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// _WX_DEFINE_TYPEARRAY: array for simple types
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
|
||||
// in STL case we don't need the entire base arrays hack as standard container
|
||||
// don't suffer from alignment/storage problems as our home-grown do
|
||||
#define _WX_DEFINE_TYPEARRAY(T, name, base, classexp) \
|
||||
_WX_DECLARE_BASEARRAY(T, name, classexp)
|
||||
|
||||
#define _WX_DEFINE_TYPEARRAY_PTR(T, name, base, classexp) \
|
||||
_WX_DEFINE_TYPEARRAY(T, name, base, classexp)
|
||||
|
||||
#else // if !wxUSE_STD_CONTAINERS
|
||||
|
||||
// common declaration used by both _WX_DEFINE_TYPEARRAY and
|
||||
// _WX_DEFINE_TYPEARRAY_PTR
|
||||
#define _WX_DEFINE_TYPEARRAY_HELPER(T, name, base, classexp, ptrop) \
|
||||
wxCOMPILE_TIME_ASSERT2(sizeof(T) <= sizeof(base::base_type), \
|
||||
TypeTooBigToBeStoredIn##base, \
|
||||
name); \
|
||||
typedef int (CMPFUNC_CONV *CMPFUNC##T)(T *pItem1, T *pItem2); \
|
||||
classexp name : public base \
|
||||
{ \
|
||||
public: \
|
||||
name() { } \
|
||||
~name() { } \
|
||||
\
|
||||
T& operator[](size_t uiIndex) const \
|
||||
{ return (T&)(base::operator[](uiIndex)); } \
|
||||
T& Item(size_t uiIndex) const \
|
||||
{ return (T&)(base::operator[](uiIndex)); } \
|
||||
T& Last() const \
|
||||
{ return (T&)(base::operator[](GetCount() - 1)); } \
|
||||
\
|
||||
int Index(T lItem, bool bFromEnd = false) const \
|
||||
{ return base::Index((base_type)lItem, bFromEnd); } \
|
||||
\
|
||||
void Add(T lItem, size_t nInsert = 1) \
|
||||
{ base::Add((base_type)lItem, nInsert); } \
|
||||
void Insert(T lItem, size_t uiIndex, size_t nInsert = 1) \
|
||||
{ base::Insert((base_type)lItem, uiIndex, nInsert) ; } \
|
||||
\
|
||||
void RemoveAt(size_t uiIndex, size_t nRemove = 1) \
|
||||
{ base::RemoveAt(uiIndex, nRemove); } \
|
||||
void Remove(T lItem) \
|
||||
{ int iIndex = Index(lItem); \
|
||||
wxCHECK_RET( iIndex != wxNOT_FOUND, _WX_ERROR_REMOVE); \
|
||||
base::RemoveAt((size_t)iIndex); } \
|
||||
\
|
||||
void Sort(CMPFUNC##T fCmp) { base::Sort((CMPFUNC)fCmp); } \
|
||||
\
|
||||
/* STL-like interface */ \
|
||||
private: \
|
||||
typedef base::iterator biterator; \
|
||||
typedef base::const_iterator bconst_iterator; \
|
||||
typedef base::value_type bvalue_type; \
|
||||
typedef base::const_reference bconst_reference; \
|
||||
public: \
|
||||
typedef T value_type; \
|
||||
typedef value_type* pointer; \
|
||||
typedef const value_type* const_pointer; \
|
||||
typedef value_type* iterator; \
|
||||
typedef const value_type* const_iterator; \
|
||||
typedef value_type& reference; \
|
||||
typedef const value_type& const_reference; \
|
||||
typedef base::difference_type difference_type; \
|
||||
typedef base::size_type size_type; \
|
||||
\
|
||||
class reverse_iterator \
|
||||
{ \
|
||||
typedef T value_type; \
|
||||
typedef value_type& reference; \
|
||||
typedef value_type* pointer; \
|
||||
typedef reverse_iterator itor; \
|
||||
friend inline itor operator+(int o, const itor& it) \
|
||||
{ return it.m_ptr - o; } \
|
||||
friend inline itor operator+(const itor& it, int o) \
|
||||
{ return it.m_ptr - o; } \
|
||||
friend inline itor operator-(const itor& it, int o) \
|
||||
{ return it.m_ptr + o; } \
|
||||
friend inline difference_type operator-(const itor& i1, \
|
||||
const itor& i2) \
|
||||
{ return i1.m_ptr - i2.m_ptr; } \
|
||||
\
|
||||
public: \
|
||||
pointer m_ptr; \
|
||||
reverse_iterator() : m_ptr(NULL) { } \
|
||||
reverse_iterator(pointer ptr) : m_ptr(ptr) { } \
|
||||
reverse_iterator(const itor& it) : m_ptr(it.m_ptr) { } \
|
||||
reference operator*() const { return *m_ptr; } \
|
||||
ptrop \
|
||||
itor& operator++() { --m_ptr; return *this; } \
|
||||
const itor operator++(int) \
|
||||
{ reverse_iterator tmp = *this; --m_ptr; return tmp; } \
|
||||
itor& operator--() { ++m_ptr; return *this; } \
|
||||
const itor operator--(int) { itor tmp = *this; ++m_ptr; return tmp; }\
|
||||
bool operator ==(const itor& it) const { return m_ptr == it.m_ptr; }\
|
||||
bool operator !=(const itor& it) const { return m_ptr != it.m_ptr; }\
|
||||
}; \
|
||||
\
|
||||
class const_reverse_iterator \
|
||||
{ \
|
||||
typedef T value_type; \
|
||||
typedef const value_type& reference; \
|
||||
typedef const value_type* pointer; \
|
||||
typedef const_reverse_iterator itor; \
|
||||
friend inline itor operator+(int o, const itor& it) \
|
||||
{ return it.m_ptr - o; } \
|
||||
friend inline itor operator+(const itor& it, int o) \
|
||||
{ return it.m_ptr - o; } \
|
||||
friend inline itor operator-(const itor& it, int o) \
|
||||
{ return it.m_ptr + o; } \
|
||||
friend inline difference_type operator-(const itor& i1, \
|
||||
const itor& i2) \
|
||||
{ return i1.m_ptr - i2.m_ptr; } \
|
||||
\
|
||||
public: \
|
||||
pointer m_ptr; \
|
||||
const_reverse_iterator() : m_ptr(NULL) { } \
|
||||
const_reverse_iterator(pointer ptr) : m_ptr(ptr) { } \
|
||||
const_reverse_iterator(const itor& it) : m_ptr(it.m_ptr) { } \
|
||||
const_reverse_iterator(const reverse_iterator& it) : m_ptr(it.m_ptr) { }\
|
||||
reference operator*() const { return *m_ptr; } \
|
||||
ptrop \
|
||||
itor& operator++() { --m_ptr; return *this; } \
|
||||
const itor operator++(int) \
|
||||
{ itor tmp = *this; --m_ptr; return tmp; } \
|
||||
itor& operator--() { ++m_ptr; return *this; } \
|
||||
const itor operator--(int) { itor tmp = *this; ++m_ptr; return tmp; }\
|
||||
bool operator ==(const itor& it) const { return m_ptr == it.m_ptr; }\
|
||||
bool operator !=(const itor& it) const { return m_ptr != it.m_ptr; }\
|
||||
}; \
|
||||
\
|
||||
name(size_type n) { assign(n, value_type()); } \
|
||||
name(size_type n, const_reference v) { assign(n, v); } \
|
||||
name(const_iterator first, const_iterator last) \
|
||||
{ assign(first, last); } \
|
||||
void assign(const_iterator first, const_iterator last) \
|
||||
{ base::assign((bconst_iterator)first, (bconst_iterator)last); } \
|
||||
void assign(size_type n, const_reference v) \
|
||||
{ base::assign(n, (bconst_reference)v); } \
|
||||
reference back() { return *(end() - 1); } \
|
||||
const_reference back() const { return *(end() - 1); } \
|
||||
iterator begin() { return (iterator)base::begin(); } \
|
||||
const_iterator begin() const { return (const_iterator)base::begin(); }\
|
||||
size_type capacity() const { return base::capacity(); } \
|
||||
iterator end() { return (iterator)base::end(); } \
|
||||
const_iterator end() const { return (const_iterator)base::end(); } \
|
||||
iterator erase(iterator first, iterator last) \
|
||||
{ return (iterator)base::erase((biterator)first, (biterator)last); }\
|
||||
iterator erase(iterator it) \
|
||||
{ return (iterator)base::erase((biterator)it); } \
|
||||
reference front() { return *begin(); } \
|
||||
const_reference front() const { return *begin(); } \
|
||||
void insert(iterator it, size_type n, const_reference v) \
|
||||
{ base::insert((biterator)it, n, (bconst_reference)v); } \
|
||||
iterator insert(iterator it, const_reference v = value_type()) \
|
||||
{ return (iterator)base::insert((biterator)it, (bconst_reference)v); }\
|
||||
void insert(iterator it, const_iterator first, const_iterator last) \
|
||||
{ base::insert((biterator)it, (bconst_iterator)first, \
|
||||
(bconst_iterator)last); } \
|
||||
void pop_back() { base::pop_back(); } \
|
||||
void push_back(const_reference v) \
|
||||
{ base::push_back((bconst_reference)v); } \
|
||||
reverse_iterator rbegin() { return reverse_iterator(end() - 1); } \
|
||||
const_reverse_iterator rbegin() const; \
|
||||
reverse_iterator rend() { return reverse_iterator(begin() - 1); } \
|
||||
const_reverse_iterator rend() const; \
|
||||
void reserve(size_type n) { base::reserve(n); } \
|
||||
void resize(size_type n, value_type v = value_type()) \
|
||||
{ base::resize(n, v); } \
|
||||
void swap(name& other) { base::swap(other); } \
|
||||
}
|
||||
|
||||
#define _WX_PTROP pointer operator->() const { return m_ptr; }
|
||||
#define _WX_PTROP_NONE
|
||||
|
||||
#define _WX_DEFINE_TYPEARRAY(T, name, base, classexp) \
|
||||
_WX_DEFINE_TYPEARRAY_HELPER(T, name, base, classexp, _WX_PTROP)
|
||||
#define _WX_DEFINE_TYPEARRAY_PTR(T, name, base, classexp) \
|
||||
_WX_DEFINE_TYPEARRAY_HELPER(T, name, base, classexp, _WX_PTROP_NONE)
|
||||
|
||||
#endif // !wxUSE_STD_CONTAINERS
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// _WX_DEFINE_SORTED_TYPEARRAY: sorted array for simple data types
|
||||
// cannot handle types with size greater than pointer because of sorting
|
||||
@@ -702,26 +341,27 @@ private: \
|
||||
#define wxARRAY_DEFAULT_EXPORT
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WX_DECLARE_BASEARRAY(T, name) declare an array class named "name" containing
|
||||
// the elements of type T
|
||||
// WX_DECLARE_BASEARRAY(T, name): now is the same as WX_DEFINE_TYPEARRAY()
|
||||
// below, only preserved for compatibility.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define wxARRAY_DUMMY_BASE
|
||||
|
||||
#define WX_DECLARE_BASEARRAY(T, name) \
|
||||
WX_DECLARE_USER_EXPORTED_BASEARRAY(T, name, wxARRAY_DEFAULT_EXPORT)
|
||||
WX_DEFINE_TYPEARRAY(T, name)
|
||||
|
||||
#define WX_DECLARE_EXPORTED_BASEARRAY(T, name) \
|
||||
WX_DECLARE_USER_EXPORTED_BASEARRAY(T, name, WXDLLIMPEXP_CORE)
|
||||
WX_DEFINE_EXPORTED_TYPEARRAY(T, name, WXDLLIMPEXP_CORE)
|
||||
|
||||
#define WX_DECLARE_USER_EXPORTED_BASEARRAY(T, name, expmode) \
|
||||
typedef T _wxArray##name; \
|
||||
_WX_DECLARE_BASEARRAY(_wxArray##name, name, class expmode)
|
||||
WX_DEFINE_TYPEARRAY_WITH_DECL(T, name, wxARRAY_DUMMY_BASE, class expmode)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WX_DEFINE_TYPEARRAY(T, name, base) define an array class named "name" deriving
|
||||
// from class "base" containing the elements of type T
|
||||
//
|
||||
// Note that the class defined has only inline function and doesn't take any
|
||||
// space at all so there is no size penalty for defining multiple array classes
|
||||
// WX_DEFINE_TYPEARRAY(T, name, base) define an array class named "name"
|
||||
// containing the elements of type T. Note that the argument "base" is unused
|
||||
// and is preserved for compatibility only. Also, macros with and without
|
||||
// "_PTR" suffix are identical, and the latter ones are also kept only for
|
||||
// compatibility.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define WX_DEFINE_TYPEARRAY(T, name, base) \
|
||||
@@ -742,13 +382,35 @@ private: \
|
||||
#define WX_DEFINE_USER_EXPORTED_TYPEARRAY_PTR(T, name, base, expdecl) \
|
||||
WX_DEFINE_TYPEARRAY_WITH_DECL_PTR(T, name, base, class expdecl)
|
||||
|
||||
// This is the only non-trivial macro, which actually defines the array class
|
||||
// with the given name containing the elements of the specified type.
|
||||
//
|
||||
// Note that "name" must be a class and not just a typedef because it can be
|
||||
// (and is) forward declared in the existing code.
|
||||
//
|
||||
// As mentioned above, "base" is unused and so is "classdecl" as this class has
|
||||
// only inline methods and so never needs to be exported from MSW DLLs.
|
||||
//
|
||||
// Note about apparently redundant wxBaseArray##name typedef: this is needed to
|
||||
// avoid clashes between T and symbols defined in wxBaseArray<> scope, e.g. if
|
||||
// we didn't do this, we would have compilation problems with arrays of type
|
||||
// "Item" (which is also the name of a method in wxBaseArray<>).
|
||||
#define WX_DEFINE_TYPEARRAY_WITH_DECL(T, name, base, classdecl) \
|
||||
typedef T _wxArray##name; \
|
||||
_WX_DEFINE_TYPEARRAY(_wxArray##name, name, base, classdecl)
|
||||
typedef wxBaseArray<T> wxBaseArrayFor##name; \
|
||||
class name : public wxBaseArrayFor##name \
|
||||
{ \
|
||||
typedef wxBaseArrayFor##name Base; \
|
||||
public: \
|
||||
name() : Base() { } \
|
||||
explicit name(size_t n) : Base(n) { } \
|
||||
name(size_t n, Base::const_reference v) : Base(n, v) { } \
|
||||
template <class InputIterator> \
|
||||
name(InputIterator first, InputIterator last) : Base(first, last) { } \
|
||||
}
|
||||
|
||||
|
||||
#define WX_DEFINE_TYPEARRAY_WITH_DECL_PTR(T, name, base, classdecl) \
|
||||
typedef T _wxArray##name; \
|
||||
_WX_DEFINE_TYPEARRAY_PTR(_wxArray##name, name, base, classdecl)
|
||||
WX_DEFINE_TYPEARRAY_WITH_DECL(T, name, base, classdecl)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// WX_DEFINE_SORTED_TYPEARRAY: this is the same as the previous macro, but it
|
||||
|
@@ -24,368 +24,7 @@
|
||||
#include "wx/intl.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // for memmove
|
||||
|
||||
#if !wxUSE_STD_CONTAINERS
|
||||
|
||||
// we cast the value to long from which we cast it to void * in IndexForInsert:
|
||||
// this can't work if the pointers are not big enough
|
||||
wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr) <= sizeof(void *),
|
||||
wxArraySizeOfPtrLessSizeOfLong ); // < 32 symbols
|
||||
|
||||
// ============================================================================
|
||||
// constants
|
||||
// ============================================================================
|
||||
|
||||
// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
|
||||
#define ARRAY_MAXSIZE_INCREMENT 4096
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxBaseArray - dynamic array of 'T's
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define _WX_DEFINE_BASEARRAY(T, name) \
|
||||
/* searches the array for an item (forward or backwards) */ \
|
||||
int name::Index(T lItem, bool bFromEnd) const \
|
||||
{ \
|
||||
if ( bFromEnd ) { \
|
||||
if ( size() > 0 ) { \
|
||||
size_t n = size(); \
|
||||
do { \
|
||||
if ( (*this)[--n] == lItem ) \
|
||||
return n; \
|
||||
} \
|
||||
while ( n != 0 ); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
for( size_t n = 0; n < size(); n++ ) { \
|
||||
if( (*this)[n] == lItem ) \
|
||||
return n; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return wxNOT_FOUND; \
|
||||
} \
|
||||
\
|
||||
/* add item assuming the array is sorted with fnCompare function */ \
|
||||
size_t name::Add(T lItem, CMPFUNC fnCompare) \
|
||||
{ \
|
||||
size_t idx = IndexForInsert(lItem, fnCompare); \
|
||||
Insert(lItem, idx); \
|
||||
return idx; \
|
||||
} \
|
||||
\
|
||||
/* ctor */ \
|
||||
name::name() \
|
||||
{ \
|
||||
m_nSize = \
|
||||
m_nCount = 0; \
|
||||
m_pItems = NULL; \
|
||||
} \
|
||||
\
|
||||
/* copy ctor */ \
|
||||
name::name(const name& src) \
|
||||
{ \
|
||||
m_nSize = /* not src.m_nSize to save memory */ \
|
||||
m_nCount = src.m_nCount; \
|
||||
\
|
||||
if ( m_nSize != 0 ) { \
|
||||
m_pItems = new T[m_nSize]; \
|
||||
/* only copy if allocation succeeded */ \
|
||||
if ( m_pItems ) { \
|
||||
memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
|
||||
} \
|
||||
else { \
|
||||
m_nSize = 0; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
m_pItems = NULL; \
|
||||
} \
|
||||
\
|
||||
/* assignment operator */ \
|
||||
name& name::operator=(const name& src) \
|
||||
{ \
|
||||
wxDELETEA(m_pItems); \
|
||||
\
|
||||
m_nSize = /* not src.m_nSize to save memory */ \
|
||||
m_nCount = src.m_nCount; \
|
||||
\
|
||||
if ( m_nSize != 0 ){ \
|
||||
m_pItems = new T[m_nSize]; \
|
||||
/* only copy if allocation succeeded */ \
|
||||
if ( m_pItems ) { \
|
||||
memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
|
||||
} \
|
||||
else { \
|
||||
m_nSize = 0; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
m_pItems = NULL; \
|
||||
\
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
/* allocate new buffer of the given size and move our data to it */ \
|
||||
bool name::Realloc(size_t nSize) \
|
||||
{ \
|
||||
T *pNew = new T[nSize]; \
|
||||
/* only grow if allocation succeeded */ \
|
||||
if ( !pNew ) \
|
||||
return false; \
|
||||
\
|
||||
m_nSize = nSize; \
|
||||
/* copy data to new location */ \
|
||||
memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
|
||||
delete [] m_pItems; \
|
||||
m_pItems = pNew; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* grow the array */ \
|
||||
void name::Grow(size_t nIncrement) \
|
||||
{ \
|
||||
/* only do it if no more place */ \
|
||||
if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \
|
||||
if( m_nSize == 0 ) { \
|
||||
/* was empty, determine initial size */ \
|
||||
size_t sz = WX_ARRAY_DEFAULT_INITIAL_SIZE; \
|
||||
if (sz < nIncrement) sz = nIncrement; \
|
||||
/* allocate some memory */ \
|
||||
m_pItems = new T[sz]; \
|
||||
/* only grow if allocation succeeded */ \
|
||||
if ( m_pItems ) { \
|
||||
m_nSize = sz; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* add at least 50% but not too much */ \
|
||||
size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \
|
||||
? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \
|
||||
if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \
|
||||
ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \
|
||||
if ( nIncrement < ndefIncrement ) \
|
||||
nIncrement = ndefIncrement; \
|
||||
Realloc(m_nSize + nIncrement); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* make sure that the array has at least count elements */ \
|
||||
void name::SetCount(size_t count, T defval) \
|
||||
{ \
|
||||
if ( m_nSize < count ) \
|
||||
{ \
|
||||
/* need to realloc memory: don't overallocate it here as if */ \
|
||||
/* SetCount() is called, it probably means that the caller */ \
|
||||
/* knows in advance how many elements there will be in the */ \
|
||||
/* array and so it won't be necessary to realloc it later */ \
|
||||
if ( !Realloc(count) ) \
|
||||
{ \
|
||||
/* out of memory -- what can we do? */ \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* add new elements if we extend the array */ \
|
||||
while ( m_nCount < count ) \
|
||||
{ \
|
||||
m_pItems[m_nCount++] = defval; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* dtor */ \
|
||||
name::~name() \
|
||||
{ \
|
||||
wxDELETEA(m_pItems); \
|
||||
} \
|
||||
\
|
||||
/* clears the list */ \
|
||||
void name::Clear() \
|
||||
{ \
|
||||
m_nSize = \
|
||||
m_nCount = 0; \
|
||||
\
|
||||
wxDELETEA(m_pItems); \
|
||||
} \
|
||||
\
|
||||
/* minimizes the memory usage by freeing unused memory */ \
|
||||
void name::Shrink() \
|
||||
{ \
|
||||
/* only do it if we have some memory to free */ \
|
||||
if( m_nCount < m_nSize ) { \
|
||||
/* allocates exactly as much memory as we need */ \
|
||||
T *pNew = new T[m_nCount]; \
|
||||
/* only shrink if allocation succeeded */ \
|
||||
if ( pNew ) { \
|
||||
/* copy data to new location */ \
|
||||
memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
|
||||
delete [] m_pItems; \
|
||||
m_pItems = pNew; \
|
||||
\
|
||||
/* update the size of the new block */ \
|
||||
m_nSize = m_nCount; \
|
||||
} \
|
||||
/* else: don't do anything, better keep old memory block! */ \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* add item at the end */ \
|
||||
void name::Add(T lItem, size_t nInsert) \
|
||||
{ \
|
||||
if (nInsert == 0) \
|
||||
return; \
|
||||
Grow(nInsert); \
|
||||
for (size_t i = 0; i < nInsert; i++) \
|
||||
m_pItems[m_nCount++] = lItem; \
|
||||
} \
|
||||
\
|
||||
/* add item at the given position */ \
|
||||
void name::Insert(T lItem, size_t nIndex, size_t nInsert) \
|
||||
{ \
|
||||
wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \
|
||||
wxCHECK_RET( m_nCount <= m_nCount + nInsert, \
|
||||
wxT("array size overflow in wxArray::Insert") ); \
|
||||
\
|
||||
if (nInsert == 0) \
|
||||
return; \
|
||||
Grow(nInsert); \
|
||||
\
|
||||
memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
|
||||
(m_nCount - nIndex)*sizeof(T)); \
|
||||
for (size_t i = 0; i < nInsert; i++) \
|
||||
m_pItems[nIndex + i] = lItem; \
|
||||
m_nCount += nInsert; \
|
||||
} \
|
||||
\
|
||||
/* search for a place to insert item into sorted array (binary search) */ \
|
||||
size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \
|
||||
{ \
|
||||
size_t i, \
|
||||
lo = 0, \
|
||||
hi = m_nCount; \
|
||||
int res; \
|
||||
\
|
||||
while ( lo < hi ) { \
|
||||
i = (lo + hi)/2; \
|
||||
\
|
||||
res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \
|
||||
(const void *)(wxUIntPtr)(m_pItems[i])); \
|
||||
if ( res < 0 ) \
|
||||
hi = i; \
|
||||
else if ( res > 0 ) \
|
||||
lo = i + 1; \
|
||||
else { \
|
||||
lo = i; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return lo; \
|
||||
} \
|
||||
\
|
||||
/* search for an item in a sorted array (binary search) */ \
|
||||
int name::Index(T lItem, CMPFUNC fnCompare) const \
|
||||
{ \
|
||||
size_t n = IndexForInsert(lItem, fnCompare); \
|
||||
\
|
||||
return (n >= m_nCount || \
|
||||
(*fnCompare)((const void *)(wxUIntPtr)lItem, \
|
||||
((const void *)(wxUIntPtr)m_pItems[n]))) \
|
||||
? wxNOT_FOUND \
|
||||
: (int)n; \
|
||||
} \
|
||||
\
|
||||
/* removes item from array (by index) */ \
|
||||
void name::RemoveAt(size_t nIndex, size_t nRemove) \
|
||||
{ \
|
||||
wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \
|
||||
wxCHECK_RET( nIndex + nRemove <= m_nCount, \
|
||||
wxT("removing too many elements in wxArray::RemoveAt") ); \
|
||||
\
|
||||
memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \
|
||||
(m_nCount - nIndex - nRemove)*sizeof(T)); \
|
||||
m_nCount -= nRemove; \
|
||||
} \
|
||||
\
|
||||
/* removes item from array (by value) */ \
|
||||
void name::Remove(T lItem) \
|
||||
{ \
|
||||
int iIndex = Index(lItem); \
|
||||
\
|
||||
wxCHECK_RET( iIndex != wxNOT_FOUND, \
|
||||
wxT("removing inexistent item in wxArray::Remove") ); \
|
||||
\
|
||||
RemoveAt((size_t)iIndex); \
|
||||
} \
|
||||
\
|
||||
/* sort array elements using passed comparaison function */ \
|
||||
void name::Sort(CMPFUNC fCmp) \
|
||||
{ \
|
||||
qsort(m_pItems, m_nCount, sizeof(T), fCmp); \
|
||||
} \
|
||||
\
|
||||
void name::assign(const_iterator first, const_iterator last) \
|
||||
{ \
|
||||
clear(); \
|
||||
reserve(last - first); \
|
||||
for(; first != last; ++first) \
|
||||
push_back(*first); \
|
||||
} \
|
||||
\
|
||||
void name::assign(size_type n, const_reference v) \
|
||||
{ \
|
||||
clear(); \
|
||||
reserve(n); \
|
||||
for( size_type i = 0; i < n; ++i ) \
|
||||
push_back(v); \
|
||||
} \
|
||||
\
|
||||
void name::insert(iterator it, const_iterator first, const_iterator last) \
|
||||
{ \
|
||||
size_t nInsert = last - first, nIndex = it - begin(); \
|
||||
if (nInsert == 0) \
|
||||
return; \
|
||||
Grow(nInsert); \
|
||||
\
|
||||
/* old iterator could have been invalidated by Grow(). */ \
|
||||
it = begin() + nIndex; \
|
||||
\
|
||||
memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
|
||||
(m_nCount - nIndex)*sizeof(T)); \
|
||||
for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \
|
||||
*it = *first; \
|
||||
m_nCount += nInsert; \
|
||||
}
|
||||
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 1684)
|
||||
#pragma warning(disable: 1572)
|
||||
#endif
|
||||
|
||||
_WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid)
|
||||
_WX_DEFINE_BASEARRAY(char, wxBaseArrayChar)
|
||||
_WX_DEFINE_BASEARRAY(short, wxBaseArrayShort)
|
||||
_WX_DEFINE_BASEARRAY(int, wxBaseArrayInt)
|
||||
_WX_DEFINE_BASEARRAY(long, wxBaseArrayLong)
|
||||
_WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT)
|
||||
_WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble)
|
||||
|
||||
#ifdef __INTELC__
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#else // wxUSE_STD_CONTAINERS
|
||||
#if wxUSE_STD_CONTAINERS
|
||||
|
||||
#include "wx/arrstr.h"
|
||||
|
||||
@@ -493,4 +132,4 @@ int wxSortedArrayString::Index(const wxString& str,
|
||||
return it - begin();
|
||||
}
|
||||
|
||||
#endif // !wxUSE_STD_CONTAINERS/wxUSE_STD_CONTAINERS
|
||||
#endif // wxUSE_STD_CONTAINERS
|
||||
|
Reference in New Issue
Block a user