1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/arrstr.cpp
3 // Purpose: wxArrayString class
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
12 // headers, declarations, constants
13 // ===========================================================================
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
22 #include "wx/arrstr.h"
24 #include "wx/beforestd.h"
27 #include "wx/afterstd.h"
29 // ============================================================================
31 // ============================================================================
33 wxArrayString::wxArrayString(size_t sz
, const char** a
)
35 #if !wxUSE_STD_CONTAINERS
38 for (size_t i
=0; i
< sz
; i
++)
42 wxArrayString::wxArrayString(size_t sz
, const wchar_t** a
)
44 #if !wxUSE_STD_CONTAINERS
47 for (size_t i
=0; i
< sz
; i
++)
51 wxArrayString::wxArrayString(size_t sz
, const wxString
* a
)
53 #if !wxUSE_STD_CONTAINERS
56 for (size_t i
=0; i
< sz
; i
++)
60 #if !wxUSE_STD_CONTAINERS
62 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
63 #define ARRAY_MAXSIZE_INCREMENT 4096
65 #ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h
66 #define ARRAY_DEFAULT_INITIAL_SIZE (16)
70 void wxArrayString::Init(bool autoSort
)
75 m_autoSort
= autoSort
;
79 wxArrayString::wxArrayString(const wxArrayString
& src
)
86 // assignment operator
87 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
)
94 m_autoSort
= src
.m_autoSort
;
99 void wxArrayString::Copy(const wxArrayString
& src
)
101 if ( src
.m_nCount
> ARRAY_DEFAULT_INITIAL_SIZE
)
104 for ( size_t n
= 0; n
< src
.m_nCount
; n
++ )
109 void wxArrayString::Grow(size_t nIncrement
)
111 // only do it if no more place
112 if ( (m_nSize
- m_nCount
) < nIncrement
) {
113 // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
115 #if ARRAY_DEFAULT_INITIAL_SIZE == 0
116 #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
119 if ( m_nSize
== 0 ) {
120 // was empty, alloc some memory
121 m_nSize
= ARRAY_DEFAULT_INITIAL_SIZE
;
122 if (m_nSize
< nIncrement
)
123 m_nSize
= nIncrement
;
124 m_pItems
= new wxString
[m_nSize
];
127 // otherwise when it's called for the first time, nIncrement would be 0
128 // and the array would never be expanded
129 // add 50% but not too much
130 size_t ndefIncrement
= m_nSize
< ARRAY_DEFAULT_INITIAL_SIZE
131 ? ARRAY_DEFAULT_INITIAL_SIZE
: m_nSize
>> 1;
132 if ( ndefIncrement
> ARRAY_MAXSIZE_INCREMENT
)
133 ndefIncrement
= ARRAY_MAXSIZE_INCREMENT
;
134 if ( nIncrement
< ndefIncrement
)
135 nIncrement
= ndefIncrement
;
136 m_nSize
+= nIncrement
;
137 wxString
*pNew
= new wxString
[m_nSize
];
139 // copy data to new location
140 for ( size_t j
= 0; j
< m_nCount
; j
++ )
141 pNew
[j
] = m_pItems
[j
];
143 // delete old memory (but do not release the strings!)
151 // deletes all the strings from the list
152 void wxArrayString::Empty()
157 // as Empty, but also frees memory
158 void wxArrayString::Clear()
167 wxArrayString::~wxArrayString()
172 void wxArrayString::reserve(size_t nSize
)
177 // pre-allocates memory (frees the previous data!)
178 void wxArrayString::Alloc(size_t nSize
)
180 // only if old buffer was not big enough
181 if ( nSize
> m_nSize
) {
182 wxString
*pNew
= new wxString
[nSize
];
186 for ( size_t j
= 0; j
< m_nCount
; j
++ )
187 pNew
[j
] = m_pItems
[j
];
195 // minimizes the memory usage by freeing unused memory
196 void wxArrayString::Shrink()
198 // only do it if we have some memory to free
199 if( m_nCount
< m_nSize
) {
200 // allocates exactly as much memory as we need
201 wxString
*pNew
= new wxString
[m_nCount
];
203 // copy data to new location
204 for ( size_t j
= 0; j
< m_nCount
; j
++ )
205 pNew
[j
] = m_pItems
[j
];
212 // searches the array for an item (forward or backwards)
213 int wxArrayString::Index(const wxString
& str
, bool bCase
, bool bFromEnd
) const
216 // use binary search in the sorted array
217 wxASSERT_MSG( bCase
&& !bFromEnd
,
218 wxT("search parameters ignored for auto sorted array") );
227 res
= str
.compare(m_pItems
[i
]);
239 // use linear search in unsorted array
241 if ( m_nCount
> 0 ) {
242 size_t ui
= m_nCount
;
244 if ( m_pItems
[--ui
].IsSameAs(str
, bCase
) )
251 for( size_t ui
= 0; ui
< m_nCount
; ui
++ ) {
252 if( m_pItems
[ui
].IsSameAs(str
, bCase
) )
261 // add item at the end
262 size_t wxArrayString::Add(const wxString
& str
, size_t nInsert
)
265 // insert the string at the correct position to keep the array sorted
273 res
= str
.Cmp(m_pItems
[i
]);
284 wxASSERT_MSG( lo
== hi
, wxT("binary search broken") );
286 Insert(str
, lo
, nInsert
);
293 for (size_t i
= 0; i
< nInsert
; i
++)
296 m_pItems
[m_nCount
+ i
] = str
;
298 size_t ret
= m_nCount
;
304 // add item at the given position
305 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
, size_t nInsert
)
307 wxCHECK_RET( nIndex
<= m_nCount
, wxT("bad index in wxArrayString::Insert") );
308 wxCHECK_RET( m_nCount
<= m_nCount
+ nInsert
,
309 wxT("array size overflow in wxArrayString::Insert") );
313 for (int j
= m_nCount
- nIndex
- 1; j
>= 0; j
--)
314 m_pItems
[nIndex
+ nInsert
+ j
] = m_pItems
[nIndex
+ j
];
316 for (size_t i
= 0; i
< nInsert
; i
++)
318 m_pItems
[nIndex
+ i
] = str
;
323 // range insert (STL 23.2.4.3)
325 wxArrayString::insert(iterator it
, const_iterator first
, const_iterator last
)
327 const int idx
= it
- begin();
332 // reset "it" since it can change inside Grow()
335 while ( first
!= last
)
337 it
= insert(it
, *first
);
339 // insert returns an iterator to the last element inserted but we need
340 // insert the next after this one, that is before the next one
347 void wxArrayString::resize(size_type n
, value_type v
)
351 else if ( n
> m_nCount
)
352 Add(v
, n
- m_nCount
);
356 void wxArrayString::SetCount(size_t count
)
361 while ( m_nCount
< count
)
362 m_pItems
[m_nCount
++] = s
;
365 // removes item from array (by index)
366 void wxArrayString::RemoveAt(size_t nIndex
, size_t nRemove
)
368 wxCHECK_RET( nIndex
< m_nCount
, wxT("bad index in wxArrayString::Remove") );
369 wxCHECK_RET( nIndex
+ nRemove
<= m_nCount
,
370 wxT("removing too many elements in wxArrayString::Remove") );
372 for ( size_t j
= 0; j
< m_nCount
- nIndex
-nRemove
; j
++)
373 m_pItems
[nIndex
+ j
] = m_pItems
[nIndex
+ nRemove
+ j
];
378 // removes item from array (by value)
379 void wxArrayString::Remove(const wxString
& sz
)
381 int iIndex
= Index(sz
);
383 wxCHECK_RET( iIndex
!= wxNOT_FOUND
,
384 wxT("removing inexistent element in wxArrayString::Remove") );
389 // ----------------------------------------------------------------------------
391 // ----------------------------------------------------------------------------
393 // we need an adaptor as our predicates use qsort() convention and so return
394 // negative, null or positive value depending on whether the first item is less
395 // than, equal to or greater than the other one while we need a real boolean
396 // predicate now that we use std::sort()
397 struct wxSortPredicateAdaptor
399 wxSortPredicateAdaptor(wxArrayString::CompareFunction compareFunction
)
400 : m_compareFunction(compareFunction
)
404 bool operator()(const wxString
& first
, const wxString
& second
) const
406 return (*m_compareFunction
)(first
, second
) < 0;
409 wxArrayString::CompareFunction m_compareFunction
;
412 void wxArrayString::Sort(CompareFunction compareFunction
)
414 wxCHECK_RET( !m_autoSort
, wxT("can't use this method with sorted arrays") );
416 std::sort(m_pItems
, m_pItems
+ m_nCount
,
417 wxSortPredicateAdaptor(compareFunction
));
420 struct wxSortPredicateAdaptor2
422 wxSortPredicateAdaptor2(wxArrayString::CompareFunction2 compareFunction
)
423 : m_compareFunction(compareFunction
)
427 bool operator()(const wxString
& first
, const wxString
& second
) const
429 return (*m_compareFunction
)(const_cast<wxString
*>(&first
),
430 const_cast<wxString
*>(&second
)) < 0;
433 wxArrayString::CompareFunction2 m_compareFunction
;
436 void wxArrayString::Sort(CompareFunction2 compareFunction
)
438 std::sort(m_pItems
, m_pItems
+ m_nCount
,
439 wxSortPredicateAdaptor2(compareFunction
));
442 void wxArrayString::Sort(bool reverseOrder
)
445 std::sort(m_pItems
, m_pItems
+ m_nCount
, std::greater
<wxString
>());
447 std::sort(m_pItems
, m_pItems
+ m_nCount
);
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
] )
464 #endif // !wxUSE_STD_CONTAINERS
466 // ===========================================================================
467 // wxJoin and wxSplit
468 // ===========================================================================
470 #include "wx/tokenzr.h"
472 wxString
wxJoin(const wxArrayString
& arr
, const wxChar sep
, const wxChar escape
)
474 size_t count
= arr
.size();
476 return wxEmptyString
;
480 // pre-allocate memory using the estimation of the average length of the
481 // strings in the given array: this is very imprecise, of course, but
482 // better than nothing
483 str
.reserve(count
*(arr
[0].length() + arr
[count
-1].length()) / 2);
485 if ( escape
== wxT('\0') )
487 // escaping is disabled:
488 for ( size_t i
= 0; i
< count
; i
++ )
495 else // use escape character
497 for ( size_t n
= 0; n
< count
; n
++ )
502 for ( wxString::const_iterator i
= arr
[n
].begin(),
507 const wxChar ch
= *i
;
509 str
+= escape
; // escape this separator
515 str
.Shrink(); // release extra memory if we allocated too much
519 wxArrayString
wxSplit(const wxString
& str
, const wxChar sep
, const wxChar escape
)
521 if ( escape
== wxT('\0') )
523 // simple case: we don't need to honour the escape character
524 return wxStringTokenize(str
, sep
, wxTOKEN_RET_EMPTY_ALL
);
529 wxChar prev
= wxT('\0');
531 for ( wxString::const_iterator i
= str
.begin(),
536 const wxChar ch
= *i
;
540 if ( prev
== escape
)
542 // remove the escape character and don't consider this
543 // occurrence of 'sep' as a real separator
544 *curr
.rbegin() = sep
;
546 else // real separator
552 else // normal character
560 // add the last token
561 if ( !curr
.empty() || prev
== sep
)