1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/dynarray.cpp
3 // Purpose: implementation of wxBaseArray class
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
23 #include "wx/dynarray.h"
28 #include <string.h> // for memmove
30 #if !wxUSE_STD_CONTAINERS
32 // we cast the value to long from which we cast it to void * in IndexForInsert:
33 // this can't work if the pointers are not big enough
34 wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr
) <= sizeof(void *),
35 wxArraySizeOfPtrLessSizeOfLong
); // < 32 symbols
37 // ============================================================================
39 // ============================================================================
41 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
42 #define ARRAY_MAXSIZE_INCREMENT 4096
44 // ============================================================================
46 // ============================================================================
48 // ----------------------------------------------------------------------------
49 // wxBaseArray - dynamic array of 'T's
50 // ----------------------------------------------------------------------------
52 #define _WX_DEFINE_BASEARRAY(T, name) \
53 /* searches the array for an item (forward or backwards) */ \
54 int name::Index(T lItem, bool bFromEnd) const \
60 if ( (*this)[--n] == lItem ) \
67 for( size_t n = 0; n < size(); n++ ) { \
68 if( (*this)[n] == lItem ) \
76 /* add item assuming the array is sorted with fnCompare function */ \
77 size_t name::Add(T lItem, CMPFUNC fnCompare) \
79 size_t idx = IndexForInsert(lItem, fnCompare); \
93 name::name(const name& src) \
95 m_nSize = /* not src.m_nSize to save memory */ \
96 m_nCount = src.m_nCount; \
98 if ( m_nSize != 0 ) { \
99 m_pItems = new T[m_nSize]; \
100 /* only copy if allocation succeeded */ \
102 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
112 /* assignment operator */ \
113 name& name::operator=(const name& src) \
115 wxDELETEA(m_pItems); \
117 m_nSize = /* not src.m_nSize to save memory */ \
118 m_nCount = src.m_nCount; \
120 if ( m_nSize != 0 ){ \
121 m_pItems = new T[m_nSize]; \
122 /* only copy if allocation succeeded */ \
124 memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \
136 /* allocate new buffer of the given size and move our data to it */ \
137 bool name::Realloc(size_t nSize) \
139 T *pNew = new T[nSize]; \
140 /* only grow if allocation succeeded */ \
145 /* copy data to new location */ \
146 memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
147 delete [] m_pItems; \
153 /* grow the array */ \
154 void name::Grow(size_t nIncrement) \
156 /* only do it if no more place */ \
157 if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \
158 if( m_nSize == 0 ) { \
159 /* was empty, determine initial size */ \
160 size_t sz = WX_ARRAY_DEFAULT_INITIAL_SIZE; \
161 if (sz < nIncrement) sz = nIncrement; \
162 /* allocate some memory */ \
163 m_pItems = new T[sz]; \
164 /* only grow if allocation succeeded */ \
171 /* add at least 50% but not too much */ \
172 size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \
173 ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \
174 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \
175 ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \
176 if ( nIncrement < ndefIncrement ) \
177 nIncrement = ndefIncrement; \
178 Realloc(m_nSize + nIncrement); \
183 /* make sure that the array has at least count elements */ \
184 void name::SetCount(size_t count, T defval) \
186 if ( m_nSize < count ) \
188 /* need to realloc memory: don't overallocate it here as if */ \
189 /* SetCount() is called, it probably means that the caller */ \
190 /* knows in advance how many elements there will be in the */ \
191 /* array and so it won't be necessary to realloc it later */ \
192 if ( !Realloc(count) ) \
194 /* out of memory -- what can we do? */ \
199 /* add new elements if we extend the array */ \
200 while ( m_nCount < count ) \
202 m_pItems[m_nCount++] = defval; \
209 wxDELETEA(m_pItems); \
212 /* clears the list */ \
218 wxDELETEA(m_pItems); \
221 /* minimizes the memory usage by freeing unused memory */ \
222 void name::Shrink() \
224 /* only do it if we have some memory to free */ \
225 if( m_nCount < m_nSize ) { \
226 /* allocates exactly as much memory as we need */ \
227 T *pNew = new T[m_nCount]; \
228 /* only shrink if allocation succeeded */ \
230 /* copy data to new location */ \
231 memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \
232 delete [] m_pItems; \
235 /* update the size of the new block */ \
236 m_nSize = m_nCount; \
238 /* else: don't do anything, better keep old memory block! */ \
242 /* add item at the end */ \
243 void name::Add(T lItem, size_t nInsert) \
248 for (size_t i = 0; i < nInsert; i++) \
249 m_pItems[m_nCount++] = lItem; \
252 /* add item at the given position */ \
253 void name::Insert(T lItem, size_t nIndex, size_t nInsert) \
255 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \
256 wxCHECK_RET( m_nCount <= m_nCount + nInsert, \
257 wxT("array size overflow in wxArray::Insert") ); \
263 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
264 (m_nCount - nIndex)*sizeof(T)); \
265 for (size_t i = 0; i < nInsert; i++) \
266 m_pItems[nIndex + i] = lItem; \
267 m_nCount += nInsert; \
270 /* search for a place to insert item into sorted array (binary search) */ \
271 size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \
278 while ( lo < hi ) { \
281 res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \
282 (const void *)(wxUIntPtr)(m_pItems[i])); \
285 else if ( res > 0 ) \
296 /* search for an item in a sorted array (binary search) */ \
297 int name::Index(T lItem, CMPFUNC fnCompare) const \
299 size_t n = IndexForInsert(lItem, fnCompare); \
301 return (n >= m_nCount || \
302 (*fnCompare)((const void *)(wxUIntPtr)lItem, \
303 ((const void *)(wxUIntPtr)m_pItems[n]))) \
308 /* removes item from array (by index) */ \
309 void name::RemoveAt(size_t nIndex, size_t nRemove) \
311 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \
312 wxCHECK_RET( nIndex + nRemove <= m_nCount, \
313 wxT("removing too many elements in wxArray::RemoveAt") ); \
315 memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \
316 (m_nCount - nIndex - nRemove)*sizeof(T)); \
317 m_nCount -= nRemove; \
320 /* removes item from array (by value) */ \
321 void name::Remove(T lItem) \
323 int iIndex = Index(lItem); \
325 wxCHECK_RET( iIndex != wxNOT_FOUND, \
326 wxT("removing inexistent item in wxArray::Remove") ); \
328 RemoveAt((size_t)iIndex); \
331 /* sort array elements using passed comparaison function */ \
332 void name::Sort(CMPFUNC fCmp) \
334 qsort(m_pItems, m_nCount, sizeof(T), fCmp); \
337 void name::assign(const_iterator first, const_iterator last) \
340 reserve(last - first); \
341 for(; first != last; ++first) \
345 void name::assign(size_type n, const_reference v) \
349 for( size_type i = 0; i < n; ++i ) \
353 void name::insert(iterator it, const_iterator first, const_iterator last) \
355 size_t nInsert = last - first, nIndex = it - begin(); \
360 /* old iterator could have been invalidated by Grow(). */ \
361 it = begin() + nIndex; \
363 memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \
364 (m_nCount - nIndex)*sizeof(T)); \
365 for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \
367 m_nCount += nInsert; \
371 #pragma warning(push)
372 #pragma warning(disable: 1684)
373 #pragma warning(disable: 1572)
376 _WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid
)
377 _WX_DEFINE_BASEARRAY(char, wxBaseArrayChar
)
378 _WX_DEFINE_BASEARRAY(short, wxBaseArrayShort
)
379 _WX_DEFINE_BASEARRAY(int, wxBaseArrayInt
)
380 _WX_DEFINE_BASEARRAY(long, wxBaseArrayLong
)
381 _WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT
)
382 _WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble
)
388 #else // wxUSE_STD_CONTAINERS
390 #include "wx/arrstr.h"
392 #include "wx/beforestd.h"
393 #include <functional>
394 #include "wx/afterstd.h"
396 // some compilers (Sun CC being the only known example) distinguish between
397 // extern "C" functions and the functions with C++ linkage and ptr_fun and
398 // wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in
399 // this case, we need the wrappers below to make this work
402 typedef wxString first_argument_type
;
403 typedef wxString second_argument_type
;
404 typedef int result_type
;
406 int operator()(const wxString
& s1
, const wxString
& s2
) const
408 return s1
.compare(s2
);
412 struct wxStringCmpNoCase
414 typedef wxString first_argument_type
;
415 typedef wxString second_argument_type
;
416 typedef int result_type
;
418 int operator()(const wxString
& s1
, const wxString
& s2
) const
420 return s1
.CmpNoCase(s2
);
424 int wxArrayString::Index(const wxString
& str
, bool bCase
, bool WXUNUSED(bFromEnd
)) const
426 wxArrayString::const_iterator it
;
430 it
= std::find_if(begin(), end(),
433 wxStringCmp(), str
)));
437 it
= std::find_if(begin(), end(),
440 wxStringCmpNoCase(), str
)));
443 return it
== end() ? wxNOT_FOUND
: it
- begin();
447 class wxStringCompareLess
450 wxStringCompareLess(F f
) : m_f(f
) { }
451 bool operator()(const wxString
& s1
, const wxString
& s2
)
452 { return m_f(s1
, s2
) < 0; }
458 wxStringCompareLess
<F
> wxStringCompare(F f
)
460 return wxStringCompareLess
<F
>(f
);
463 void wxArrayString::Sort(CompareFunction function
)
465 std::sort(begin(), end(), wxStringCompare(function
));
468 void wxArrayString::Sort(bool reverseOrder
)
472 std::sort(begin(), end(), std::greater
<wxString
>());
476 std::sort(begin(), end());
480 int wxSortedArrayString::Index(const wxString
& str
,
481 bool WXUNUSED_UNLESS_DEBUG(bCase
),
482 bool WXUNUSED_UNLESS_DEBUG(bFromEnd
)) const
484 wxASSERT_MSG( bCase
&& !bFromEnd
,
485 "search parameters ignored for sorted array" );
487 wxSortedArrayString::const_iterator
488 it
= std::lower_bound(begin(), end(), str
, wxStringCompare(wxStringCmp()));
490 if ( it
== end() || str
.Cmp(*it
) != 0 )
496 #endif // !wxUSE_STD_CONTAINERS/wxUSE_STD_CONTAINERS