stringimpl.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: wx/stringimpl.h
  3. // Purpose: wxStringImpl class, implementation of wxString
  4. // Author: Vadim Zeitlin
  5. // Modified by:
  6. // Created: 29/01/98
  7. // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  8. // Licence: wxWindows licence
  9. ///////////////////////////////////////////////////////////////////////////////
  10. /*
  11. This header implements std::string-like string class, wxStringImpl, that is
  12. used by wxString to store the data. Alternatively, if wxUSE_STD_STRING=1,
  13. wxStringImpl is just a typedef to std:: string class.
  14. */
  15. #ifndef _WX_WXSTRINGIMPL_H__
  16. #define _WX_WXSTRINGIMPL_H__
  17. // ----------------------------------------------------------------------------
  18. // headers
  19. // ----------------------------------------------------------------------------
  20. #include "wx/defs.h" // everybody should include this
  21. #include "wx/chartype.h" // for wxChar
  22. #include "wx/wxcrtbase.h" // for wxStrlen() etc.
  23. #include <stdlib.h>
  24. // ---------------------------------------------------------------------------
  25. // macros
  26. // ---------------------------------------------------------------------------
  27. // implementation only
  28. #define wxASSERT_VALID_INDEX(i) \
  29. wxASSERT_MSG( (size_t)(i) <= length(), wxT("invalid index in wxString") )
  30. // ----------------------------------------------------------------------------
  31. // global data
  32. // ----------------------------------------------------------------------------
  33. // global pointer to empty string
  34. extern WXDLLIMPEXP_DATA_BASE(const wxChar*) wxEmptyString;
  35. #if wxUSE_UNICODE_UTF8
  36. // FIXME-UTF8: we should have only one wxEmptyString
  37. extern WXDLLIMPEXP_DATA_BASE(const wxStringCharType*) wxEmptyStringImpl;
  38. #endif
  39. // ----------------------------------------------------------------------------
  40. // deal with various build options
  41. // ----------------------------------------------------------------------------
  42. // we use STL-based string internally if we use std::string at all now, there
  43. // should be no reason to prefer our internal implement but if you really need
  44. // it you can predefine wxUSE_STL_BASED_WXSTRING as 0 when building the library
  45. #ifndef wxUSE_STL_BASED_WXSTRING
  46. #define wxUSE_STL_BASED_WXSTRING wxUSE_STD_STRING
  47. #endif
  48. // in both cases we need to define wxStdString
  49. #if wxUSE_STL_BASED_WXSTRING || wxUSE_STD_STRING
  50. #include "wx/beforestd.h"
  51. #include <string>
  52. #include "wx/afterstd.h"
  53. #ifdef HAVE_STD_WSTRING
  54. typedef std::wstring wxStdWideString;
  55. #else
  56. typedef std::basic_string<wchar_t> wxStdWideString;
  57. #endif
  58. #if wxUSE_UNICODE_WCHAR
  59. typedef wxStdWideString wxStdString;
  60. #else
  61. typedef std::string wxStdString;
  62. #endif
  63. #endif // wxUSE_STL_BASED_WXSTRING || wxUSE_STD_STRING
  64. #if wxUSE_STL_BASED_WXSTRING
  65. // we always want ctor from std::string when using std::string internally
  66. #undef wxUSE_STD_STRING
  67. #define wxUSE_STD_STRING 1
  68. // the versions of std::string included with gcc 2.95 and VC6 (for which
  69. // _MSC_VER == 1200) and eVC4 (_MSC_VER == 1201) lack clear() method
  70. #if (defined(__GNUG__) && (__GNUG__ < 3)) || \
  71. !wxCHECK_VISUALC_VERSION(7) || defined(__EVC4__)
  72. #define wxSTRING_BASE_HASNT_CLEAR
  73. #endif
  74. typedef wxStdString wxStringImpl;
  75. #else // if !wxUSE_STL_BASED_WXSTRING
  76. // in non-STL mode, compare() is implemented in wxString and not wxStringImpl
  77. #undef HAVE_STD_STRING_COMPARE
  78. // ---------------------------------------------------------------------------
  79. // string data prepended with some housekeeping info (used by wxString class),
  80. // is never used directly (but had to be put here to allow inlining)
  81. // ---------------------------------------------------------------------------
  82. struct WXDLLIMPEXP_BASE wxStringData
  83. {
  84. int nRefs; // reference count
  85. size_t nDataLength, // actual string length
  86. nAllocLength; // allocated memory size
  87. // mimics declaration 'wxStringCharType data[nAllocLength]'
  88. wxStringCharType* data() const { return (wxStringCharType*)(this + 1); }
  89. // empty string has a special ref count so it's never deleted
  90. bool IsEmpty() const { return (nRefs == -1); }
  91. bool IsShared() const { return (nRefs > 1); }
  92. // lock/unlock
  93. void Lock() { if ( !IsEmpty() ) nRefs++; }
  94. // VC++ will refuse to inline Unlock but profiling shows that it is wrong
  95. #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
  96. __forceinline
  97. #endif
  98. // VC++ free must take place in same DLL as allocation when using non dll
  99. // run-time library (e.g. Multithreaded instead of Multithreaded DLL)
  100. #if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
  101. void Unlock() { if ( !IsEmpty() && --nRefs == 0) Free(); }
  102. // we must not inline deallocation since allocation is not inlined
  103. void Free();
  104. #else
  105. void Unlock() { if ( !IsEmpty() && --nRefs == 0) free(this); }
  106. #endif
  107. // if we had taken control over string memory (GetWriteBuf), it's
  108. // intentionally put in invalid state
  109. void Validate(bool b) { nRefs = (b ? 1 : 0); }
  110. bool IsValid() const { return (nRefs != 0); }
  111. };
  112. class WXDLLIMPEXP_BASE wxStringImpl
  113. {
  114. public:
  115. // an 'invalid' value for string index, moved to this place due to a CW bug
  116. static const size_t npos;
  117. protected:
  118. // points to data preceded by wxStringData structure with ref count info
  119. wxStringCharType *m_pchData;
  120. // accessor to string data
  121. wxStringData* GetStringData() const { return (wxStringData*)m_pchData - 1; }
  122. // string (re)initialization functions
  123. // initializes the string to the empty value (must be called only from
  124. // ctors, use Reinit() otherwise)
  125. #if wxUSE_UNICODE_UTF8
  126. void Init() { m_pchData = (wxStringCharType *)wxEmptyStringImpl; } // FIXME-UTF8
  127. #else
  128. void Init() { m_pchData = (wxStringCharType *)wxEmptyString; }
  129. #endif
  130. // initializes the string with (a part of) C-string
  131. void InitWith(const wxStringCharType *psz, size_t nPos = 0, size_t nLen = npos);
  132. // as Init, but also frees old data
  133. void Reinit() { GetStringData()->Unlock(); Init(); }
  134. // memory allocation
  135. // allocates memory for string of length nLen
  136. bool AllocBuffer(size_t nLen);
  137. // effectively copies data to string
  138. bool AssignCopy(size_t, const wxStringCharType *);
  139. // append a (sub)string
  140. bool ConcatSelf(size_t nLen, const wxStringCharType *src, size_t nMaxLen);
  141. bool ConcatSelf(size_t nLen, const wxStringCharType *src)
  142. { return ConcatSelf(nLen, src, nLen); }
  143. // functions called before writing to the string: they copy it if there
  144. // are other references to our data (should be the only owner when writing)
  145. bool CopyBeforeWrite();
  146. bool AllocBeforeWrite(size_t);
  147. // compatibility with wxString
  148. bool Alloc(size_t nLen);
  149. public:
  150. // standard types
  151. typedef wxStringCharType value_type;
  152. typedef wxStringCharType char_type;
  153. typedef size_t size_type;
  154. typedef value_type& reference;
  155. typedef const value_type& const_reference;
  156. typedef value_type* pointer;
  157. typedef const value_type* const_pointer;
  158. // macro to define the bulk of iterator and const_iterator classes
  159. #define WX_DEFINE_STRINGIMPL_ITERATOR(iterator_name, ref_type, ptr_type) \
  160. public: \
  161. typedef wxStringCharType value_type; \
  162. typedef ref_type reference; \
  163. typedef ptr_type pointer; \
  164. typedef int difference_type; \
  165. \
  166. iterator_name() : m_ptr(NULL) { } \
  167. iterator_name(pointer ptr) : m_ptr(ptr) { } \
  168. \
  169. reference operator*() const { return *m_ptr; } \
  170. \
  171. iterator_name& operator++() { m_ptr++; return *this; } \
  172. iterator_name operator++(int) \
  173. { \
  174. const iterator_name tmp(*this); \
  175. m_ptr++; \
  176. return tmp; \
  177. } \
  178. \
  179. iterator_name& operator--() { m_ptr--; return *this; } \
  180. iterator_name operator--(int) \
  181. { \
  182. const iterator_name tmp(*this); \
  183. m_ptr--; \
  184. return tmp; \
  185. } \
  186. \
  187. iterator_name operator+(ptrdiff_t n) const \
  188. { return iterator_name(m_ptr + n); } \
  189. iterator_name operator-(ptrdiff_t n) const \
  190. { return iterator_name(m_ptr - n); } \
  191. iterator_name& operator+=(ptrdiff_t n) \
  192. { m_ptr += n; return *this; } \
  193. iterator_name& operator-=(ptrdiff_t n) \
  194. { m_ptr -= n; return *this; } \
  195. \
  196. difference_type operator-(const iterator_name& i) const \
  197. { return m_ptr - i.m_ptr; } \
  198. \
  199. bool operator==(const iterator_name& i) const \
  200. { return m_ptr == i.m_ptr; } \
  201. bool operator!=(const iterator_name& i) const \
  202. { return m_ptr != i.m_ptr; } \
  203. \
  204. bool operator<(const iterator_name& i) const \
  205. { return m_ptr < i.m_ptr; } \
  206. bool operator>(const iterator_name& i) const \
  207. { return m_ptr > i.m_ptr; } \
  208. bool operator<=(const iterator_name& i) const \
  209. { return m_ptr <= i.m_ptr; } \
  210. bool operator>=(const iterator_name& i) const \
  211. { return m_ptr >= i.m_ptr; } \
  212. \
  213. private: \
  214. /* for wxStringImpl use only */ \
  215. pointer GetPtr() const { return m_ptr; } \
  216. \
  217. friend class wxStringImpl; \
  218. \
  219. pointer m_ptr
  220. // we need to declare const_iterator in wxStringImpl scope, the friend
  221. // declaration inside iterator class itself is not enough, or at least not
  222. // for g++ 3.4 (g++ 4 is ok)
  223. class WXDLLIMPEXP_FWD_BASE const_iterator;
  224. class WXDLLIMPEXP_BASE iterator
  225. {
  226. WX_DEFINE_STRINGIMPL_ITERATOR(iterator,
  227. wxStringCharType&,
  228. wxStringCharType*);
  229. friend class const_iterator;
  230. };
  231. class WXDLLIMPEXP_BASE const_iterator
  232. {
  233. public:
  234. const_iterator(iterator i) : m_ptr(i.m_ptr) { }
  235. WX_DEFINE_STRINGIMPL_ITERATOR(const_iterator,
  236. const wxStringCharType&,
  237. const wxStringCharType*);
  238. };
  239. #undef WX_DEFINE_STRINGIMPL_ITERATOR
  240. // constructors and destructor
  241. // ctor for an empty string
  242. wxStringImpl() { Init(); }
  243. // copy ctor
  244. wxStringImpl(const wxStringImpl& stringSrc)
  245. {
  246. wxASSERT_MSG( stringSrc.GetStringData()->IsValid(),
  247. wxT("did you forget to call UngetWriteBuf()?") );
  248. if ( stringSrc.empty() ) {
  249. // nothing to do for an empty string
  250. Init();
  251. }
  252. else {
  253. m_pchData = stringSrc.m_pchData; // share same data
  254. GetStringData()->Lock(); // => one more copy
  255. }
  256. }
  257. // string containing nRepeat copies of ch
  258. wxStringImpl(size_type nRepeat, wxStringCharType ch);
  259. // ctor takes first nLength characters from C string
  260. // (default value of npos means take all the string)
  261. wxStringImpl(const wxStringCharType *psz)
  262. { InitWith(psz, 0, npos); }
  263. wxStringImpl(const wxStringCharType *psz, size_t nLength)
  264. { InitWith(psz, 0, nLength); }
  265. // take nLen chars starting at nPos
  266. wxStringImpl(const wxStringImpl& str, size_t nPos, size_t nLen)
  267. {
  268. wxASSERT_MSG( str.GetStringData()->IsValid(),
  269. wxT("did you forget to call UngetWriteBuf()?") );
  270. Init();
  271. size_t strLen = str.length() - nPos; nLen = strLen < nLen ? strLen : nLen;
  272. InitWith(str.c_str(), nPos, nLen);
  273. }
  274. // take everything between start and end
  275. wxStringImpl(const_iterator start, const_iterator end);
  276. // ctor from and conversion to std::string
  277. #if wxUSE_STD_STRING
  278. wxStringImpl(const wxStdString& impl)
  279. { InitWith(impl.c_str(), 0, impl.length()); }
  280. operator wxStdString() const
  281. { return wxStdString(c_str(), length()); }
  282. #endif
  283. #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
  284. // disable warning about Unlock() below not being inlined (first, it
  285. // seems to be inlined nevertheless and second, even if it isn't, there
  286. // is nothing we can do about this
  287. #pragma warning(push)
  288. #pragma warning (disable:4714)
  289. #endif
  290. // dtor is not virtual, this class must not be inherited from!
  291. ~wxStringImpl()
  292. {
  293. GetStringData()->Unlock();
  294. }
  295. #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
  296. #pragma warning(pop)
  297. #endif
  298. // overloaded assignment
  299. // from another wxString
  300. wxStringImpl& operator=(const wxStringImpl& stringSrc);
  301. // from a character
  302. wxStringImpl& operator=(wxStringCharType ch);
  303. // from a C string
  304. wxStringImpl& operator=(const wxStringCharType *psz);
  305. // return the length of the string
  306. size_type length() const { return GetStringData()->nDataLength; }
  307. // return the length of the string
  308. size_type size() const { return length(); }
  309. // return the maximum size of the string
  310. size_type max_size() const { return npos; }
  311. // resize the string, filling the space with c if c != 0
  312. void resize(size_t nSize, wxStringCharType ch = '\0');
  313. // delete the contents of the string
  314. void clear() { erase(0, npos); }
  315. // returns true if the string is empty
  316. bool empty() const { return length() == 0; }
  317. // inform string about planned change in size
  318. void reserve(size_t sz) { Alloc(sz); }
  319. size_type capacity() const { return GetStringData()->nAllocLength; }
  320. // lib.string.access
  321. // return the character at position n
  322. value_type operator[](size_type n) const { return m_pchData[n]; }
  323. value_type at(size_type n) const
  324. { wxASSERT_VALID_INDEX( n ); return m_pchData[n]; }
  325. // returns the writable character at position n
  326. reference operator[](size_type n) { CopyBeforeWrite(); return m_pchData[n]; }
  327. reference at(size_type n)
  328. {
  329. wxASSERT_VALID_INDEX( n );
  330. CopyBeforeWrite();
  331. return m_pchData[n];
  332. } // FIXME-UTF8: not useful for us...?
  333. // lib.string.modifiers
  334. // append elements str[pos], ..., str[pos+n]
  335. wxStringImpl& append(const wxStringImpl& str, size_t pos, size_t n)
  336. {
  337. wxASSERT(pos <= str.length());
  338. ConcatSelf(n, str.c_str() + pos, str.length() - pos);
  339. return *this;
  340. }
  341. // append a string
  342. wxStringImpl& append(const wxStringImpl& str)
  343. { ConcatSelf(str.length(), str.c_str()); return *this; }
  344. // append first n (or all if n == npos) characters of sz
  345. wxStringImpl& append(const wxStringCharType *sz)
  346. { ConcatSelf(wxStrlen(sz), sz); return *this; }
  347. wxStringImpl& append(const wxStringCharType *sz, size_t n)
  348. { ConcatSelf(n, sz); return *this; }
  349. // append n copies of ch
  350. wxStringImpl& append(size_t n, wxStringCharType ch);
  351. // append from first to last
  352. wxStringImpl& append(const_iterator first, const_iterator last)
  353. { ConcatSelf(last - first, first.GetPtr()); return *this; }
  354. // same as `this_string = str'
  355. wxStringImpl& assign(const wxStringImpl& str)
  356. { return *this = str; }
  357. // same as ` = str[pos..pos + n]
  358. wxStringImpl& assign(const wxStringImpl& str, size_t pos, size_t n)
  359. { return replace(0, npos, str, pos, n); }
  360. // same as `= first n (or all if n == npos) characters of sz'
  361. wxStringImpl& assign(const wxStringCharType *sz)
  362. { return replace(0, npos, sz, wxStrlen(sz)); }
  363. wxStringImpl& assign(const wxStringCharType *sz, size_t n)
  364. { return replace(0, npos, sz, n); }
  365. // same as `= n copies of ch'
  366. wxStringImpl& assign(size_t n, wxStringCharType ch)
  367. { return replace(0, npos, n, ch); }
  368. // assign from first to last
  369. wxStringImpl& assign(const_iterator first, const_iterator last)
  370. { return replace(begin(), end(), first, last); }
  371. // first valid index position
  372. const_iterator begin() const { return m_pchData; }
  373. iterator begin();
  374. // position one after the last valid one
  375. const_iterator end() const { return m_pchData + length(); }
  376. iterator end();
  377. // insert another string
  378. wxStringImpl& insert(size_t nPos, const wxStringImpl& str)
  379. {
  380. wxASSERT( str.GetStringData()->IsValid() );
  381. return insert(nPos, str.c_str(), str.length());
  382. }
  383. // insert n chars of str starting at nStart (in str)
  384. wxStringImpl& insert(size_t nPos, const wxStringImpl& str, size_t nStart, size_t n)
  385. {
  386. wxASSERT( str.GetStringData()->IsValid() );
  387. wxASSERT( nStart < str.length() );
  388. size_t strLen = str.length() - nStart;
  389. n = strLen < n ? strLen : n;
  390. return insert(nPos, str.c_str() + nStart, n);
  391. }
  392. // insert first n (or all if n == npos) characters of sz
  393. wxStringImpl& insert(size_t nPos, const wxStringCharType *sz, size_t n = npos);
  394. // insert n copies of ch
  395. wxStringImpl& insert(size_t nPos, size_t n, wxStringCharType ch)
  396. { return insert(nPos, wxStringImpl(n, ch)); }
  397. iterator insert(iterator it, wxStringCharType ch)
  398. { size_t idx = it - begin(); insert(idx, 1, ch); return begin() + idx; }
  399. void insert(iterator it, const_iterator first, const_iterator last)
  400. { insert(it - begin(), first.GetPtr(), last - first); }
  401. void insert(iterator it, size_type n, wxStringCharType ch)
  402. { insert(it - begin(), n, ch); }
  403. // delete characters from nStart to nStart + nLen
  404. wxStringImpl& erase(size_type pos = 0, size_type n = npos);
  405. iterator erase(iterator first, iterator last)
  406. {
  407. size_t idx = first - begin();
  408. erase(idx, last - first);
  409. return begin() + idx;
  410. }
  411. iterator erase(iterator first);
  412. // explicit conversion to C string (use this with printf()!)
  413. const wxStringCharType* c_str() const { return m_pchData; }
  414. const wxStringCharType* data() const { return m_pchData; }
  415. // replaces the substring of length nLen starting at nStart
  416. wxStringImpl& replace(size_t nStart, size_t nLen, const wxStringCharType* sz)
  417. { return replace(nStart, nLen, sz, npos); }
  418. // replaces the substring of length nLen starting at nStart
  419. wxStringImpl& replace(size_t nStart, size_t nLen, const wxStringImpl& str)
  420. { return replace(nStart, nLen, str.c_str(), str.length()); }
  421. // replaces the substring with nCount copies of ch
  422. wxStringImpl& replace(size_t nStart, size_t nLen,
  423. size_t nCount, wxStringCharType ch)
  424. { return replace(nStart, nLen, wxStringImpl(nCount, ch)); }
  425. // replaces a substring with another substring
  426. wxStringImpl& replace(size_t nStart, size_t nLen,
  427. const wxStringImpl& str, size_t nStart2, size_t nLen2)
  428. { return replace(nStart, nLen, str.substr(nStart2, nLen2)); }
  429. // replaces the substring with first nCount chars of sz
  430. wxStringImpl& replace(size_t nStart, size_t nLen,
  431. const wxStringCharType* sz, size_t nCount);
  432. wxStringImpl& replace(iterator first, iterator last, const_pointer s)
  433. { return replace(first - begin(), last - first, s); }
  434. wxStringImpl& replace(iterator first, iterator last, const_pointer s,
  435. size_type n)
  436. { return replace(first - begin(), last - first, s, n); }
  437. wxStringImpl& replace(iterator first, iterator last, const wxStringImpl& s)
  438. { return replace(first - begin(), last - first, s); }
  439. wxStringImpl& replace(iterator first, iterator last, size_type n, wxStringCharType c)
  440. { return replace(first - begin(), last - first, n, c); }
  441. wxStringImpl& replace(iterator first, iterator last,
  442. const_iterator first1, const_iterator last1)
  443. { return replace(first - begin(), last - first, first1.GetPtr(), last1 - first1); }
  444. // swap two strings
  445. void swap(wxStringImpl& str);
  446. // All find() functions take the nStart argument which specifies the
  447. // position to start the search on, the default value is 0. All functions
  448. // return npos if there were no match.
  449. // find a substring
  450. size_t find(const wxStringImpl& str, size_t nStart = 0) const;
  451. // find first n characters of sz
  452. size_t find(const wxStringCharType* sz, size_t nStart = 0, size_t n = npos) const;
  453. // find the first occurrence of character ch after nStart
  454. size_t find(wxStringCharType ch, size_t nStart = 0) const;
  455. // rfind() family is exactly like find() but works right to left
  456. // as find, but from the end
  457. size_t rfind(const wxStringImpl& str, size_t nStart = npos) const;
  458. // as find, but from the end
  459. size_t rfind(const wxStringCharType* sz, size_t nStart = npos,
  460. size_t n = npos) const;
  461. // as find, but from the end
  462. size_t rfind(wxStringCharType ch, size_t nStart = npos) const;
  463. size_type copy(wxStringCharType* s, size_type n, size_type pos = 0);
  464. // substring extraction
  465. wxStringImpl substr(size_t nStart = 0, size_t nLen = npos) const;
  466. // string += string
  467. wxStringImpl& operator+=(const wxStringImpl& s) { return append(s); }
  468. // string += C string
  469. wxStringImpl& operator+=(const wxStringCharType *psz) { return append(psz); }
  470. // string += char
  471. wxStringImpl& operator+=(wxStringCharType ch) { return append(1, ch); }
  472. // helpers for wxStringBuffer and wxStringBufferLength
  473. wxStringCharType *DoGetWriteBuf(size_t nLen);
  474. void DoUngetWriteBuf();
  475. void DoUngetWriteBuf(size_t nLen);
  476. friend class WXDLLIMPEXP_FWD_BASE wxString;
  477. };
  478. #endif // !wxUSE_STL_BASED_WXSTRING
  479. // don't pollute the library user's name space
  480. #undef wxASSERT_VALID_INDEX
  481. #endif // _WX_WXSTRINGIMPL_H__