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
)