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"
25 // ============================================================================
27 // ============================================================================
29 #include "wx/arrstr.h"
31 wxArrayString
::wxArrayString(size_t sz
, const wxChar
** a
)
36 for (size_t i
=0; i
< sz
; i
++)
40 wxArrayString
::wxArrayString(size_t sz
, const wxString
* a
)
45 for (size_t i
=0; i
< sz
; i
++)
51 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
52 #define ARRAY_MAXSIZE_INCREMENT 4096
54 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
55 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
59 void wxArrayString
::Init(bool autoSort
)
64 m_autoSort
= autoSort
;
68 wxArrayString
::wxArrayString(const wxArrayString
& src
)
75 // assignment operator
76 wxArrayString
& wxArrayString
::operator=(const wxArrayString
& src
)
83 m_autoSort
= src
.m_autoSort
;
88 void wxArrayString
::Copy(const wxArrayString
& src
)
90 if ( src
.m_nCount
> ARRAY_DEFAULT_INITIAL_SIZE
)
93 for ( size_t n
= 0; n
< src
.m_nCount
; n
++ )
98 void wxArrayString
::Grow(size_t nIncrement
)
100 // only do it if no more place
101 if ( (m_nSize
- m_nCount
) < nIncrement
) {
102 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
104 #if ARRAY_DEFAULT_INITIAL_SIZE == 0
105 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
108 if ( m_nSize
== 0 ) {
109 // was empty, alloc some memory
110 m_nSize
= ARRAY_DEFAULT_INITIAL_SIZE
;
111 if (m_nSize
< nIncrement
)
112 m_nSize
= nIncrement
;
113 m_pItems
= new wxString
[m_nSize
];
116 // otherwise when it's called for the first time, nIncrement would be 0
117 // and the array would never be expanded
118 // add 50% but not too much
119 size_t ndefIncrement
= m_nSize
< ARRAY_DEFAULT_INITIAL_SIZE
120 ? ARRAY_DEFAULT_INITIAL_SIZE
: m_nSize
>> 1;
121 if ( ndefIncrement
> ARRAY_MAXSIZE_INCREMENT
)
122 ndefIncrement
= ARRAY_MAXSIZE_INCREMENT
;
123 if ( nIncrement
< ndefIncrement
)
124 nIncrement
= ndefIncrement
;
125 m_nSize
+= nIncrement
;
126 wxString
*pNew
= new wxString
[m_nSize
];
128 // copy data to new location
129 for ( size_t j
= 0; j
< m_nCount
; j
++ )
130 pNew
[j
] = m_pItems
[j
];
132 // delete old memory (but do not release the strings!)
140 // deletes all the strings from the list
141 void wxArrayString
::Empty()
146 // as Empty, but also frees memory
147 void wxArrayString
::Clear()
156 wxArrayString
::~wxArrayString()
161 void wxArrayString
::reserve(size_t nSize
)
166 // pre-allocates memory (frees the previous data!)
167 void wxArrayString
::Alloc(size_t nSize
)
169 // only if old buffer was not big enough
170 if ( nSize
> m_nSize
) {
171 wxString
*pNew
= new wxString
[nSize
];
175 for ( size_t j
= 0; j
< m_nCount
; j
++ )
176 pNew
[j
] = m_pItems
[j
];
184 // minimizes the memory usage by freeing unused memory
185 void wxArrayString
::Shrink()
187 // only do it if we have some memory to free
188 if( m_nCount
< m_nSize
) {
189 // allocates exactly as much memory as we need
190 wxString
*pNew
= new wxString
[m_nCount
];
192 // copy data to new location
193 for ( size_t j
= 0; j
< m_nCount
; j
++ )
194 pNew
[j
] = m_pItems
[j
];
200 // searches the array for an item (forward or backwards)
201 int wxArrayString
::Index(const wxChar
*sz
, bool bCase
, bool bFromEnd
) const
204 // use binary search in the sorted array
205 wxASSERT_MSG( bCase
&& !bFromEnd
,
206 wxT("search parameters ignored for auto sorted array") );
215 res
= wxStrcmp(sz
, m_pItems
[i
]);
227 // use linear search in unsorted array
229 if ( m_nCount
> 0 ) {
230 size_t ui
= m_nCount
;
232 if ( m_pItems
[--ui
].IsSameAs(sz
, bCase
) )
239 for( size_t ui
= 0; ui
< m_nCount
; ui
++ ) {
240 if( m_pItems
[ui
].IsSameAs(sz
, bCase
) )
249 // add item at the end
250 size_t wxArrayString
::Add(const wxString
& str
, size_t nInsert
)
253 // insert the string at the correct position to keep the array sorted
261 res
= str
.Cmp(m_pItems
[i
]);
272 wxASSERT_MSG( lo
== hi
, wxT("binary search broken") );
274 Insert(str
, lo
, nInsert
);
281 for (size_t i
= 0; i
< nInsert
; i
++)
284 m_pItems
[m_nCount
+ i
] = str
;
286 size_t ret
= m_nCount
;
292 // add item at the given position
293 void wxArrayString
::Insert(const wxString
& str
, size_t nIndex
, size_t nInsert
)
295 wxCHECK_RET( nIndex
<= m_nCount
, wxT("bad index in wxArrayString::Insert") );
296 wxCHECK_RET( m_nCount
<= m_nCount
+ nInsert
,
297 wxT("array size overflow in wxArrayString::Insert") );
301 for (int j
= m_nCount
- nIndex
- 1; j
>= 0; j
--)
302 m_pItems
[nIndex
+ nInsert
+ j
] = m_pItems
[nIndex
+ j
];
304 for (size_t i
= 0; i
< nInsert
; i
++)
306 m_pItems
[nIndex
+ i
] = str
;
311 // range insert (STL 23.2.4.3)
313 wxArrayString
::insert(iterator it
, const_iterator first
, const_iterator last
)
315 const int idx
= it
- begin();
320 // reset "it" since it can change inside Grow()
323 while ( first
!= last
)
325 it
= insert(it
, *first
);
327 // insert returns an iterator to the last element inserted but we need
328 // insert the next after this one, that is before the next one
336 void wxArrayString
::SetCount(size_t count
)
341 while ( m_nCount
< count
)
342 m_pItems
[m_nCount
++] = s
;
345 // removes item from array (by index)
346 void wxArrayString
::RemoveAt(size_t nIndex
, size_t nRemove
)
348 wxCHECK_RET( nIndex
< m_nCount
, wxT("bad index in wxArrayString::Remove") );
349 wxCHECK_RET( nIndex
+ nRemove
<= m_nCount
,
350 wxT("removing too many elements in wxArrayString::Remove") );
352 for ( size_t j
= 0; j
< m_nCount
- nIndex
-nRemove
; j
++)
353 m_pItems
[nIndex
+ j
] = m_pItems
[nIndex
+ nRemove
+ j
];
358 // removes item from array (by value)
359 void wxArrayString
::Remove(const wxChar
*sz
)
361 int iIndex
= Index(sz
);
363 wxCHECK_RET( iIndex
!= wxNOT_FOUND
,
364 wxT("removing inexistent element in wxArrayString::Remove") );
369 void wxArrayString
::assign(const_iterator first
, const_iterator last
)
371 reserve(last
- first
);
372 for(; first
!= last
; ++first
)
376 // ----------------------------------------------------------------------------
378 // ----------------------------------------------------------------------------
380 // we can only sort one array at a time with the quick-sort based
383 // need a critical section to protect access to gs_compareFunction and
384 // gs_sortAscending variables
385 static wxCriticalSection gs_critsectStringSort
;
386 #endif // wxUSE_THREADS
388 // function to use for string comparaison
389 static wxArrayString
::CompareFunction gs_compareFunction
= NULL
;
391 // if we don't use the compare function, this flag tells us if we sort the
392 // array in ascending or descending order
393 static bool gs_sortAscending
= true;
395 // function which is called by quick sort
396 extern "C" int wxC_CALLING_CONV
// LINKAGEMODE
397 wxStringCompareFunction(const void *first
, const void *second
)
399 wxString
*strFirst
= (wxString
*)first
;
400 wxString
*strSecond
= (wxString
*)second
;
402 if ( gs_compareFunction
) {
403 return gs_compareFunction(*strFirst
, *strSecond
);
406 // maybe we should use wxStrcoll
407 int result
= strFirst
->Cmp(*strSecond
);
409 return gs_sortAscending ? result
: -result
;
413 // sort array elements using passed comparaison function
414 void wxArrayString
::Sort(CompareFunction compareFunction
)
416 wxCRIT_SECT_LOCKER(lockCmpFunc
, gs_critsectStringSort
);
418 wxASSERT( !gs_compareFunction
); // must have been reset to NULL
419 gs_compareFunction
= compareFunction
;
423 // reset it to NULL so that Sort(bool) will work the next time
424 gs_compareFunction
= NULL
;
429 typedef int (wxC_CALLING_CONV
* wxStringCompareFn
)(const void *first
,
433 void wxArrayString
::Sort(CompareFunction2 compareFunction
)
435 qsort(m_pItems
, m_nCount
, sizeof(wxString
), (wxStringCompareFn
)compareFunction
);
438 void wxArrayString
::Sort(bool reverseOrder
)
440 Sort(reverseOrder ? wxStringSortDescending
: wxStringSortAscending
);
443 void wxArrayString
::DoSort()
445 wxCHECK_RET( !m_autoSort
, wxT("can't use this method with sorted arrays") );
447 qsort(m_pItems
, m_nCount
, sizeof(wxString
), wxStringCompareFunction
);
450 bool wxArrayString
::operator==(const wxArrayString
& a
) const
452 if ( m_nCount
!= a
.m_nCount
)
455 for ( size_t n
= 0; n
< m_nCount
; n
++ )
457 if ( Item(n
) != a
[n
] )
466 int wxCMPFUNC_CONV
wxStringSortAscending(wxString
* s1
, wxString
* s2
)
471 int wxCMPFUNC_CONV
wxStringSortDescending(wxString
* s1
, wxString
* s2
)
473 return -s1
->Cmp(*s2
);
478 // ===========================================================================
479 // wxJoin and wxSplit
480 // ===========================================================================
482 #include "wx/tokenzr.h"
484 wxString
wxJoin(const wxArrayString
& arr
, const wxChar sep
, const wxChar escape
)
486 size_t count
= arr
.size();
488 return wxEmptyString
;
492 // pre-allocate memory using the estimation of the average length of the
493 // strings in the given array: this is very imprecise, of course, but
494 // better than nothing
495 str
.reserve(count
*(arr
[0].length() + arr
[count
-1].length()) / 2);
497 if ( escape
== wxT('\0') )
499 // escaping is disabled:
500 for ( size_t i
= 0; i
< count
; i
++ )
507 else // use escape character
509 for ( size_t n
= 0; n
< count
; n
++ )
514 for ( wxString
::const_iterator i
= arr
[n
].begin(),
519 const wxChar ch
= *i
;
521 str
+= escape
; // escape this separator
527 str
.Shrink(); // release extra memory if we allocated too much
531 wxArrayString
wxSplit(const wxString
& str
, const wxChar sep
, const wxChar escape
)
533 if ( escape
== wxT('\0') )
535 // simple case: we don't need to honour the escape character
536 return wxStringTokenize(str
, sep
, wxTOKEN_RET_EMPTY_ALL
);
541 wxChar prev
= wxT('\0');
543 for ( wxString
::const_iterator i
= str
.begin(),
548 const wxChar ch
= *i
;
552 if ( prev
== escape
)
554 // remove the escape character and don't consider this
555 // occurrence of 'sep' as a real separator
556 *curr
.rbegin() = sep
;
558 else // real separator
564 else // normal character
572 // add the last token
573 if ( !curr
.empty() || prev
== sep
)