1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: implementation of wxBaseArray class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 #include "wx/wxprec.h"
22 #include "wx/dynarray.h"
26 #include <string.h> // for memmove
28 // we cast the value to long from which we cast it to void * in IndexForInsert:
29 // this can't work if the pointers are not big enough
30 wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr
) <= sizeof(void *),
31 wxArraySizeOfPtrLessSizeOfLong
); // < 32 symbols
33 // ============================================================================
35 // ============================================================================
37 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
38 #define ARRAY_MAXSIZE_INCREMENT 4096
40 // ============================================================================
42 // ============================================================================
44 // ----------------------------------------------------------------------------
45 // wxBaseArray - dynamic array of 'T's
46 // ----------------------------------------------------------------------------
48 #define _WX_DEFINE_BASEARRAY_COMMON(T, name) \
49 /* searches the array for an item (forward or backwards) */ \
50 int name::Index(T lItem, bool bFromEnd) const \
56 if ( (*this)[--n] == lItem ) \
63 for( size_t n = 0; n < size(); n++ ) { \
64 if( (*this)[n] == lItem ) \
72 /* add item assuming the array is sorted with fnCompare function */ \
73 size_t name::Add(T lItem, CMPFUNC fnCompare) \
75 size_t idx = IndexForInsert(lItem, fnCompare); \
82 #define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \
83 size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \
85 Predicate p((SCMPFUNC)fnCompare); \
86 const_iterator it = std::lower_bound(begin(), end(), lItem, p); \
87 return it - begin(); \
90 int name::Index(T lItem, CMPFUNC fnCompare) const \
92 Predicate p((SCMPFUNC)fnCompare); \
93 const_iterator it = std::lower_bound(begin(), end(), lItem, p); \
94 return (it != end() && !p(lItem, *it)) ? \
95 (int)(it - begin()) : wxNOT_FOUND; \
104 #else // if !wxUSE_STL
106 #define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \
112 m_pItems = (T *)NULL; \
116 name::name(const name& src) \
118 m_nSize = /* not src.m_nSize to save memory */ \
119 m_nCount = src.m_nCount; \
121 if ( m_nSize != 0 ) { \
122 m_pItems = new T[m_nSize]; \
123 /* only copy if allocation succeeded */ \
125 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
132 m_pItems = (T *) NULL; \
135 /* assignment operator */ \
136 name& name::operator=(const name& src) \
138 wxDELETEA(m_pItems); \
140 m_nSize = /* not src.m_nSize to save memory */ \
141 m_nCount = src.m_nCount; \
143 if ( m_nSize != 0 ){ \
144 m_pItems = new T[m_nSize]; \
145 /* only copy if allocation succeeded */ \
147 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
154 m_pItems = (T *) NULL; \
159 /* allocate new buffer of the given size and move our data to it */ \
160 bool name::Realloc(size_t nSize) \
162 T *pNew = new T[nSize]; \
163 /* only grow if allocation succeeded */ \
168 /* copy data to new location */ \
169 memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
170 delete [] m_pItems; \
176 /* grow the array */ \
177 void name::Grow(size_t nIncrement) \
179 /* only do it if no more place */ \
180 if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \
181 if( m_nSize == 0 ) { \
182 /* was empty, determine initial size */ \
183 size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE; \
184 if (size < nIncrement) size = nIncrement; \
185 /* allocate some memory */ \
186 m_pItems = new T[size]; \
187 /* only grow if allocation succeeded */ \
194 /* add at least 50% but not too much */ \
195 size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \
196 ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \
197 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \
198 ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \
199 if ( nIncrement < ndefIncrement ) \
200 nIncrement = ndefIncrement; \
201 Realloc(m_nSize + nIncrement); \
206 /* make sure that the array has at least count elements */ \
207 void name::SetCount(size_t count, T defval) \
209 if ( m_nSize < count ) \
211 /* need to realloc memory: don't overallocate it here as if */ \
212 /* SetCount() is called, it probably means that the caller */ \
213 /* knows in advance how many elements there will be in the */ \
214 /* array and so it won't be necessary to realloc it later */ \
215 if ( !Realloc(count) ) \
217 /* out of memory -- what can we do? */ \
222 /* add new elements if we extend the array */ \
223 while ( m_nCount < count ) \
225 m_pItems[m_nCount++] = defval; \
232 wxDELETEA(m_pItems); \
235 /* clears the list */ \
241 wxDELETEA(m_pItems); \
244 /* pre-allocates memory (frees the previous data!) */ \
245 void name::Alloc(size_t nSize) \
247 /* only if old buffer was not big enough */ \
248 if ( nSize > m_nSize ) { \
249 wxDELETEA(m_pItems); \
251 m_pItems = new T[nSize]; \
252 /* only alloc if allocation succeeded */ \
261 /* minimizes the memory usage by freeing unused memory */ \
262 void name::Shrink() \
264 /* only do it if we have some memory to free */ \
265 if( m_nCount < m_nSize ) { \
266 /* allocates exactly as much memory as we need */ \
267 T *pNew = new T[m_nCount]; \
268 /* only shrink if allocation succeeded */ \
270 /* copy data to new location */ \
271 memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
272 delete [] m_pItems; \
275 /* update the size of the new block */ \
276 m_nSize = m_nCount; \
278 /* else: don't do anything, better keep old memory block! */ \
282 /* add item at the end */ \
283 void name::Add(T lItem, size_t nInsert) \
288 for (size_t i = 0; i < nInsert; i++) \
289 m_pItems[m_nCount++] = lItem; \
292 /* add item at the given position */ \
293 void name::Insert(T lItem, size_t nIndex, size_t nInsert) \
295 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \
296 wxCHECK_RET( m_nCount <= m_nCount + nInsert, \
297 wxT("array size overflow in wxArray::Insert") ); \
303 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
304 (m_nCount - nIndex)*sizeof(T)); \
305 for (size_t i = 0; i < nInsert; i++) \
306 m_pItems[nIndex + i] = lItem; \
307 m_nCount += nInsert; \
310 /* search for a place to insert item into sorted array (binary search) */ \
311 size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \
318 while ( lo < hi ) { \
321 res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \
322 (const void *)(wxUIntPtr)(m_pItems[i])); \
325 else if ( res > 0 ) \
336 /* search for an item in a sorted array (binary search) */ \
337 int name::Index(T lItem, CMPFUNC fnCompare) const \
339 size_t n = IndexForInsert(lItem, fnCompare); \
341 return (n >= m_nCount || \
342 (*fnCompare)((const void *)(wxUIntPtr)lItem, \
343 ((const void *)(wxUIntPtr)m_pItems[n]))) \
348 /* removes item from array (by index) */ \
349 void name::RemoveAt(size_t nIndex, size_t nRemove) \
351 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \
352 wxCHECK_RET( nIndex + nRemove <= m_nCount, \
353 wxT("removing too many elements in wxArray::RemoveAt") ); \
355 memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \
356 (m_nCount - nIndex - nRemove)*sizeof(T)); \
357 m_nCount -= nRemove; \
360 /* removes item from array (by value) */ \
361 void name::Remove(T lItem) \
363 int iIndex = Index(lItem); \
365 wxCHECK_RET( iIndex != wxNOT_FOUND, \
366 wxT("removing inexistent item in wxArray::Remove") ); \
368 RemoveAt((size_t)iIndex); \
371 /* sort array elements using passed comparaison function */ \
372 void name::Sort(CMPFUNC fCmp) \
374 qsort(m_pItems, m_nCount, sizeof(T), fCmp); \
377 void name::assign(const_iterator first, const_iterator last) \
380 reserve(last - first); \
381 for(; first != last; ++first) \
385 void name::assign(size_type n, const_reference v) \
389 for( size_type i = 0; i < n; ++i ) \
393 void name::insert(iterator it, const_iterator first, const_iterator last) \
395 size_t nInsert = last - first, nIndex = it - begin(); \
400 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
401 (m_nCount - nIndex)*sizeof(T)); \
402 for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \
404 m_nCount += nInsert; \
409 #define _WX_DEFINE_BASEARRAY(T, name) \
410 _WX_DEFINE_BASEARRAY_COMMON(T, name) \
411 _WX_DEFINE_BASEARRAY_NOCOMMON(T, name)
413 _WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid
)
414 _WX_DEFINE_BASEARRAY(short, wxBaseArrayShort
)
415 _WX_DEFINE_BASEARRAY(int, wxBaseArrayInt
)
416 _WX_DEFINE_BASEARRAY(long, wxBaseArrayLong
)
417 _WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT
)
418 _WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble
)
421 #include "wx/arrstr.h"
423 #include "wx/beforestd.h"
424 #include <functional>
425 #include "wx/afterstd.h"
427 _WX_DEFINE_BASEARRAY(wxString
, wxBaseArrayStringBase
);
429 // some compilers (Sun CC being the only known example) distinguish between
430 // extern "C" functions and the functions with C++ linkage and ptr_fun and
431 // wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in
432 // this case, we need the wrappers below to make this work
433 inline int wxStrcmpCppWrapper(const wxChar
*p
, const wxChar
*q
)
435 return wxStrcmp(p
, q
);
438 inline int wxStricmpCppWrapper(const wxChar
*p
, const wxChar
*q
)
440 return wxStricmp(p
, q
);
443 int wxArrayString::Index(const wxChar
* sz
, bool bCase
, bool WXUNUSED(bFromEnd
)) const
445 wxArrayString::const_iterator it
;
449 it
= std::find_if(begin(), end(),
452 std::ptr_fun(wxStrcmpCppWrapper
), sz
)));
456 it
= std::find_if(begin(), end(),
459 std::ptr_fun(wxStricmpCppWrapper
), sz
)));
462 return it
== end() ? wxNOT_FOUND
: it
- begin();
466 class wxStringCompareLess
469 wxStringCompareLess(F f
) : m_f(f
) { }
470 bool operator()(const wxChar
* s1
, const wxChar
* s2
)
471 { return m_f(s1
, s2
) < 0; }
472 bool operator()(const wxString
& s1
, const wxString
& s2
)
473 { return m_f(s1
, s2
) < 0; }
479 wxStringCompareLess
<F
> wxStringCompare(F f
)
481 return wxStringCompareLess
<F
>(f
);
484 void wxArrayString::Sort(CompareFunction function
)
486 std::sort(begin(), end(), wxStringCompare(function
));
489 void wxArrayString::Sort(bool reverseOrder
)
493 std::sort(begin(), end(), std::greater
<wxString
>());
497 std::sort(begin(), end());
501 int wxSortedArrayString::Index(const wxChar
* sz
, bool bCase
, bool WXUNUSED(bFromEnd
)) const
503 wxSortedArrayString::const_iterator it
;
507 it
= std::lower_bound(begin(), end(), s
,
508 wxStringCompare(wxStrcmpCppWrapper
));
510 it
= std::lower_bound(begin(), end(), s
,
511 wxStringCompare(wxStricmpCppWrapper
));
518 if (wxStrcmp(it
->c_str(), sz
) != 0)
523 if (wxStricmp(it
->c_str(), sz
) != 0)