1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/arrstr.cpp
3 // Purpose: wxArrayString class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
13 // headers, declarations, constants
14 // ===========================================================================
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
23 #include "wx/arrstr.h"
24 #include "wx/thread.h"
26 // ============================================================================
28 // ============================================================================
30 wxArrayString::wxArrayString(size_t sz, const char** a)
35 for (size_t i=0; i < sz; i++)
39 wxArrayString::wxArrayString(size_t sz, const wchar_t** a)
44 for (size_t i=0; i < sz; i++)
48 wxArrayString::wxArrayString(size_t sz, const wxString* a)
53 for (size_t i=0; i < sz; i++)
59 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
60 #define ARRAY_MAXSIZE_INCREMENT 4096
62 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
63 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
67 void wxArrayString::Init(bool autoSort)
72 m_autoSort = autoSort;
76 wxArrayString::wxArrayString(const wxArrayString& src)
83 // assignment operator
84 wxArrayString& wxArrayString::operator=(const wxArrayString& src)
91 m_autoSort = src.m_autoSort;
96 void wxArrayString::Copy(const wxArrayString& src)
98 if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
101 for ( size_t n = 0; n < src.m_nCount; n++ )
106 void wxArrayString::Grow(size_t nIncrement)
108 // only do it if no more place
109 if ( (m_nSize - m_nCount) < nIncrement ) {
110 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
112 #if ARRAY_DEFAULT_INITIAL_SIZE == 0
113 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
116 if ( m_nSize == 0 ) {
117 // was empty, alloc some memory
118 m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
119 if (m_nSize < nIncrement)
120 m_nSize = nIncrement;
121 m_pItems = new wxString[m_nSize];
124 // otherwise when it's called for the first time, nIncrement would be 0
125 // and the array would never be expanded
126 // add 50% but not too much
127 size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
128 ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
129 if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
130 ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
131 if ( nIncrement < ndefIncrement )
132 nIncrement = ndefIncrement;
133 m_nSize += nIncrement;
134 wxString *pNew = new wxString[m_nSize];
136 // copy data to new location
137 for ( size_t j = 0; j < m_nCount; j++ )
138 pNew[j] = m_pItems[j];
140 // delete old memory (but do not release the strings!)
148 // deletes all the strings from the list
149 void wxArrayString::Empty()
154 // as Empty, but also frees memory
155 void wxArrayString::Clear()
164 wxArrayString::~wxArrayString()
169 void wxArrayString::reserve(size_t nSize)
174 // pre-allocates memory (frees the previous data!)
175 void wxArrayString::Alloc(size_t nSize)
177 // only if old buffer was not big enough
178 if ( nSize > m_nSize ) {
179 wxString *pNew = new wxString[nSize];
183 for ( size_t j = 0; j < m_nCount; j++ )
184 pNew[j] = m_pItems[j];
192 // minimizes the memory usage by freeing unused memory
193 void wxArrayString::Shrink()
195 // only do it if we have some memory to free
196 if( m_nCount < m_nSize ) {
197 // allocates exactly as much memory as we need
198 wxString *pNew = new wxString[m_nCount];
200 // copy data to new location
201 for ( size_t j = 0; j < m_nCount; j++ )
202 pNew[j] = m_pItems[j];
208 // searches the array for an item (forward or backwards)
209 int wxArrayString::Index(const wxString& str, bool bCase, bool bFromEnd) const
212 // use binary search in the sorted array
213 wxASSERT_MSG( bCase && !bFromEnd,
214 wxT("search parameters ignored for auto sorted array") );
223 res = str.compare(m_pItems[i]);
235 // use linear search in unsorted array
237 if ( m_nCount > 0 ) {
238 size_t ui = m_nCount;
240 if ( m_pItems[--ui].IsSameAs(str, bCase) )
247 for( size_t ui = 0; ui < m_nCount; ui++ ) {
248 if( m_pItems[ui].IsSameAs(str, bCase) )
257 // add item at the end
258 size_t wxArrayString::Add(const wxString& str, size_t nInsert)
261 // insert the string at the correct position to keep the array sorted
269 res = str.Cmp(m_pItems[i]);
280 wxASSERT_MSG( lo == hi, wxT("binary search broken") );
282 Insert(str, lo, nInsert);
289 for (size_t i = 0; i < nInsert; i++)
292 m_pItems[m_nCount + i] = str;
294 size_t ret = m_nCount;
300 // add item at the given position
301 void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
303 wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
304 wxCHECK_RET( m_nCount <= m_nCount + nInsert,
305 wxT("array size overflow in wxArrayString::Insert") );
309 for (int j = m_nCount - nIndex - 1; j >= 0; j--)
310 m_pItems[nIndex + nInsert + j] = m_pItems[nIndex + j];
312 for (size_t i = 0; i < nInsert; i++)
314 m_pItems[nIndex + i] = str;
319 // range insert (STL 23.2.4.3)
321 wxArrayString::insert(iterator it, const_iterator first, const_iterator last)
323 const int idx = it - begin();
328 // reset "it" since it can change inside Grow()
331 while ( first != last )
333 it = insert(it, *first);
335 // insert returns an iterator to the last element inserted but we need
336 // insert the next after this one, that is before the next one
344 void wxArrayString::SetCount(size_t count)
349 while ( m_nCount < count )
350 m_pItems[m_nCount++] = s;
353 // removes item from array (by index)
354 void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
356 wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
357 wxCHECK_RET( nIndex + nRemove <= m_nCount,
358 wxT("removing too many elements in wxArrayString::Remove") );
360 for ( size_t j = 0; j < m_nCount - nIndex -nRemove; j++)
361 m_pItems[nIndex + j] = m_pItems[nIndex + nRemove + j];
366 // removes item from array (by value)
367 void wxArrayString::Remove(const wxString& sz)
369 int iIndex = Index(sz);
371 wxCHECK_RET( iIndex != wxNOT_FOUND,
372 wxT("removing inexistent element in wxArrayString::Remove") );
377 void wxArrayString::assign(const_iterator first, const_iterator last)
379 reserve(last - first);
380 for(; first != last; ++first)
384 // ----------------------------------------------------------------------------
386 // ----------------------------------------------------------------------------
388 // we can only sort one array at a time with the quick-sort based
391 // need a critical section to protect access to gs_compareFunction and
392 // gs_sortAscending variables
393 static wxCriticalSection gs_critsectStringSort;
394 #endif // wxUSE_THREADS
396 // function to use for string comparaison
397 static wxArrayString::CompareFunction gs_compareFunction = NULL;
399 // if we don't use the compare function, this flag tells us if we sort the
400 // array in ascending or descending order
401 static bool gs_sortAscending = true;
403 // function which is called by quick sort
404 extern "C" int wxC_CALLING_CONV // LINKAGEMODE
405 wxStringCompareFunction(const void *first, const void *second)
407 wxString *strFirst = (wxString *)first;
408 wxString *strSecond = (wxString *)second;
410 if ( gs_compareFunction ) {
411 return gs_compareFunction(*strFirst, *strSecond);
414 // maybe we should use wxStrcoll
415 int result = strFirst->Cmp(*strSecond);
417 return gs_sortAscending ? result : -result;
421 // sort array elements using passed comparaison function
422 void wxArrayString::Sort(CompareFunction compareFunction)
424 wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort);
426 wxASSERT( !gs_compareFunction ); // must have been reset to NULL
427 gs_compareFunction = compareFunction;
431 // reset it to NULL so that Sort(bool) will work the next time
432 gs_compareFunction = NULL;
437 typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first,
441 void wxArrayString::Sort(CompareFunction2 compareFunction)
443 qsort(m_pItems, m_nCount, sizeof(wxString), (wxStringCompareFn)compareFunction);
446 void wxArrayString::Sort(bool reverseOrder)
448 Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending);
451 void wxArrayString::DoSort()
453 wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
455 qsort(m_pItems, m_nCount, sizeof(wxString), wxStringCompareFunction);
458 bool wxArrayString::operator==(const wxArrayString& a) const
460 if ( m_nCount != a.m_nCount )
463 for ( size_t n = 0; n < m_nCount; n++ )
465 if ( Item(n) != a[n] )
474 int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2)
479 int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2)
481 return -s1->Cmp(*s2);
486 // ===========================================================================
487 // wxJoin and wxSplit
488 // ===========================================================================
490 #include "wx/tokenzr.h"
492 wxString wxJoin(const wxArrayString& arr, const wxChar sep, const wxChar escape)
494 size_t count = arr.size();
496 return wxEmptyString;
500 // pre-allocate memory using the estimation of the average length of the
501 // strings in the given array: this is very imprecise, of course, but
502 // better than nothing
503 str.reserve(count*(arr[0].length() + arr[count-1].length()) / 2);
505 if ( escape == wxT('\0') )
507 // escaping is disabled:
508 for ( size_t i = 0; i < count; i++ )
515 else // use escape character
517 for ( size_t n = 0; n < count; n++ )
522 for ( wxString::const_iterator i = arr[n].begin(),
527 const wxChar ch = *i;
529 str += escape; // escape this separator
535 str.Shrink(); // release extra memory if we allocated too much
539 wxArrayString wxSplit(const wxString& str, const wxChar sep, const wxChar escape)
541 if ( escape == wxT('\0') )
543 // simple case: we don't need to honour the escape character
544 return wxStringTokenize(str, sep, wxTOKEN_RET_EMPTY_ALL);
549 wxChar prev = wxT('\0');
551 for ( wxString::const_iterator i = str.begin(),
556 const wxChar ch = *i;
560 if ( prev == escape )
562 // remove the escape character and don't consider this
563 // occurrence of 'sep' as a real separator
564 *curr.rbegin() = sep;
566 else // real separator
572 else // normal character
580 // add the last token
581 if ( !curr.empty() || prev == sep )