1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/dynarray.cpp 
   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 // For compilers that support precompilation, includes "wx.h". 
  17 #include  "wx/wxprec.h" 
  24     #include "wx/dynarray.h" 
  29 #include <string.h> // for memmove 
  31 #if !wxUSE_STD_CONTAINERS 
  33 // we cast the value to long from which we cast it to void * in IndexForInsert: 
  34 // this can't work if the pointers are not big enough 
  35 wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr
) <= sizeof(void *), 
  36                        wxArraySizeOfPtrLessSizeOfLong 
); // < 32 symbols 
  38 // ============================================================================ 
  40 // ============================================================================ 
  42 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
  43 #define   ARRAY_MAXSIZE_INCREMENT    4096 
  45 // ============================================================================ 
  47 // ============================================================================ 
  49 // ---------------------------------------------------------------------------- 
  50 // wxBaseArray - dynamic array of 'T's 
  51 // ---------------------------------------------------------------------------- 
  53 #define _WX_DEFINE_BASEARRAY(T, name)                                       \ 
  54 /* searches the array for an item (forward or backwards) */                 \ 
  55 int name::Index(T lItem, bool bFromEnd) const                               \ 
  61         if ( (*this)[--n] == lItem )                                        \ 
  68     for( size_t n = 0; n < size(); n++ ) {                                  \ 
  69       if( (*this)[n] == lItem )                                             \ 
  77 /* add item assuming the array is sorted with fnCompare function */         \ 
  78 size_t name::Add(T lItem, CMPFUNC fnCompare)                                \ 
  80   size_t idx = IndexForInsert(lItem, fnCompare);                            \ 
  94 name::name(const name& src)                                                 \ 
  96   m_nSize  = /* not src.m_nSize to save memory */                           \ 
  97   m_nCount = src.m_nCount;                                                  \ 
  99   if ( m_nSize != 0 ) {                                                     \ 
 100       m_pItems = new T[m_nSize];                                            \ 
 101       /* only copy if allocation succeeded */                               \ 
 103           memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T));               \ 
 113 /* assignment operator */                                                   \ 
 114 name& name::operator=(const name& src)                                      \ 
 116   wxDELETEA(m_pItems);                                                      \ 
 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));               \ 
 137 /* allocate new buffer of the given size and move our data to it */         \ 
 138 bool name::Realloc(size_t nSize)                                            \ 
 140   T *pNew = new T[nSize];                                                   \ 
 141   /* only grow if allocation succeeded */                                   \ 
 146   /* copy data to new location */                                           \ 
 147   memcpy(pNew, m_pItems, m_nCount*sizeof(T));                               \ 
 148   delete [] m_pItems;                                                       \ 
 154 /* grow the array */                                                        \ 
 155 void name::Grow(size_t nIncrement)                                          \ 
 157   /* only do it if no more place */                                         \ 
 158   if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) {      \ 
 159     if( m_nSize == 0 ) {                                                    \ 
 160       /* was empty, determine initial size */                               \ 
 161       size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE;                          \ 
 162       if (size < nIncrement) size = nIncrement;                             \ 
 163       /* allocate some memory */                                            \ 
 164       m_pItems = new T[size];                                               \ 
 165       /* only grow if allocation succeeded */                               \ 
 172       /* add at least 50% but not too much */                               \ 
 173       size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE        \ 
 174                             ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \ 
 175       if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )                        \ 
 176         ndefIncrement = ARRAY_MAXSIZE_INCREMENT;                            \ 
 177       if ( nIncrement < ndefIncrement )                                     \ 
 178         nIncrement = ndefIncrement;                                         \ 
 179       Realloc(m_nSize + nIncrement);                                        \ 
 184 /* make sure that the array has at least count elements */                  \ 
 185 void name::SetCount(size_t count, T defval)                                 \ 
 187     if ( m_nSize < count )                                                  \ 
 189         /* need to realloc memory: don't overallocate it here as if */      \ 
 190         /* SetCount() is called, it probably means that the caller  */      \ 
 191         /* knows in advance how many elements there will be in the  */      \ 
 192         /* array and so it won't be necessary to realloc it later   */      \ 
 193         if ( !Realloc(count) )                                              \ 
 195             /* out of memory -- what can we do? */                          \ 
 200     /* add new elements if we extend the array */                           \ 
 201     while ( m_nCount < count )                                              \ 
 203         m_pItems[m_nCount++] = defval;                                      \ 
 210   wxDELETEA(m_pItems);                                                      \ 
 213 /* clears the list */                                                       \ 
 219   wxDELETEA(m_pItems);                                                      \ 
 222 /* minimizes the memory usage by freeing unused memory */                   \ 
 223 void name::Shrink()                                                         \ 
 225   /* only do it if we have some memory to free */                           \ 
 226   if( m_nCount < m_nSize ) {                                                \ 
 227     /* allocates exactly as much memory as we need */                       \ 
 228     T *pNew = new T[m_nCount];                                              \ 
 229     /* only shrink if allocation succeeded */                               \ 
 231         /* copy data to new location */                                     \ 
 232         memcpy(pNew, m_pItems, m_nCount*sizeof(T));                         \ 
 233         delete [] m_pItems;                                                 \ 
 236         /* update the size of the new block */                              \ 
 237         m_nSize = m_nCount;                                                 \ 
 239     /* else: don't do anything, better keep old memory block! */            \ 
 243 /* add item at the end */                                                   \ 
 244 void name::Add(T lItem, size_t nInsert)                                     \ 
 249   for (size_t i = 0; i < nInsert; i++)                                      \ 
 250       m_pItems[m_nCount++] = lItem;                                         \ 
 253 /* add item at the given position */                                        \ 
 254 void name::Insert(T lItem, size_t nIndex, size_t nInsert)                   \ 
 256   wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") );   \ 
 257   wxCHECK_RET( m_nCount <= m_nCount + nInsert,                              \ 
 258                wxT("array size overflow in wxArray::Insert") );             \ 
 264   memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],                   \ 
 265           (m_nCount - nIndex)*sizeof(T));                                   \ 
 266   for (size_t i = 0; i < nInsert; i++)                                      \ 
 267       m_pItems[nIndex + i] = lItem;                                         \ 
 268   m_nCount += nInsert;                                                      \ 
 271 /* search for a place to insert item into sorted array (binary search) */   \ 
 272 size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const               \ 
 279   while ( lo < hi ) {                                                       \ 
 282     res = (*fnCompare)((const void *)(wxUIntPtr)lItem,                      \ 
 283                        (const void *)(wxUIntPtr)(m_pItems[i]));             \ 
 286     else if ( res > 0 )                                                     \ 
 297 /* search for an item in a sorted array (binary search) */                  \ 
 298 int name::Index(T lItem, CMPFUNC fnCompare) const                           \ 
 300     size_t n = IndexForInsert(lItem, fnCompare);                            \ 
 302     return (n >= m_nCount ||                                                \ 
 303            (*fnCompare)((const void *)(wxUIntPtr)lItem,                     \ 
 304                         ((const void *)(wxUIntPtr)m_pItems[n])))            \ 
 309 /* removes item from array (by index) */                                    \ 
 310 void name::RemoveAt(size_t nIndex, size_t nRemove)                          \ 
 312   wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") );  \ 
 313   wxCHECK_RET( nIndex + nRemove <= m_nCount,                                \ 
 314                wxT("removing too many elements in wxArray::RemoveAt") );    \ 
 316   memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],                   \ 
 317           (m_nCount - nIndex - nRemove)*sizeof(T));                         \ 
 318   m_nCount -= nRemove;                                                      \ 
 321 /* removes item from array (by value) */                                    \ 
 322 void name::Remove(T lItem)                                                  \ 
 324   int iIndex = Index(lItem);                                                \ 
 326   wxCHECK_RET( iIndex != wxNOT_FOUND,                                       \ 
 327                wxT("removing inexistent item in wxArray::Remove") );        \ 
 329   RemoveAt((size_t)iIndex);                                                 \ 
 332 /* sort array elements using passed comparaison function */                 \ 
 333 void name::Sort(CMPFUNC fCmp)                                               \ 
 335   qsort(m_pItems, m_nCount, sizeof(T), fCmp);                               \ 
 338 void name::assign(const_iterator first, const_iterator last)                \ 
 341   reserve(last - first);                                                    \ 
 342   for(; first != last; ++first)                                             \ 
 346 void name::assign(size_type n, const_reference v)                           \ 
 350   for( size_type i = 0; i < n; ++i )                                        \ 
 354 void name::insert(iterator it, const_iterator first, const_iterator last)   \ 
 356   size_t nInsert = last - first, nIndex = it - begin();                     \ 
 361   memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],                   \ 
 362           (m_nCount - nIndex)*sizeof(T));                                   \ 
 363   for (size_t i = 0; i < nInsert; ++i, ++it, ++first)                       \ 
 365   m_nCount += nInsert;                                                      \ 
 369     #pragma warning(push) 
 370     #pragma warning(disable: 1684) 
 371     #pragma warning(disable: 1572) 
 374 _WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid
) 
 375 _WX_DEFINE_BASEARRAY(char,         wxBaseArrayChar
) 
 376 _WX_DEFINE_BASEARRAY(short,        wxBaseArrayShort
) 
 377 _WX_DEFINE_BASEARRAY(int,          wxBaseArrayInt
) 
 378 _WX_DEFINE_BASEARRAY(long,         wxBaseArrayLong
) 
 379 _WX_DEFINE_BASEARRAY(size_t,       wxBaseArraySizeT
) 
 380 _WX_DEFINE_BASEARRAY(double,       wxBaseArrayDouble
) 
 386 #else // wxUSE_STD_CONTAINERS 
 388 #include "wx/arrstr.h" 
 390 #include "wx/beforestd.h" 
 391 #include <functional> 
 392 #include "wx/afterstd.h" 
 394 // some compilers (Sun CC being the only known example) distinguish between 
 395 // extern "C" functions and the functions with C++ linkage and ptr_fun and 
 396 // wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in 
 397 // this case, we need the wrappers below to make this work 
 400     typedef wxString first_argument_type
; 
 401     typedef wxString second_argument_type
; 
 402     typedef int result_type
; 
 404     int operator()(const wxString
& s1
, const wxString
& s2
) const 
 406         return s1
.compare(s2
); 
 410 struct wxStringCmpNoCase
 
 412     typedef wxString first_argument_type
; 
 413     typedef wxString second_argument_type
; 
 414     typedef int result_type
; 
 416     int operator()(const wxString
& s1
, const wxString
& s2
) const 
 418         return s1
.CmpNoCase(s2
); 
 422 int wxArrayString::Index(const wxString
& str
, bool bCase
, bool WXUNUSED(bFromEnd
)) const 
 424     wxArrayString::const_iterator it
; 
 428         it 
= std::find_if(begin(), end(), 
 431                                   wxStringCmp(), str
))); 
 435         it 
= std::find_if(begin(), end(), 
 438                                   wxStringCmpNoCase(), str
))); 
 441     return it 
== end() ? wxNOT_FOUND 
: it 
- begin(); 
 445 class wxStringCompareLess
 
 448     wxStringCompareLess(F f
) : m_f(f
) { } 
 449     bool operator()(const wxString
& s1
, const wxString
& s2
) 
 450         { return m_f(s1
, s2
) < 0; } 
 456 wxStringCompareLess
<F
> wxStringCompare(F f
) 
 458     return wxStringCompareLess
<F
>(f
); 
 461 void wxArrayString::Sort(CompareFunction function
) 
 463     std::sort(begin(), end(), wxStringCompare(function
)); 
 466 void wxArrayString::Sort(bool reverseOrder
) 
 470         std::sort(begin(), end(), std::greater
<wxString
>()); 
 474         std::sort(begin(), end()); 
 478 int wxSortedArrayString::Index(const wxString
& str
, 
 479                                bool WXUNUSED_UNLESS_DEBUG(bCase
), 
 480                                bool WXUNUSED_UNLESS_DEBUG(bFromEnd
)) const 
 482     wxASSERT_MSG( bCase 
&& !bFromEnd
, 
 483                   "search parameters ignored for sorted array" ); 
 485     wxSortedArrayString::const_iterator
 
 486         it 
= std::lower_bound(begin(), end(), str
, wxStringCompare(wxStringCmp())); 
 488     if ( it 
== end() || str
.Cmp(*it
) != 0 ) 
 494 #endif // !wxUSE_STD_CONTAINERS/wxUSE_STD_CONTAINERS