From 8f93a29f8e50aa9dc6076a900ad6d316fafddcc3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Mon, 26 Mar 2007 20:28:04 +0000 Subject: [PATCH] Preparing wxString for UTF-8 representation: 1) split into wxStringImpl class that has std::string-like API and operates on char* or wchar_t* data and wxString class that provides Unicode iterators and indexes 2) added both char* and wchar_t* versions of many wxString methods to avoid having to use _T() git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45078 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/chartype.h | 25 + include/wx/string.h | 1596 +++++++++++++++++++++++++------------- include/wx/strvararg.h | 20 +- src/common/string.cpp | 801 ++++++++++++------- src/common/strvararg.cpp | 6 +- 5 files changed, 1605 insertions(+), 843 deletions(-) diff --git a/include/wx/chartype.h b/include/wx/chartype.h index c73722946a..934e13d1bc 100644 --- a/include/wx/chartype.h +++ b/include/wx/chartype.h @@ -183,6 +183,31 @@ #endif /* __WCHAR_TYPE__ */ #endif /* ASCII/Unicode */ +/* ------------------------------------------------------------------------- */ +/* define wxStringCharType */ +/* ------------------------------------------------------------------------- */ + +/* depending on the platform, Unicode build can either store wxStrings as + wchar_t* or UTF-8 encoded char*: */ +#if wxUSE_UNICODE + /* for now, all Unicode builds are wchar_t* based: */ + #define wxUSE_UNICODE_WCHAR 1 + #define wxUSE_UNICODE_UTF8 0 +#else + #define wxUSE_UNICODE_WCHAR 0 + #define wxUSE_UNICODE_UTF8 0 +#endif + +/* define char type used by wxString internal representation: */ +#if wxUSE_UNICODE_UTF8 + typedef char wxStringCharType; +#elif wxUSE_UNICODE_WCHAR + typedef wchar_t wxStringCharType; +#else + typedef char wxStringCharType; +#endif + + /* ------------------------------------------------------------------------- */ /* define _T() and related macros */ /* ------------------------------------------------------------------------- */ diff --git a/include/wx/string.h b/include/wx/string.h index ae60ab5125..2bb59dc033 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -52,7 +52,6 @@ #endif #include "wx/wxchar.h" // for wxChar, wxStrlen() etc. -#include "wx/unichar.h" #include "wx/strvararg.h" #include "wx/buffer.h" // for wxCharBuffer #include "wx/strconv.h" // for wxConvertXXX() macros and wxMBConv classes @@ -83,7 +82,7 @@ class WXDLLIMPEXP_BASE wxString; // deprecated in favour of wxString::npos, don't use in new code // // maximum possible length for a string means "take all string" everywhere -#define wxSTRING_MAXLEN wxStringBase::npos +#define wxSTRING_MAXLEN wxString::npos #endif // WXWIN_COMPATIBILITY_2_6 @@ -180,12 +179,15 @@ inline int Stricmp(const char *psz1, const char *psz2) // FIXME-UTF8: using std::string as wxString base class is currently broken, // so we use the standard wxString with std::string conversion // enabled, this is API-compatible. +#if 1 #define wxUSE_STL_BASED_WXSTRING 0 #if wxUSE_STL #undef wxUSE_STD_STRING #define wxUSE_STD_STRING 1 #endif -//#define wxUSE_STL_BASED_WXSTRING wxUSE_STL +#else +#define wxUSE_STL_BASED_WXSTRING wxUSE_STL +#endif // in both cases we need to define wxStdString #if wxUSE_STL_BASED_WXSTRING || wxUSE_STD_STRING @@ -194,7 +196,7 @@ inline int Stricmp(const char *psz1, const char *psz2) #include #include "wx/afterstd.h" -#if wxUSE_UNICODE +#if wxUSE_UNICODE_WCHAR #ifdef HAVE_STD_WSTRING typedef std::wstring wxStdString; #else @@ -208,23 +210,20 @@ inline int Stricmp(const char *psz1, const char *psz2) #if wxUSE_STL_BASED_WXSTRING - // we don't need an extra ctor from std::string when copy ctor already does - // the work + // we always want ctor from std::string when using std::string internally #undef wxUSE_STD_STRING - #define wxUSE_STD_STRING 0 + #define wxUSE_STD_STRING 1 #if (defined(__GNUG__) && (__GNUG__ < 3)) || \ (defined(_MSC_VER) && (_MSC_VER <= 1200)) #define wxSTRING_BASE_HASNT_CLEAR #endif - typedef wxStdString wxStringBase; + typedef wxStdString wxStringImpl; #else // if !wxUSE_STL_BASED_WXSTRING -#if !defined(HAVE_STD_STRING_COMPARE) && \ - (!defined(__WX_SETUP_H__) || wxUSE_STL_BASED_WXSTRING == 0) - #define HAVE_STD_STRING_COMPARE -#endif +// in non-STL mode, compare() is implemented in wxString and not wxStringImpl +#undef HAVE_STD_STRING_COMPARE // --------------------------------------------------------------------------- // string data prepended with some housekeeping info (used by wxString class), @@ -267,14 +266,15 @@ struct WXDLLIMPEXP_BASE wxStringData bool IsValid() const { return (nRefs != 0); } }; -class WXDLLIMPEXP_BASE wxStringBase +class WXDLLIMPEXP_BASE wxStringImpl { -public : +public: // an 'invalid' value for string index, moved to this place due to a CW bug static const size_t npos; + protected: // points to data preceded by wxStringData structure with ref count info - wxChar *m_pchData; + wxStringCharType *m_pchData; // accessor to string data wxStringData* GetStringData() const { return (wxStringData*)m_pchData - 1; } @@ -282,9 +282,9 @@ protected: // string (re)initialization functions // initializes the string to the empty value (must be called only from // ctors, use Reinit() otherwise) - void Init() { m_pchData = (wxChar *)wxEmptyString; } + void Init() { m_pchData = (wxStringCharType *)wxEmptyString; } // initializes the string with (a part of) C-string - void InitWith(const wxChar *psz, size_t nPos = 0, size_t nLen = npos); + void InitWith(const wxStringCharType *psz, size_t nPos = 0, size_t nLen = npos); // as Init, but also frees old data void Reinit() { GetStringData()->Unlock(); Init(); } @@ -292,11 +292,11 @@ protected: // allocates memory for string of length nLen bool AllocBuffer(size_t nLen); // effectively copies data to string - bool AssignCopy(size_t, const wxChar *); + bool AssignCopy(size_t, const wxStringCharType *); // append a (sub)string - bool ConcatSelf(size_t nLen, const wxChar *src, size_t nMaxLen); - bool ConcatSelf(size_t nLen, const wxChar *src) + bool ConcatSelf(size_t nLen, const wxStringCharType *src, size_t nMaxLen); + bool ConcatSelf(size_t nLen, const wxStringCharType *src) { return ConcatSelf(nLen, src, nLen); } // functions called before writing to the string: they copy it if there @@ -306,179 +306,24 @@ protected: // compatibility with wxString bool Alloc(size_t nLen); + public: // standard types - typedef wxUniChar value_type; - typedef wxUniChar char_type; - typedef wxUniCharRef reference; - typedef wxChar* pointer; - typedef const wxChar* const_pointer; - + typedef wxStringCharType value_type; + typedef wxStringCharType char_type; typedef size_t size_type; - typedef wxUniChar const_reference; - - #define WX_STR_ITERATOR_IMPL(iterator_name, pointer_type, \ - reference_type, reference_ctor) \ - public: \ - typedef wxUniChar value_type; \ - typedef reference_type reference; \ - typedef pointer_type pointer; \ - \ - iterator_name(const iterator_name& i) : m_cur(i.m_cur) {} \ - \ - reference operator*() const { return reference_ctor; } \ - \ - iterator_name& operator++() \ - { ++m_cur; return *this; } \ - iterator_name operator++(int) \ - { iterator_name tmp = *this; ++m_cur; return tmp; } \ - iterator_name& operator--() \ - { --m_cur; return *this; } \ - iterator_name operator--(int) \ - { iterator_name tmp = *this; --m_cur; return tmp; } \ - \ - iterator_name operator+(int n) const \ - { return iterator_name(m_cur + n); } \ - iterator_name operator+(size_t n) const \ - { return iterator_name(m_cur + n); } \ - iterator_name operator-(int n) const \ - { return iterator_name(m_cur - n); } \ - iterator_name operator-(size_t n) const \ - { return iterator_name(m_cur - n); } \ - iterator_name operator+=(int n) \ - { m_cur += n; return *this; } \ - iterator_name operator+=(size_t n) \ - { m_cur += n; return *this; } \ - iterator_name operator-=(int n) \ - { m_cur -= n; return *this; } \ - iterator_name operator-=(size_t n) \ - { m_cur -= n; return *this; } \ - \ - unsigned operator-(const iterator_name& i) const \ - { return m_cur - i.m_cur; } \ - \ - bool operator==(const iterator_name&i) const \ - { return m_cur == i.m_cur; } \ - bool operator!=(const iterator_name& i) const \ - { return m_cur != i.m_cur; } \ - \ - bool operator<(const iterator_name& i) const \ - { return m_cur < i.m_cur; } \ - bool operator>(const iterator_name& i) const \ - { return m_cur > i.m_cur; } \ - bool operator<=(const iterator_name& i) const \ - { return m_cur <= i.m_cur; } \ - bool operator>=(const iterator_name& i) const \ - { return m_cur >= i.m_cur; } \ - \ - protected: \ - /* for internal wxString use only: */ \ - iterator_name(pointer ptr) : m_cur(ptr) {} \ - operator pointer() const { return m_cur; } \ - \ - friend class WXDLLIMPEXP_BASE wxString; \ - friend class WXDLLIMPEXP_BASE wxStringBase; \ - friend class wxCStrData; \ - \ - protected: \ - pointer m_cur; - - class const_iterator; - - class iterator - { - WX_STR_ITERATOR_IMPL(iterator, wxChar*, wxUniCharRef, - wxUniCharRef::CreateForString(m_cur)) - - friend class const_iterator; - }; - - class const_iterator - { - // NB: reference_type is intentionally value, not reference, the character - // may be encoded differently in wxString data: - WX_STR_ITERATOR_IMPL(const_iterator, const wxChar*, wxUniChar, - wxUniChar(*m_cur)) - - public: - const_iterator(const iterator& i) : m_cur(i.m_cur) {} - }; - - #undef WX_STR_ITERATOR - - template - class reverse_iterator_impl - { - public: - typedef T iterator_type; - typedef typename T::value_type value_type; - typedef typename T::reference reference; - typedef typename T::pointer *pointer; - - reverse_iterator_impl(iterator_type i) : m_cur(i) {} - reverse_iterator_impl(const reverse_iterator_impl& ri) - : m_cur(ri.m_cur) {} - - iterator_type base() const { return m_cur; } - - reference operator*() const { return *(m_cur-1); } - - reverse_iterator_impl& operator++() - { --m_cur; return *this; } - reverse_iterator_impl operator++(int) - { reverse_iterator_impl tmp = *this; --m_cur; return tmp; } - reverse_iterator_impl& operator--() - { ++m_cur; return *this; } - reverse_iterator_impl operator--(int) - { reverse_iterator_impl tmp = *this; ++m_cur; return tmp; } - - reverse_iterator_impl operator+(int n) const - { return reverse_iterator_impl(m_cur - n); } - reverse_iterator_impl operator+(size_t n) const - { return reverse_iterator_impl(m_cur - n); } - reverse_iterator_impl operator-(int n) const - { return reverse_iterator_impl(m_cur + n); } - reverse_iterator_impl operator-(size_t n) const - { return reverse_iterator_impl(m_cur + n); } - reverse_iterator_impl operator+=(int n) - { m_cur -= n; return *this; } - reverse_iterator_impl operator+=(size_t n) - { m_cur -= n; return *this; } - reverse_iterator_impl operator-=(int n) - { m_cur += n; return *this; } - reverse_iterator_impl operator-=(size_t n) - { m_cur += n; return *this; } - - unsigned operator-(const reverse_iterator_impl& i) const - { return i.m_cur - m_cur; } - - bool operator==(const reverse_iterator_impl& ri) const - { return m_cur == ri.m_cur; } - bool operator!=(const reverse_iterator_impl& ri) const - { return !(*this == ri); } - - bool operator<(const reverse_iterator_impl& i) const - { return m_cur > i.m_cur; } - bool operator>(const reverse_iterator_impl& i) const - { return m_cur < i.m_cur; } - bool operator<=(const reverse_iterator_impl& i) const - { return m_cur >= i.m_cur; } - bool operator>=(const reverse_iterator_impl& i) const - { return m_cur <= i.m_cur; } - - private: - iterator_type m_cur; - }; - - typedef reverse_iterator_impl reverse_iterator; - typedef reverse_iterator_impl const_reverse_iterator; - + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type *iterator; + typedef const value_type *const_iterator; // constructors and destructor // ctor for an empty string - wxStringBase() { Init(); } + wxStringImpl() { Init(); } // copy ctor - wxStringBase(const wxStringBase& stringSrc) + wxStringImpl(const wxStringImpl& stringSrc) { wxASSERT_MSG( stringSrc.GetStringData()->IsValid(), _T("did you forget to call UngetWriteBuf()?") ); @@ -493,19 +338,15 @@ public: } } // string containing nRepeat copies of ch - wxStringBase(size_type nRepeat, wxUniChar ch); + wxStringImpl(size_type nRepeat, wxStringCharType ch); // ctor takes first nLength characters from C string // (default value of npos means take all the string) - wxStringBase(const wxChar *psz) + wxStringImpl(const wxStringCharType *psz) { InitWith(psz, 0, npos); } - wxStringBase(const wxChar *psz, size_t nLength) - { InitWith(psz, 0, nLength); } - wxStringBase(const wxChar *psz, - const wxMBConv& WXUNUSED(conv), - size_t nLength = npos) + wxStringImpl(const wxStringCharType *psz, size_t nLength) { InitWith(psz, 0, nLength); } // take nLen chars starting at nPos - wxStringBase(const wxStringBase& str, size_t nPos, size_t nLen) + wxStringImpl(const wxStringImpl& str, size_t nPos, size_t nLen) { wxASSERT_MSG( str.GetStringData()->IsValid(), _T("did you forget to call UngetWriteBuf()?") ); @@ -514,10 +355,10 @@ public: InitWith(str.c_str(), nPos, nLen); } // take all characters from pStart to pEnd - wxStringBase(const void *pStart, const void *pEnd); + wxStringImpl(const void *pStart, const void *pEnd); // dtor is not virtual, this class must not be inherited from! - ~wxStringBase() + ~wxStringImpl() { #if defined(__VISUALC__) && (__VISUALC__ >= 1200) //RN - according to the above VC++ does indeed inline this, @@ -534,11 +375,11 @@ public: #endif // overloaded assignment // from another wxString - wxStringBase& operator=(const wxStringBase& stringSrc); + wxStringImpl& operator=(const wxStringImpl& stringSrc); // from a character - wxStringBase& operator=(wxUniChar ch); + wxStringImpl& operator=(wxStringCharType ch); // from a C string - wxStringBase& operator=(const wxChar *psz); + wxStringImpl& operator=(const wxStringCharType *psz); // return the length of the string size_type length() const { return GetStringData()->nDataLength; } @@ -547,7 +388,7 @@ public: // return the maximum size of the string size_type max_size() const { return npos; } // resize the string, filling the space with c if c != 0 - void resize(size_t nSize, wxUniChar ch = wxT('\0')); + void resize(size_t nSize, wxStringCharType ch = '\0'); // delete the contents of the string void clear() { erase(0, npos); } // returns true if the string is empty @@ -565,47 +406,47 @@ public: { wxASSERT_VALID_INDEX( n ); CopyBeforeWrite(); - return wxUniCharRef::CreateForString(&m_pchData[n]); - } + return m_pchData[n]; + } // FIXME-UTF8: not useful for us...? // lib.string.modifiers // append elements str[pos], ..., str[pos+n] - wxStringBase& append(const wxStringBase& str, size_t pos, size_t n) + wxStringImpl& append(const wxStringImpl& str, size_t pos, size_t n) { wxASSERT(pos <= str.length()); ConcatSelf(n, str.c_str() + pos, str.length() - pos); return *this; } // append a string - wxStringBase& append(const wxStringBase& str) + wxStringImpl& append(const wxStringImpl& str) { ConcatSelf(str.length(), str.c_str()); return *this; } // append first n (or all if n == npos) characters of sz - wxStringBase& append(const wxChar *sz) + wxStringImpl& append(const wxStringCharType *sz) { ConcatSelf(wxStrlen(sz), sz); return *this; } - wxStringBase& append(const wxChar *sz, size_t n) + wxStringImpl& append(const wxStringCharType *sz, size_t n) { ConcatSelf(n, sz); return *this; } // append n copies of ch - wxStringBase& append(size_t n, wxUniChar ch); + wxStringImpl& append(size_t n, wxStringCharType ch); // append from first to last - wxStringBase& append(const_iterator first, const_iterator last) + wxStringImpl& append(const_iterator first, const_iterator last) { ConcatSelf(last - first, first); return *this; } // same as `this_string = str' - wxStringBase& assign(const wxStringBase& str) + wxStringImpl& assign(const wxStringImpl& str) { return *this = str; } // same as ` = str[pos..pos + n] - wxStringBase& assign(const wxStringBase& str, size_t pos, size_t n) + wxStringImpl& assign(const wxStringImpl& str, size_t pos, size_t n) { clear(); return append(str, pos, n); } // same as `= first n (or all if n == npos) characters of sz' - wxStringBase& assign(const wxChar *sz) + wxStringImpl& assign(const wxStringCharType *sz) { clear(); return append(sz, wxStrlen(sz)); } - wxStringBase& assign(const wxChar *sz, size_t n) + wxStringImpl& assign(const wxStringCharType *sz, size_t n) { clear(); return append(sz, n); } // same as `= n copies of ch' - wxStringBase& assign(size_t n, wxUniChar ch) + wxStringImpl& assign(size_t n, wxStringCharType ch) { clear(); return append(n, ch); } // assign from first to last - wxStringBase& assign(const_iterator first, const_iterator last) + wxStringImpl& assign(const_iterator first, const_iterator last) { clear(); return append(first, last); } // first valid index position @@ -615,21 +456,14 @@ public: const_iterator end() const { return m_pchData + length(); } iterator end(); - // first element of the reversed string - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } - reverse_iterator rbegin() { return reverse_iterator(end()); } - // one beyond the end of the reversed string - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - // insert another string - wxStringBase& insert(size_t nPos, const wxStringBase& str) + wxStringImpl& insert(size_t nPos, const wxStringImpl& str) { wxASSERT( str.GetStringData()->IsValid() ); return insert(nPos, str.c_str(), str.length()); } // insert n chars of str starting at nStart (in str) - wxStringBase& insert(size_t nPos, const wxStringBase& str, size_t nStart, size_t n) + wxStringImpl& insert(size_t nPos, const wxStringImpl& str, size_t nStart, size_t n) { wxASSERT( str.GetStringData()->IsValid() ); wxASSERT( nStart < str.length() ); @@ -638,19 +472,19 @@ public: return insert(nPos, str.c_str() + nStart, n); } // insert first n (or all if n == npos) characters of sz - wxStringBase& insert(size_t nPos, const wxChar *sz, size_t n = npos); + wxStringImpl& insert(size_t nPos, const wxStringCharType *sz, size_t n = npos); // insert n copies of ch - wxStringBase& insert(size_t nPos, size_t n, wxUniChar ch) - { return insert(nPos, wxStringBase(n, ch)); } - iterator insert(iterator it, wxUniChar ch) + wxStringImpl& insert(size_t nPos, size_t n, wxStringCharType ch)// FIXME-UTF8: tricky + { return insert(nPos, wxStringImpl(n, ch)); } + iterator insert(iterator it, wxStringCharType ch) // FIXME-UTF8: tricky { size_t idx = it - begin(); insert(idx, 1, ch); return begin() + idx; } void insert(iterator it, const_iterator first, const_iterator last) { insert(it - begin(), first, last - first); } - void insert(iterator it, size_type n, wxUniChar ch) + void insert(iterator it, size_type n, wxStringCharType ch) { insert(it - begin(), n, ch); } // delete characters from nStart to nStart + nLen - wxStringBase& erase(size_type pos = 0, size_type n = npos); + wxStringImpl& erase(size_type pos = 0, size_type n = npos); iterator erase(iterator first, iterator last) { size_t idx = first - begin(); @@ -660,138 +494,92 @@ public: iterator erase(iterator first); // explicit conversion to C string (use this with printf()!) - const wxChar* c_str() const { return m_pchData; } - const wxChar* data() const { return m_pchData; } + const wxStringCharType* c_str() const { return m_pchData; } + const wxStringCharType* data() const { return m_pchData; } // replaces the substring of length nLen starting at nStart - wxStringBase& replace(size_t nStart, size_t nLen, const wxChar* sz); + wxStringImpl& replace(size_t nStart, size_t nLen, const wxStringCharType* sz); // replaces the substring of length nLen starting at nStart - wxStringBase& replace(size_t nStart, size_t nLen, const wxStringBase& str) + wxStringImpl& replace(size_t nStart, size_t nLen, const wxStringImpl& str) { return replace(nStart, nLen, str.c_str()); } // replaces the substring with nCount copies of ch - wxStringBase& replace(size_t nStart, size_t nLen, size_t nCount, wxUniChar ch); + wxStringImpl& replace(size_t nStart, size_t nLen, size_t nCount, wxStringCharType ch); // replaces a substring with another substring - wxStringBase& replace(size_t nStart, size_t nLen, - const wxStringBase& str, size_t nStart2, size_t nLen2); + wxStringImpl& replace(size_t nStart, size_t nLen, + const wxStringImpl& str, size_t nStart2, size_t nLen2); // replaces the substring with first nCount chars of sz - wxStringBase& replace(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount); - wxStringBase& replace(iterator first, iterator last, const_pointer s) + wxStringImpl& replace(size_t nStart, size_t nLen, + const wxStringCharType* sz, size_t nCount); + wxStringImpl& replace(iterator first, iterator last, const_pointer s) { return replace(first - begin(), last - first, s); } - wxStringBase& replace(iterator first, iterator last, const_pointer s, + wxStringImpl& replace(iterator first, iterator last, const_pointer s, size_type n) { return replace(first - begin(), last - first, s, n); } - wxStringBase& replace(iterator first, iterator last, const wxStringBase& s) + wxStringImpl& replace(iterator first, iterator last, const wxStringImpl& s) { return replace(first - begin(), last - first, s); } - wxStringBase& replace(iterator first, iterator last, size_type n, wxUniChar c) + wxStringImpl& replace(iterator first, iterator last, size_type n, wxStringCharType c) { return replace(first - begin(), last - first, n, c); } - wxStringBase& replace(iterator first, iterator last, + wxStringImpl& replace(iterator first, iterator last, const_iterator first1, const_iterator last1) { return replace(first - begin(), last - first, first1, last1 - first1); } // swap two strings - void swap(wxStringBase& str); + void swap(wxStringImpl& str); // All find() functions take the nStart argument which specifies the // position to start the search on, the default value is 0. All functions // return npos if there were no match. // find a substring - size_t find(const wxStringBase& str, size_t nStart = 0) const; + size_t find(const wxStringImpl& str, size_t nStart = 0) const; // find first n characters of sz - size_t find(const wxChar* sz, size_t nStart = 0, size_t n = npos) const; + size_t find(const wxStringCharType* sz, size_t nStart = 0, size_t n = npos) const; // find the first occurence of character ch after nStart - size_t find(wxUniChar ch, size_t nStart = 0) const; + size_t find(wxStringCharType ch, size_t nStart = 0) const; // rfind() family is exactly like find() but works right to left // as find, but from the end - size_t rfind(const wxStringBase& str, size_t nStart = npos) const; + size_t rfind(const wxStringImpl& str, size_t nStart = npos) const; // as find, but from the end - size_t rfind(const wxChar* sz, size_t nStart = npos, + size_t rfind(const wxStringCharType* sz, size_t nStart = npos, size_t n = npos) const; // as find, but from the end - size_t rfind(wxUniChar ch, size_t nStart = npos) const; - - // find first/last occurence of any character in the set - - // as strpbrk() but starts at nStart, returns npos if not found - size_t find_first_of(const wxStringBase& str, size_t nStart = 0) const - { return find_first_of(str.c_str(), nStart); } - // same as above - size_t find_first_of(const wxChar* sz, size_t nStart = 0) const; - size_t find_first_of(const wxChar* sz, size_t nStart, size_t n) const; - // same as find(char, size_t) - size_t find_first_of(wxUniChar c, size_t nStart = 0) const - { return find(c, nStart); } - // find the last (starting from nStart) char from str in this string - size_t find_last_of (const wxStringBase& str, size_t nStart = npos) const - { return find_last_of(str.c_str(), nStart); } - // same as above - size_t find_last_of (const wxChar* sz, size_t nStart = npos) const; - size_t find_last_of(const wxChar* sz, size_t nStart, size_t n) const; - // same as above - size_t find_last_of(wxUniChar c, size_t nStart = npos) const - { return rfind(c, nStart); } + size_t rfind(wxStringCharType ch, size_t nStart = npos) const; - // find first/last occurence of any character not in the set - - // as strspn() (starting from nStart), returns npos on failure - size_t find_first_not_of(const wxStringBase& str, size_t nStart = 0) const - { return find_first_not_of(str.c_str(), nStart); } - // same as above - size_t find_first_not_of(const wxChar* sz, size_t nStart = 0) const; - size_t find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const; - // same as above - size_t find_first_not_of(wxUniChar ch, size_t nStart = 0) const; - // as strcspn() - size_t find_last_not_of(const wxStringBase& str, size_t nStart = npos) const - { return find_last_not_of(str.c_str(), nStart); } - // same as above - size_t find_last_not_of(const wxChar* sz, size_t nStart = npos) const; - size_t find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const; - // same as above - size_t find_last_not_of(wxUniChar ch, size_t nStart = npos) const; - - // All compare functions return -1, 0 or 1 if the [sub]string is less, - // equal or greater than the compare() argument. - - // comparison with another string - int compare(const wxStringBase& str) const; - // comparison with a substring - int compare(size_t nStart, size_t nLen, const wxStringBase& str) const; - // comparison of 2 substrings - int compare(size_t nStart, size_t nLen, - const wxStringBase& str, size_t nStart2, size_t nLen2) const; - // comparison with a c string - int compare(const wxChar* sz) const; - // substring comparison with first nCount characters of sz - int compare(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount = npos) const; - - size_type copy(wxChar* s, size_type n, size_type pos = 0); + size_type copy(wxStringCharType* s, size_type n, size_type pos = 0); // substring extraction - wxStringBase substr(size_t nStart = 0, size_t nLen = npos) const; + wxStringImpl substr(size_t nStart = 0, size_t nLen = npos) const; // string += string - wxStringBase& operator+=(const wxStringBase& s) { return append(s); } + wxStringImpl& operator+=(const wxStringImpl& s) { return append(s); } // string += C string - wxStringBase& operator+=(const wxChar *psz) { return append(psz); } + wxStringImpl& operator+=(const wxStringCharType *psz) { return append(psz); } // string += char - wxStringBase& operator+=(wxUniChar ch) { return append(1, ch); } - wxStringBase& operator+=(wxUniCharRef ch) { return append(1, ch); } - wxStringBase& operator+=(char ch) { return append(1, ch); } - wxStringBase& operator+=(wchar_t ch) { return append(1, ch); } + wxStringImpl& operator+=(wxStringCharType ch) { return append(1, ch); } + +#if !wxUSE_UNICODE_UTF8 + // helpers for wxStringBuffer and wxStringBufferLength + wxStringCharType *DoGetWriteBuf(size_t nLen); + void DoUngetWriteBuf(); + void DoUngetWriteBuf(size_t nLen); +#endif + + friend class WXDLLIMPEXP_BASE wxString; }; +#endif // !wxUSE_STL_BASED_WXSTRING + // don't pollute the library user's name space #undef wxASSERT_VALID_INDEX -#endif // !wxUSE_STL_BASED_WXSTRING +// wx/unichar.h needs wxStringImpl, so it's only possible to include it here +// (it includes string.h if not included from string.h): +#include "wx/unichar.h" // ---------------------------------------------------------------------------- // wxCStrData @@ -938,14 +726,20 @@ protected: #pragma warning (disable:4275) #endif -class WXDLLIMPEXP_BASE wxString : public wxStringBase +class WXDLLIMPEXP_BASE wxString #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN - ,public wxStringPrintfMixin + : public wxStringPrintfMixin #endif { // NB: special care was taken in arranging the member functions in such order // that all inline functions can be effectively inlined, verify that all // performance critical functions are still inlined if you change order! +public: +#if !wxUSE_STL_BASED_WXSTRING + // an 'invalid' value for string index, moved to this place due to a CW bug + static const size_t npos; +#endif + private: // if we hadn't made these operators private, it would be possible to // compile "wxString s; s = 17;" without any warnings as 17 is implicitly @@ -956,94 +750,461 @@ private: // ambiguity between operator=(char) and operator=(int) wxString& operator=(int); - // these methods are not implemented - there is _no_ conversion from int to - // string, you're doing something wrong if the compiler wants to call it! - // - // try `s << i' or `s.Printf("%d", i)' instead - wxString(int); + // these methods are not implemented - there is _no_ conversion from int to + // string, you're doing something wrong if the compiler wants to call it! + // + // try `s << i' or `s.Printf("%d", i)' instead + wxString(int); + + + // buffer for holding temporary substring when using any of the methods + // that take (char*,size_t) or (wchar_t*,size_t) arguments: + // FIXME-UTF8: This will need changes when UTF8 build is introduced + template + struct SubstrBufFromType + { + T data; + size_t len; + + SubstrBufFromType() {} + SubstrBufFromType(const T& data_, size_t len_) + : data(data_), len(len_) {} + }; + +#if wxUSE_UNICODE_UTF8 + // FIXME-UTF8: this will have to use slightly different type +#elif wxUSE_UNICODE_WCHAR + typedef SubstrBufFromType SubstrBufFromWC; + typedef SubstrBufFromType SubstrBufFromMB; + typedef SubstrBufFromWC SubstrBufFrom; +#else + typedef SubstrBufFromType SubstrBufFromMB; + typedef SubstrBufFromType SubstrBufFromWC; + typedef SubstrBufFromMB SubstrBufFrom; +#endif + + + // Functions implementing primitive operations on string data; wxString + // methods and iterators are implemented in terms of it. The differences + // between UTF-8 and wchar_t* representations of the string are mostly + // contained here. + +#if wxUSE_UNICODE + // FIXME-UTF8: This will need changes when UTF8 build is introduced + static SubstrBufFromMB ConvertStr(const char *psz, size_t nLength, + const wxMBConv& conv); +#else + static SubstrBufFromWC ConvertStr(const wchar_t *pwz, size_t nLength, + const wxMBConv& conv); +#endif + +#if !wxUSE_UNICODE_UTF8 // wxUSE_UNICODE_WCHAR or !wxUSE_UNICODE + // returns C string encoded as the implementation expects (version for + // the same char type as used internally) + static const wxStringCharType* ImplStr(const wxStringCharType* str) + { return str; } + static const SubstrBufFrom ImplStr(const wxStringCharType* str, size_t n) + { return SubstrBufFrom(str, n); } + #if wxUSE_UNICODE + // returns C string encoded as the implementation expects (version for + // the other char type than the one used internally) + static wxWCharBuffer ImplStr(const char* str) + { return ConvertStr(str, npos, wxConvLibc).data; } + static SubstrBufFromMB ImplStr(const char* str, size_t n) + { return ConvertStr(str, n, wxConvLibc); } + #else + static wxCharBuffer ImplStr(const wchar_t* str) + { return ConvertStr(str, npos, wxConvLibc).data; } + static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n) + { return ConvertStr(str, n, wxConvLibc); } + #endif + + // moves the iterator to the next Unicode character + static void IncIter(wxStringImpl::iterator& i) { ++i; } + static void IncIter(wxStringImpl::const_iterator& i) { ++i; } + // moves the iterator to the previous Unicode character + static void DecIter(wxStringImpl::iterator& i) { --i; } + static void DecIter(wxStringImpl::const_iterator& i) { --i; } + // moves the iterator by n Unicode characters + static wxStringImpl::iterator AddToIter(wxStringImpl::iterator i, int n) + { return i + n; } + static wxStringImpl::const_iterator AddToIter(wxStringImpl::const_iterator i, int n) + { return i + n; } + // returns distance of the two iterators in Unicode characters + static int DiffIters(wxStringImpl::iterator i1, wxStringImpl::iterator i2) + { return i1 - i2; } + static int DiffIters(wxStringImpl::const_iterator i1, wxStringImpl::const_iterator i2) + { return i1 - i2; } + + // encodes the character to a form used to represent it in internal + // representation (returns a string in UTF8 version) + static wxChar EncodeChar(wxUniChar ch) { return (wxChar)ch; } + + // translates position index in wxString to/from index in underlying + // wxStringImpl: + static size_t PosToImpl(size_t pos) { return pos; } + static void PosLenToImpl(size_t pos, size_t len, + size_t *implPos, size_t *implLen) + { *implPos = pos; *implLen = len; } + static size_t PosFromImpl(size_t pos) { return pos; } + +#else // wxUSE_UNICODE_UTF8 + + typedef char Utf8CharBuffer[5]; + static Utf8CharBuffer EncodeChar(wxUniChar ch); + // returns n copies of ch encoded in UTF-8 string + static wxCharBuffer EncodeNChars(size_t n, wxUniChar ch); + + size_t PosToImpl(size_t pos) const + { + if ( pos == 0 || pos == npos ) + return pos; + else + return wxStringImpl::const_iterator(begin() + pos) - m_impl.begin(); + } + + size_t PosFromImpl(size_t pos) const + { + if ( pos == 0 || pos == npos ) + return pos; + else + return const_iterator(m_impl.begin() + pos) - begin(); + } + + // FIXME: return as-is without copying under UTF8 locale, return + // converted string under other locales - needs wxCharBuffer + // changes + static wxCharBuffer ImplStr(const char* str); + + static wxCharBuffer ImplStr(const wchar_t* str) + { return wxConvUTF8.cWC2MB(str); } +#endif // !wxUSE_UNICODE_UTF8/wxUSE_UNICODE_UTF8 + + +public: + // constructors and destructor + // ctor for an empty string + wxString() {} + // copy ctor + wxString(const wxStringImpl& stringSrc) : m_impl(stringSrc) { } + wxString(const wxString& stringSrc) : m_impl(stringSrc) { } + // string containing nRepeat copies of ch + wxString(wxUniChar ch, size_t nRepeat = 1) + : m_impl(nRepeat, ch) { } + wxString(size_t nRepeat, wxUniChar ch) + : m_impl(nRepeat, ch) { } + wxString(wxUniCharRef ch, size_t nRepeat = 1) + : m_impl(nRepeat, ch) { } + wxString(size_t nRepeat, wxUniCharRef ch) + : m_impl(nRepeat, ch) { } + wxString(char ch, size_t nRepeat = 1) + : m_impl(nRepeat, ch) { } + wxString(size_t nRepeat, char ch) + : m_impl(nRepeat, ch) { } + wxString(wchar_t ch, size_t nRepeat = 1) + : m_impl(nRepeat, ch) { } + wxString(size_t nRepeat, wchar_t ch) + : m_impl(nRepeat, ch) { } + // ctor takes first nLength characters from C string + // (default value of npos means take all the string) + wxString(const wxChar *psz) + : m_impl(psz ? psz : wxT("")) { } + wxString(const wxChar *psz, size_t nLength) + : m_impl(psz, nLength) { } + wxString(const wxChar *psz, + const wxMBConv& WXUNUSED(conv), + size_t nLength = npos) + : m_impl(psz, nLength == npos ? wxStrlen(psz) : nLength) { } + + // even if we're not built with wxUSE_STL == 1 it is very convenient to allow + // implicit conversions from std::string to wxString as this allows to use + // the same strings in non-GUI and GUI code, however we don't want to + // unconditionally add this ctor as it would make wx lib dependent on + // libstdc++ on some Linux versions which is bad, so instead we ask the + // client code to define this wxUSE_STD_STRING symbol if they need it +#if wxUSE_STD_STRING + wxString(const wxStdString& s) + : m_impl(s.c_str()) { } +#endif // wxUSE_STD_STRING + +#if wxUSE_UNICODE + // from multibyte string + wxString(const char *psz, + const wxMBConv& conv = wxConvLibc, + size_t nLength = npos); + // from multibyte string for ANSI compatibility, with wxConvLibc + wxString(const char *psz, size_t nLength); + // from wxWCharBuffer (i.e. return from wxGetString) + wxString(const wxWCharBuffer& psz) : m_impl(psz.data()) { } +#else // ANSI + // from C string (for compilers using unsigned char) + wxString(const unsigned char* psz) + : m_impl((const char*)psz) { } + // from part of C string (for compilers using unsigned char) + wxString(const unsigned char* psz, size_t nLength) + : m_impl((const char*)psz, nLength) { } + +#if wxUSE_WCHAR_T + // from wide (Unicode) string + wxString(const wchar_t *pwz, + const wxMBConv& conv = wxConvLibc, + size_t nLength = npos); + // from wide string for Unicode compatibility, with wxConvLibc + wxString(const wchar_t *pwz, size_t nLength); +#endif // !wxUSE_WCHAR_T + + // from wxCharBuffer + wxString(const wxCharBuffer& psz) + : m_impl(psz) { } +#endif // Unicode/ANSI + + // as we provide both ctors with this signature for both char and unsigned + // char string, we need to provide one for wxCStrData to resolve ambiguity + wxString(const wxCStrData& cstr, size_t nLength) + { assign(cstr.AsString(), nLength); } + + // and because wxString is convertible to wxCStrData and const wxChar * + // we also need to provide this one + wxString(const wxString& str, size_t nLength) + { assign(str, nLength); } + +public: + // standard types + typedef wxUniChar value_type; + typedef wxUniChar char_type; + typedef wxUniCharRef reference; + typedef wxChar* pointer; + typedef const wxChar* const_pointer; + + typedef size_t size_type; + typedef wxUniChar const_reference; + + #define WX_STR_ITERATOR_IMPL(iterator_name, pointer_type, \ + reference_type, reference_ctor) \ + private: \ + typedef wxStringImpl::iterator_name underlying_iterator; \ + public: \ + typedef wxUniChar value_type; \ + typedef reference_type reference; \ + typedef pointer_type pointer; \ + \ + iterator_name(const iterator_name& i) : m_cur(i.m_cur) {} \ + \ + reference operator*() const { return reference_ctor; } \ + \ + iterator_name& operator++() \ + { wxString::IncIter(m_cur); return *this; } \ + iterator_name& operator--() \ + { wxString::DecIter(m_cur); return *this; } \ + iterator_name operator++(int) \ + { \ + iterator_name tmp = *this; \ + wxString::IncIter(m_cur); \ + return tmp; \ + } \ + iterator_name operator--(int) \ + { \ + iterator_name tmp = *this; \ + wxString::DecIter(m_cur); \ + return tmp; \ + } \ + \ + iterator_name operator+(int n) const \ + { return iterator_name(wxString::AddToIter(m_cur, n)); } \ + iterator_name operator+(size_t n) const \ + { return iterator_name(wxString::AddToIter(m_cur, (int)n)); } \ + iterator_name operator-(int n) const \ + { return iterator_name(wxString::AddToIter(m_cur, -n)); } \ + iterator_name operator-(size_t n) const \ + { return iterator_name(wxString::AddToIter(m_cur, -(int)n)); } \ + iterator_name operator+=(int n) \ + { m_cur = wxString::AddToIter(m_cur, n); return *this; } \ + iterator_name operator+=(size_t n) \ + { m_cur = wxString::AddToIter(m_cur, (int)n); return *this; } \ + iterator_name operator-=(int n) \ + { m_cur = wxString::AddToIter(m_cur, -n); return *this; } \ + iterator_name operator-=(size_t n) \ + { m_cur = wxString::AddToIter(m_cur, -(int)n); return *this; } \ + \ + unsigned operator-(const iterator_name& i) const \ + { return wxString::DiffIters(m_cur, i.m_cur); } \ + \ + bool operator==(const iterator_name&i) const \ + { return m_cur == i.m_cur; } \ + bool operator!=(const iterator_name& i) const \ + { return m_cur != i.m_cur; } \ + \ + bool operator<(const iterator_name& i) const \ + { return m_cur < i.m_cur; } \ + bool operator>(const iterator_name& i) const \ + { return m_cur > i.m_cur; } \ + bool operator<=(const iterator_name& i) const \ + { return m_cur <= i.m_cur; } \ + bool operator>=(const iterator_name& i) const \ + { return m_cur >= i.m_cur; } \ + \ + private: \ + /* for internal wxString use only: */ \ + iterator_name(underlying_iterator ptr) : m_cur(ptr) {} \ + operator underlying_iterator() const { return m_cur; } \ + \ + friend class WXDLLIMPEXP_BASE wxString; \ + friend class WXDLLIMPEXP_BASE wxStringImpl; \ + friend class WXDLLIMPEXP_BASE wxCStrData; \ + \ + private: \ + underlying_iterator m_cur; + + class const_iterator; + + class iterator + { + WX_STR_ITERATOR_IMPL(iterator, wxChar*, wxUniCharRef, + wxUniCharRef::CreateForString(m_cur)) + + friend class const_iterator; + }; + + class const_iterator + { + // NB: reference_type is intentionally value, not reference, the character + // may be encoded differently in wxString data: + WX_STR_ITERATOR_IMPL(const_iterator, const wxChar*, wxUniChar, + wxUniChar(*m_cur)) + + public: + const_iterator(const iterator& i) : m_cur(i.m_cur) {} + }; + + #undef WX_STR_ITERATOR_IMPL + + friend class iterator; + friend class const_iterator; + + template + class reverse_iterator_impl + { + public: + typedef T iterator_type; + typedef typename T::value_type value_type; + typedef typename T::reference reference; + typedef typename T::pointer *pointer; + + reverse_iterator_impl(iterator_type i) : m_cur(i) {} + reverse_iterator_impl(const reverse_iterator_impl& ri) + : m_cur(ri.m_cur) {} + + iterator_type base() const { return m_cur; } + + reference operator*() const { return *(m_cur-1); } + + reverse_iterator_impl& operator++() + { --m_cur; return *this; } + reverse_iterator_impl operator++(int) + { reverse_iterator_impl tmp = *this; --m_cur; return tmp; } + reverse_iterator_impl& operator--() + { ++m_cur; return *this; } + reverse_iterator_impl operator--(int) + { reverse_iterator_impl tmp = *this; ++m_cur; return tmp; } + + reverse_iterator_impl operator+(int n) const + { return reverse_iterator_impl(m_cur - n); } + reverse_iterator_impl operator+(size_t n) const + { return reverse_iterator_impl(m_cur - n); } + reverse_iterator_impl operator-(int n) const + { return reverse_iterator_impl(m_cur + n); } + reverse_iterator_impl operator-(size_t n) const + { return reverse_iterator_impl(m_cur + n); } + reverse_iterator_impl operator+=(int n) + { m_cur -= n; return *this; } + reverse_iterator_impl operator+=(size_t n) + { m_cur -= n; return *this; } + reverse_iterator_impl operator-=(int n) + { m_cur += n; return *this; } + reverse_iterator_impl operator-=(size_t n) + { m_cur += n; return *this; } + + unsigned operator-(const reverse_iterator_impl& i) const + { return i.m_cur - m_cur; } + + bool operator==(const reverse_iterator_impl& ri) const + { return m_cur == ri.m_cur; } + bool operator!=(const reverse_iterator_impl& ri) const + { return !(*this == ri); } + + bool operator<(const reverse_iterator_impl& i) const + { return m_cur > i.m_cur; } + bool operator>(const reverse_iterator_impl& i) const + { return m_cur < i.m_cur; } + bool operator<=(const reverse_iterator_impl& i) const + { return m_cur >= i.m_cur; } + bool operator>=(const reverse_iterator_impl& i) const + { return m_cur <= i.m_cur; } + + private: + iterator_type m_cur; + }; -public: - // constructors and destructor - // ctor for an empty string - wxString() : wxStringBase() { } - // copy ctor - wxString(const wxStringBase& stringSrc) : wxStringBase(stringSrc) { } - wxString(const wxString& stringSrc) : wxStringBase(stringSrc) { } - // string containing nRepeat copies of ch - wxString(wxUniChar ch, size_t nRepeat = 1) - : wxStringBase(nRepeat, ch) { } - wxString(size_t nRepeat, wxUniChar ch) - : wxStringBase(nRepeat, ch) { } - wxString(wxUniCharRef ch, size_t nRepeat = 1) - : wxStringBase(nRepeat, ch) { } - wxString(size_t nRepeat, wxUniCharRef ch) - : wxStringBase(nRepeat, ch) { } - wxString(char ch, size_t nRepeat = 1) - : wxStringBase(nRepeat, ch) { } - wxString(size_t nRepeat, char ch) - : wxStringBase(nRepeat, ch) { } - wxString(wchar_t ch, size_t nRepeat = 1) - : wxStringBase(nRepeat, ch) { } - wxString(size_t nRepeat, wchar_t ch) - : wxStringBase(nRepeat, ch) { } - // ctor takes first nLength characters from C string - // (default value of npos means take all the string) - wxString(const wxChar *psz) - : wxStringBase(psz ? psz : wxT("")) { } - wxString(const wxChar *psz, size_t nLength) - : wxStringBase(psz, nLength) { } - wxString(const wxChar *psz, - const wxMBConv& WXUNUSED(conv), - size_t nLength = npos) - : wxStringBase(psz, nLength == npos ? wxStrlen(psz) : nLength) { } + typedef reverse_iterator_impl reverse_iterator; + typedef reverse_iterator_impl const_reverse_iterator; - // even if we're not built with wxUSE_STL == 1 it is very convenient to allow - // implicit conversions from std::string to wxString as this allows to use - // the same strings in non-GUI and GUI code, however we don't want to - // unconditionally add this ctor as it would make wx lib dependent on - // libstdc++ on some Linux versions which is bad, so instead we ask the - // client code to define this wxUSE_STD_STRING symbol if they need it -#if wxUSE_STD_STRING - wxString(const wxStdString& s) - : wxStringBase(s.c_str()) { } -#endif // wxUSE_STD_STRING + // first valid index position + const_iterator begin() const { return const_iterator(m_impl.begin()); } + iterator begin() { return iterator(m_impl.begin()); } + // position one after the last valid one + const_iterator end() const { return const_iterator(m_impl.end()); } + iterator end() { return iterator(m_impl.end()); } + + // first element of the reversed string + const_reverse_iterator rbegin() const + { return const_reverse_iterator(end()); } + reverse_iterator rbegin() + { return reverse_iterator(end()); } + // one beyond the end of the reversed string + const_reverse_iterator rend() const + { return const_reverse_iterator(begin()); } + reverse_iterator rend() + { return reverse_iterator(begin()); } + + // std::string methods: +#if wxUSE_UNICODE_UTF8 + size_t length() const { return end() - begin(); } // FIXME-UTF8: optimize! +#else + size_t length() const { return m_impl.length(); } +#endif -#if wxUSE_UNICODE - // from multibyte string - wxString(const char *psz, - const wxMBConv& conv = wxConvLibc, - size_t nLength = npos); - // from wxWCharBuffer (i.e. return from wxGetString) - wxString(const wxWCharBuffer& psz) : wxStringBase(psz.data()) { } -#else // ANSI - // from C string (for compilers using unsigned char) - wxString(const unsigned char* psz) - : wxStringBase((const char*)psz) { } - // from part of C string (for compilers using unsigned char) - wxString(const unsigned char* psz, size_t nLength) - : wxStringBase((const char*)psz, nLength) { } + size_type size() const { return length(); } + size_type max_size() const { return npos; } - // as we provide both ctors with this signature for both char and unsigned - // char string, we need to provide one for wxCStrData to resolve ambiguity - wxString(const wxCStrData& cstr, size_t nLength) - : wxStringBase(cstr.AsChar(), nLength) { } + bool empty() const { return m_impl.empty(); } - // and because wxString is convertible to wxCStrData and const wxChar * - // we also need to provide this one - wxString(const wxString& str, size_t nLength) - : wxStringBase(str, 0, nLength) { } + size_type capacity() const { return m_impl.capacity(); } // FIXME-UTF8 + void reserve(size_t sz) { m_impl.reserve(sz); } // FIXME-UTF8 -#if wxUSE_WCHAR_T - // from wide (Unicode) string - wxString(const wchar_t *pwz, - const wxMBConv& conv = wxConvLibc, - size_t nLength = npos); -#endif // !wxUSE_WCHAR_T + void resize(size_t nSize, wxUniChar ch = wxT('\0')) + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + { + size_t len = length(); + if ( nSize == len) + return; + else if ( nSize < len ) + erase(nSize); + else + append(nSize - len, ch); + } + else +#endif + m_impl.resize(nSize, (wxStringCharType)ch); + } - // from wxCharBuffer - wxString(const wxCharBuffer& psz) - : wxStringBase(psz) { } -#endif // Unicode/ANSI + wxString substr(size_t nStart = 0, size_t nLen = npos) const + { + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + return m_impl.substr(pos, len); + } // generic attributes & operations // as standard strlen() @@ -1078,9 +1239,13 @@ public: // data access (all indexes are 0 based) // read access + wxUniChar at(size_t n) const + { return *(begin() + n); } // FIXME-UTF8: optimize? wxUniChar GetChar(size_t n) const { return at(n); } // read/write access + wxUniCharRef at(size_t n) + { return *(begin() + n); } // FIXME-UTF8: optimize? wxUniCharRef GetWritableChar(size_t n) { return at(n); } // write access @@ -1088,7 +1253,7 @@ public: { at(n) = ch; } // get last character - wxUniChar Last() const + wxUniChar Last() const { wxASSERT_MSG( !empty(), _T("wxString: index out of bounds") ); @@ -1107,30 +1272,31 @@ public: ambiguity when using str[0]. */ wxUniChar operator[](int n) const - { return wxStringBase::at(n); } + { return at(n); } wxUniChar operator[](long n) const - { return wxStringBase::at(n); } + { return at(n); } wxUniChar operator[](size_t n) const - { return wxStringBase::at(n); } + { return at(n); } #ifndef wxSIZE_T_IS_UINT wxUniChar operator[](unsigned int n) const - { return wxStringBase::at(n); } + { return at(n); } #endif // size_t != unsigned int // operator versions of GetWriteableChar() wxUniCharRef operator[](int n) - { return wxStringBase::at(n); } + { return at(n); } wxUniCharRef operator[](long n) - { return wxStringBase::at(n); } + { return at(n); } wxUniCharRef operator[](size_t n) - { return wxStringBase::at(n); } + { return at(n); } #ifndef wxSIZE_T_IS_UINT wxUniCharRef operator[](unsigned int n) - { return wxStringBase::at(n); } + { return at(n); } #endif // size_t != unsigned int // explicit conversion to C string (use this with printf()!) wxCStrData c_str() const { return wxCStrData(this); } + wxCStrData data() const { return c_str(); } // implicit conversion to C string operator wxCStrData() const { return c_str(); } @@ -1141,7 +1307,7 @@ public: // explicit conversion to C string in internal representation (char*, // wchar_t*, UTF-8-encoded char*, depending on the build): - const_pointer wx_str() const { return data(); } + const_pointer wx_str() const { return m_impl.c_str(); } // conversion to/from plain (i.e. 7 bit) ASCII: this is useful for // converting numbers or strings which are certain not to contain special @@ -1203,32 +1369,33 @@ public: // overloaded assignment // from another wxString - wxString& operator=(const wxStringBase& stringSrc) - { return (wxString&)wxStringBase::operator=(stringSrc); } - wxString& operator=(const wxCStrData& cstr); + wxString& operator=(const wxStringImpl& stringSrc) + { m_impl = stringSrc; return *this; } + wxString& operator=(const wxCStrData& cstr) + { return *this = cstr.AsString(); } // from a character wxString& operator=(wxUniChar ch) - { return (wxString&)wxStringBase::operator=(ch); } + { m_impl = EncodeChar(ch); return *this; } wxString& operator=(wxUniCharRef ch) - { return (wxString&)wxStringBase::operator=((wxUniChar)ch); } + { return operator=((wxUniChar)ch); } wxString& operator=(char ch) - { return (wxString&)wxStringBase::operator=(wxUniChar(ch)); } + { return operator=(wxUniChar(ch)); } wxString& operator=(wchar_t ch) - { return (wxString&)wxStringBase::operator=(wxUniChar(ch)); } + { return operator=(wxUniChar(ch)); } // from a C string - STL probably will crash on NULL, // so we need to compensate in that case #if wxUSE_STL_BASED_WXSTRING wxString& operator=(const wxChar *psz) - { if(psz) wxStringBase::operator=(psz); else Clear(); return *this; } + { if(psz) m_impl = psz; else Clear(); return *this; } #else wxString& operator=(const wxChar *psz) - { return (wxString&)wxStringBase::operator=(psz); } + { m_impl = psz; return *this; } #endif #if wxUSE_UNICODE // from wxWCharBuffer - wxString& operator=(const wxWCharBuffer& psz) - { (void) operator=((const wchar_t *)psz); return *this; } + wxString& operator=(const wxWCharBuffer& s) + { (void) operator=((const wchar_t *)s); return *this; } // from C string wxString& operator=(const char* psz) { return operator=(wxString(psz)); } @@ -1254,8 +1421,8 @@ public: // string += string wxString& operator<<(const wxString& s) { -#if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL - wxASSERT_MSG( s.GetStringData()->IsValid(), +#if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 + wxASSERT_MSG( s.IsValid(), _T("did you forget to call UngetWriteBuf()?") ); #endif @@ -1263,10 +1430,12 @@ public: return *this; } // string += C string - wxString& operator<<(const wxChar *psz) + wxString& operator<<(const char *psz) { append(psz); return *this; } + wxString& operator<<(const wchar_t *pwz) + { append(pwz); return *this; } wxString& operator<<(const wxCStrData& psz) - { append(psz); return *this; } + { append(psz.AsString()); return *this; } // string += char wxString& operator<<(wxUniChar ch) { append(1, ch); return *this; } wxString& operator<<(wxUniCharRef ch) { append(1, ch); return *this; } @@ -1274,25 +1443,15 @@ public: wxString& operator<<(wchar_t ch) { append(1, ch); return *this; } // string += buffer (i.e. from wxGetString) -#if wxUSE_UNICODE wxString& operator<<(const wxWCharBuffer& s) { return operator<<((const wchar_t *)s); } wxString& operator+=(const wxWCharBuffer& s) { return operator<<((const wchar_t *)s); } -#else // !wxUSE_UNICODE + wxString& operator<<(const wxCharBuffer& s) { return operator<<((const char *)s); } wxString& operator+=(const wxCharBuffer& s) { return operator<<((const char *)s); } -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - -#if wxUSE_UNICODE - // string += C string in Unicode build (with conversion) - wxString& operator<<(const char *s) - { return operator<<(wxString(s)); } - wxString& operator+=(const char *s) - { return operator+=(wxString(s)); } -#endif // wxUSE_UNICODE // string += C string wxString& Append(const wxString& s) @@ -1306,8 +1465,10 @@ public: } wxString& Append(const wxCStrData& psz) { append(psz); return *this; } - wxString& Append(const wxChar* psz) + wxString& Append(const char* psz) { append(psz); return *this; } + wxString& Append(const wchar_t* pwz) + { append(pwz); return *this; } // append count copies of given character wxString& Append(wxUniChar ch, size_t count = 1u) { append(count, ch); return *this; } @@ -1317,8 +1478,10 @@ public: { append(count, ch); return *this; } wxString& Append(wchar_t ch, size_t count = 1u) { append(count, ch); return *this; } - wxString& Append(const wxChar* psz, size_t nLen) + wxString& Append(const char* psz, size_t nLen) { append(psz, nLen); return *this; } + wxString& Append(const wchar_t* pwz, size_t nLen) + { append(pwz, nLen); return *this; } // prepend a string, return the string itself wxString& Prepend(const wxString& str) @@ -1334,9 +1497,13 @@ public: friend wxString WXDLLIMPEXP_BASE operator+(wxUniChar ch, const wxString& string); // string with C string friend wxString WXDLLIMPEXP_BASE operator+(const wxString& string, - const wxChar *psz); + const char *psz); + friend wxString WXDLLIMPEXP_BASE operator+(const wxString& string, + const wchar_t *pwz); // C string with string - friend wxString WXDLLIMPEXP_BASE operator+(const wxChar *psz, + friend wxString WXDLLIMPEXP_BASE operator+(const char *psz, + const wxString& string); + friend wxString WXDLLIMPEXP_BASE operator+(const wchar_t *pwz, const wxString& string); // stream-like functions @@ -1375,15 +1542,24 @@ public: // string comparison // case-sensitive comparison (returns a value < 0, = 0 or > 0) - int Cmp(const wxChar *psz) const; - int Cmp(const wxString& s) const; + int Cmp(const char *psz) const + { return compare(psz); } + int Cmp(const wchar_t *pwz) const + { return compare(pwz); } + int Cmp(const wxString& s) const + { return compare(s); } // same as Cmp() but not case-sensitive - int CmpNoCase(const wxChar *psz) const; int CmpNoCase(const wxString& s) const; + int CmpNoCase(const char *psz) const + { return CmpNoCase(wxString(psz)); } + int CmpNoCase(const wchar_t *pwz) const + { return CmpNoCase(wxString(pwz)); } // test for the string equality, either considering case or not // (if compareWithCase then the case matters) - bool IsSameAs(const wxChar *psz, bool compareWithCase = true) const + bool IsSameAs(const char *psz, bool compareWithCase = true) const { return (compareWithCase ? Cmp(psz) : CmpNoCase(psz)) == 0; } + bool IsSameAs(const wchar_t *pwz, bool compareWithCase = true) const + { return (compareWithCase ? Cmp(pwz) : CmpNoCase(pwz)) == 0; } // comparison with a single character: returns true if equal bool IsSameAs(wxUniChar c, bool compareWithCase = true) const { @@ -1505,7 +1681,7 @@ public: // minimize the string's memory // only works if the data of this string is not shared bool Shrink(); -#if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING +#if WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // These are deprecated, use wxStringBuffer or wxStringBufferLength instead // // get writable buffer of at least nLen bytes. Unget() *must* be called @@ -1514,7 +1690,7 @@ public: // call this immediately after GetWriteBuf() has been used wxDEPRECATED( void UngetWriteBuf() ); wxDEPRECATED( void UngetWriteBuf(size_t nLen) ); -#endif // WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING +#endif // WXWIN_COMPATIBILITY_2_8 && !wxUSE_STL_BASED_WXSTRING && wxUSE_UNICODE_UTF8 // wxWidgets version 1 compatibility functions @@ -1537,7 +1713,7 @@ public: inline int CompareTo(const wxChar* psz, caseCompare cmp = exact) const { return cmp == exact ? Cmp(psz) : CmpNoCase(psz); } - // use Len + // use length() size_t Length() const { return length(); } // Count the number of characters int Freq(wxUniChar ch) const; @@ -1559,12 +1735,12 @@ public: { return (wxString&)erase( nStart, nLen ); } // use Find() - int First( const wxUniChar ch ) const { return Find(ch); } + int First( wxUniChar ch ) const { return Find(ch); } int First( char ch ) const { return Find(ch); } int First( wchar_t ch ) const { return Find(ch); } int First( const wxChar* psz ) const { return Find(psz); } int First( const wxString &str ) const { return Find(str); } - int Last( const wxUniChar ch ) const { return Find(ch, true); } + int Last( wxUniChar ch ) const { return Find(ch, true); } bool Contains(const wxString& str) const { return Find(str) != wxNOT_FOUND; } // use empty() @@ -1574,164 +1750,531 @@ public: // take nLen chars starting at nPos wxString(const wxString& str, size_t nPos, size_t nLen) - : wxStringBase(str, nPos, nLen) { } + : m_impl(str.m_impl, nPos, nLen) { } // take all characters from pStart to pEnd wxString(const void *pStart, const void *pEnd) - : wxStringBase((const wxChar*)pStart, (const wxChar*)pEnd) { } + : m_impl((const wxChar*)pStart, (const wxChar*)pEnd) { } wxString(const_iterator first, const_iterator last) - : wxStringBase(first, last) { } + : m_impl(first, last) { } wxString(iterator first, iterator last) - : wxStringBase(first, last) { } + : m_impl(first, last) { } // lib.string.modifiers // append elements str[pos], ..., str[pos+n] wxString& append(const wxString& str, size_t pos, size_t n) - { return (wxString&)wxStringBase::append(str, pos, n); } + { + size_t from, len; + str.PosLenToImpl(pos, n, &from, &len); + m_impl.append(str.m_impl, from, len); + return *this; + } // append a string wxString& append(const wxString& str) - { return (wxString&)wxStringBase::append(str); } + { m_impl.append(str.m_impl); return *this; } wxString& append(const wxCStrData& str) - { return (wxString&)wxStringBase::append(str.AsString()); } + { m_impl.append(str.AsString().m_impl); return *this; } // append first n (or all if n == npos) characters of sz - wxString& append(const wxChar *sz) - { return (wxString&)wxStringBase::append(sz); } - wxString& append(const wxChar *sz, size_t n) - { return (wxString&)wxStringBase::append(sz, n); } + wxString& append(const char *sz) + { m_impl.append(ImplStr(sz)); return *this; } + wxString& append(const wchar_t *sz) + { m_impl.append(ImplStr(sz)); return *this; } + wxString& append(const char *sz, size_t n) + { + SubstrBufFromMB str(ImplStr(sz, n)); + m_impl.append(str.data, str.len); + return *this; + } + wxString& append(const wchar_t *sz, size_t n) + { + SubstrBufFromWC str(ImplStr(sz, n)); + m_impl.append(str.data, str.len); + return *this; + } // append n copies of ch wxString& append(size_t n, wxUniChar ch) - { return (wxString&)wxStringBase::append(n, ch); } + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.append(EncodeNChars(n, ch)); + else +#endif + m_impl.append(n, (wxStringCharType)ch); + return *this; + } // append from first to last wxString& append(const_iterator first, const_iterator last) - { return (wxString&)wxStringBase::append(first, last); } + { m_impl.append(first, last); return *this; } // same as `this_string = str' wxString& assign(const wxString& str) - { return (wxString&)wxStringBase::assign(str); } + { m_impl = str.m_impl; return *this; } // same as ` = str[pos..pos + n] wxString& assign(const wxString& str, size_t pos, size_t n) - { return (wxString&)wxStringBase::assign(str, pos, n); } + { + size_t from, len; + str.PosLenToImpl(pos, n, &from, &len); + m_impl.assign(str.m_impl, from, len); + return *this; + } // same as `= first n (or all if n == npos) characters of sz' - wxString& assign(const wxChar *sz) - { return (wxString&)wxStringBase::assign(sz); } - wxString& assign(const wxChar *sz, size_t n) - { return (wxString&)wxStringBase::assign(sz, n); } + wxString& assign(const char *sz) + { m_impl.assign(ImplStr(sz)); return *this; } + wxString& assign(const wchar_t *sz) + { m_impl.assign(ImplStr(sz)); return *this; } + wxString& assign(const char *sz, size_t n) + { + SubstrBufFromMB str(ImplStr(sz, n)); + m_impl.assign(str.data, str.len); + return *this; + } + wxString& assign(const wchar_t *sz, size_t n) + { + SubstrBufFromWC str(ImplStr(sz, n)); + m_impl.assign(str.data, str.len); + return *this; + } // same as `= n copies of ch' wxString& assign(size_t n, wxUniChar ch) - { return (wxString&)wxStringBase::assign(n, ch); } + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.assign(EncodeNChars(n, ch)); + else +#endif + m_impl.assign(n, (wxStringCharType)ch); + return *this; + } // assign from first to last wxString& assign(const_iterator first, const_iterator last) - { return (wxString&)wxStringBase::assign(first, last); } + { m_impl.assign(first, last); return *this; } // string comparison -#if !defined(HAVE_STD_STRING_COMPARE) - int compare(const wxStringBase& str) const; + int compare(const wxString& str) const; // comparison with a substring - int compare(size_t nStart, size_t nLen, const wxStringBase& str) const; + int compare(size_t nStart, size_t nLen, const wxString& str) const; // comparison of 2 substrings int compare(size_t nStart, size_t nLen, - const wxStringBase& str, size_t nStart2, size_t nLen2) const; + const wxString& str, size_t nStart2, size_t nLen2) const; // just like strcmp() - int compare(const wxChar* sz) const; + int compare(const char* sz) const; + int compare(const wchar_t* sz) const; // substring comparison with first nCount characters of sz int compare(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount = npos) const; -#endif // !defined HAVE_STD_STRING_COMPARE + const char* sz, size_t nCount = npos) const; + int compare(size_t nStart, size_t nLen, + const wchar_t* sz, size_t nCount = npos) const; // insert another string wxString& insert(size_t nPos, const wxString& str) - { return (wxString&)wxStringBase::insert(nPos, str); } + { insert(begin() + nPos, str.begin(), str.end()); return *this; } // insert n chars of str starting at nStart (in str) wxString& insert(size_t nPos, const wxString& str, size_t nStart, size_t n) - { return (wxString&)wxStringBase::insert(nPos, str, nStart, n); } + { + size_t from, len; + str.PosLenToImpl(nStart, n, &from, &len); + m_impl.insert(PosToImpl(nPos), str.m_impl, from, len); + return *this; + } // insert first n (or all if n == npos) characters of sz - wxString& insert(size_t nPos, const wxChar *sz) - { return (wxString&)wxStringBase::insert(nPos, sz); } - wxString& insert(size_t nPos, const wxChar *sz, size_t n) - { return (wxString&)wxStringBase::insert(nPos, sz, n); } + wxString& insert(size_t nPos, const char *sz) + { m_impl.insert(PosToImpl(nPos), ImplStr(sz)); return *this; } + wxString& insert(size_t nPos, const wchar_t *sz) + { m_impl.insert(PosToImpl(nPos), ImplStr(sz)); return *this; } + wxString& insert(size_t nPos, const char *sz, size_t n) + { + SubstrBufFromMB str(ImplStr(sz, n)); + m_impl.insert(PosToImpl(nPos), str.data, str.len); + return *this; + } + wxString& insert(size_t nPos, const wchar_t *sz, size_t n) + { + SubstrBufFromWC str(ImplStr(sz, n)); + m_impl.insert(PosToImpl(nPos), str.data, str.len); + return *this; + } // insert n copies of ch wxString& insert(size_t nPos, size_t n, wxUniChar ch) - { return (wxString&)wxStringBase::insert(nPos, n, ch); } + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.insert(begin() + nPos, EncodeNChars(n, ch)); + else +#endif + m_impl.insert(begin() + nPos, n, (wxStringCharType)ch); + return *this; + } iterator insert(iterator it, wxUniChar ch) - { return wxStringBase::insert(it, ch); } + { return iterator(m_impl.insert(it, EncodeChar(ch))); } void insert(iterator it, const_iterator first, const_iterator last) - { wxStringBase::insert(it, first, last); } + { m_impl.insert(it, first, last); } void insert(iterator it, size_type n, wxUniChar ch) - { wxStringBase::insert(it, n, ch); } + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.insert(it, EncodeNChars(n, ch)); + else +#endif + m_impl.insert(it, n, (wxStringCharType)ch); + } // delete characters from nStart to nStart + nLen wxString& erase(size_type pos = 0, size_type n = npos) - { return (wxString&)wxStringBase::erase(pos, n); } + { + size_t from, len; + PosLenToImpl(pos, n, &from, &len); + m_impl.erase(from, len); + return *this; + } iterator erase(iterator first, iterator last) - { return wxStringBase::erase(first, last); } + { return iterator(m_impl.erase(first, last)); } iterator erase(iterator first) - { return wxStringBase::erase(first); } + { return iterator(m_impl.erase(first)); } #ifdef wxSTRING_BASE_HASNT_CLEAR void clear() { erase(); } +#else + void clear() { m_impl.clear(); } #endif // replaces the substring of length nLen starting at nStart - wxString& replace(size_t nStart, size_t nLen, const wxChar* sz) - { return (wxString&)wxStringBase::replace(nStart, nLen, sz); } + wxString& replace(size_t nStart, size_t nLen, const char* sz) + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, ImplStr(sz)); + return *this; + } + wxString& replace(size_t nStart, size_t nLen, const wchar_t* sz) + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, ImplStr(sz)); + return *this; + } // replaces the substring of length nLen starting at nStart wxString& replace(size_t nStart, size_t nLen, const wxString& str) - { return (wxString&)wxStringBase::replace(nStart, nLen, str); } + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, str.m_impl); + return *this; + } // replaces the substring with nCount copies of ch wxString& replace(size_t nStart, size_t nLen, size_t nCount, wxUniChar ch) - { return (wxString&)wxStringBase::replace(nStart, nLen, nCount, ch); } + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.replace(from, len, EncodeNChars(nCount, ch)); + else +#endif + m_impl.replace(from, len, nCount, (wxStringCharType)ch); + return *this; + } // replaces a substring with another substring wxString& replace(size_t nStart, size_t nLen, const wxString& str, size_t nStart2, size_t nLen2) - { return (wxString&)wxStringBase::replace(nStart, nLen, str, - nStart2, nLen2); } + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + + size_t from2, len2; + str.PosLenToImpl(nStart2, nLen2, &from2, &len2); + + m_impl.replace(from, len, str.m_impl, from2, len2); + return *this; + } // replaces the substring with first nCount chars of sz wxString& replace(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) - { return (wxString&)wxStringBase::replace(nStart, nLen, sz, nCount); } - wxString& replace(iterator first, iterator last, const_pointer s) - { return (wxString&)wxStringBase::replace(first, last, s); } - wxString& replace(iterator first, iterator last, const_pointer s, - size_type n) - { return (wxString&)wxStringBase::replace(first, last, s, n); } + const char* sz, size_t nCount) + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + + SubstrBufFromMB str(ImplStr(sz, nCount)); + + m_impl.replace(from, len, str.data, str.len); + return *this; + } + wxString& replace(size_t nStart, size_t nLen, + const wchar_t* sz, size_t nCount) + { + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + + SubstrBufFromWC str(ImplStr(sz, nCount)); + + m_impl.replace(from, len, str.data, str.len); + return *this; + } + wxString& replace(iterator first, iterator last, const char* s) + { m_impl.replace(first, last, ImplStr(s)); return *this; } + wxString& replace(iterator first, iterator last, const wchar_t* s) + { m_impl.replace(first, last, ImplStr(s)); return *this; } + wxString& replace(iterator first, iterator last, const char* s, size_type n) + { + SubstrBufFromMB str(ImplStr(s, n)); + m_impl.replace(first, last, str.data, str.len); + return *this; + } + wxString& replace(iterator first, iterator last, const wchar_t* s, size_type n) + { + SubstrBufFromWC str(ImplStr(s, n)); + m_impl.replace(first, last, str.data, str.len); + return *this; + } wxString& replace(iterator first, iterator last, const wxString& s) - { return (wxString&)wxStringBase::replace(first, last, s); } - wxString& replace(iterator first, iterator last, size_type n, wxUniChar c) - { return (wxString&)wxStringBase::replace(first, last, n, c); } + { m_impl.replace(first, last, s.m_impl); return *this; } + wxString& replace(iterator first, iterator last, size_type n, wxUniChar ch) + { +#if wxUSE_UNICODE_UTF8 + if ( !ch.IsAscii() ) + m_impl.replace(first, last, EncodeNChars(n, ch)); + else +#endif + m_impl.replace(first, last, n, (wxStringCharType)ch); + return *this; + } wxString& replace(iterator first, iterator last, const_iterator first1, const_iterator last1) - { return (wxString&)wxStringBase::replace(first, last, first1, last1); } + { m_impl.replace(first, last, first1, last1); return *this; } + + // swap two strings + void swap(wxString& str) + { m_impl.swap(str.m_impl); } + + // find a substring + size_t find(const wxString& str, size_t nStart = 0) const + { return PosFromImpl(m_impl.find(str.m_impl, PosToImpl(nStart))); } + + // find first n characters of sz + size_t find(const char* sz, size_t nStart = 0, size_t n = npos) const + { + SubstrBufFromMB str(ImplStr(sz, n)); + return PosFromImpl(m_impl.find(str.data, PosToImpl(nStart), str.len)); + } + size_t find(const wchar_t* sz, size_t nStart = 0, size_t n = npos) const + { + SubstrBufFromWC str(ImplStr(sz, n)); + return PosFromImpl(m_impl.find(str.data, PosToImpl(nStart), str.len)); + } + + // find the first occurence of character ch after nStart + size_t find(wxUniChar ch, size_t nStart = 0) const + { return PosFromImpl(m_impl.find(EncodeChar(ch), PosToImpl(nStart))); } + size_t find(wxUniCharRef ch, size_t nStart = 0) const + { return find(wxUniChar(ch), nStart); } + size_t find(char ch, size_t nStart = 0) const + { return find(wxUniChar(ch), nStart); } + size_t find(wchar_t ch, size_t nStart = 0) const + { return find(wxUniChar(ch), nStart); } + + // rfind() family is exactly like find() but works right to left + + // as find, but from the end + size_t rfind(const wxString& str, size_t nStart = npos) const + { return PosFromImpl(m_impl.rfind(str.m_impl, PosToImpl(nStart))); } + + // as find, but from the end + size_t rfind(const char* sz, size_t nStart = npos, size_t n = npos) const + { + SubstrBufFromMB str(ImplStr(sz, n)); + return PosFromImpl(m_impl.rfind(str.data, PosToImpl(nStart), str.len)); + } + size_t rfind(const wchar_t* sz, size_t nStart = npos, size_t n = npos) const + { + SubstrBufFromWC str(ImplStr(sz, n)); + return PosFromImpl(m_impl.rfind(str.data, PosToImpl(nStart), str.len)); + } + // as find, but from the end + size_t rfind(wxUniChar ch, size_t nStart = npos) const + { return PosFromImpl(m_impl.rfind(EncodeChar(ch), PosToImpl(nStart))); } + size_t rfind(wxUniCharRef ch, size_t nStart = npos) const + { return rfind(wxUniChar(ch), nStart); } + size_t rfind(char ch, size_t nStart = npos) const + { return rfind(wxUniChar(ch), nStart); } + size_t rfind(wchar_t ch, size_t nStart = npos) const + { return rfind(wxUniChar(ch), nStart); } + + // find first/last occurence of any character (not) in the set: +#if wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 + // FIXME-UTF8: this is not entirely correct, because it doesn't work if + // sizeof(wchar_t)==2 and surrogates are present in the string; + // should we care? Probably not. + size_t find_first_of(const wxString& str, size_t nStart = 0) const + { return m_impl.find_first_of(str.impl, nStart); } + size_t find_first_of(const char* sz, size_t nStart = 0) const + { return m_impl.find_first_of(ImplStr(sz), nStart); } + size_t find_first_of(const wchar_t* sz, size_t nStart = 0) const + { return m_impl.find_first_of(ImplStr(sz), nStart); } + size_t find_first_of(const char* sz, size_t nStart, size_t n) const; + { return m_impl.find_first_of(ImplStr(sz), nStart, n); } + size_t find_first_of(const wchar_t* sz, size_t nStart, size_t n) const; + { return m_impl.find_first_of(ImplStr(sz), nStart, n); } + size_t find_first_of(wxUniChar c, size_t nStart = 0) const + { return m_impl.find_first_of((wxChar)c, nStart); } + + size_t find_last_of(const wxStringImpl& str, size_t nStart = npos) const + { return m_impl.find_last_of(str.impl, nStart); } + size_t find_last_of(const char* sz, size_t nStart = npos) const + { return m_impl.find_last_of(ImplStr(sz), nStart); } + size_t find_last_of(const wchar_t* sz, size_t nStart = npos) const + { return m_impl.find_last_of(ImplStr(sz), nStart); } + size_t find_last_of(const char* sz, size_t nStart, size_t n) const + { return m_impl.find_last_of(ImplStr(sz), nStart, n); } + size_t find_last_of(const wchar_t* sz, size_t nStart, size_t n) const + { return m_impl.find_last_of(ImplStr(sz), nStart, n); } + size_t find_last_of(wxUniChar c, size_t nStart = npos) const + { return m_impl.find_last_of((wxChar)c, nStart); } + + size_t find_first_not_of(const wxStringImpl& str, size_t nStart = 0) const + { return m_impl.find_first_not_of(str.m_impl, nStart); } + size_t find_first_not_of(const char* sz, size_t nStart = 0) const; + { return m_impl.find_first_not_of(ImplStr(sz), nStart); } + size_t find_first_not_of(const wchar_t* sz, size_t nStart = 0) const; + { return m_impl.find_first_not_of(ImplStr(sz), nStart); } + size_t find_first_not_of(const char* sz, size_t nStart, size_t n) const; + { return m_impl.find_first_not_of(ImplStr(sz), nStart, n); } + size_t find_first_not_of(const wchar_t* sz, size_t nStart, size_t n) const; + { return m_impl.find_first_not_of(ImplStr(sz), nStart, n); } + size_t find_first_not_of(wxUniChar c, size_t nStart = 0) const; + { return m_impl.find_first_not_of((wxChar)c, nStart); } + + size_t find_last_not_of(const wxStringImpl& str, size_t nStart = npos) const + { return m_impl.find_last_not_of(str.m_impl, nStart); } + size_t find_last_not_of(const char* sz, size_t nStart = npos) const; + { return m_impl.find_last_not_of(ImplStr(sz), nStart); } + size_t find_last_not_of(const wchar_t* sz, size_t nStart = npos) const; + { return m_impl.find_last_not_of(ImplStr(sz), nStart); } + size_t find_last_not_of(const char* sz, size_t nStart, size_t n) const; + { return m_impl.find_last_not_of(ImplStr(sz), nStart, n); } + size_t find_last_not_of(const wchar_t* sz, size_t nStart, size_t n) const; + { return m_impl.find_last_not_of(ImplStr(sz), nStart, n); } + size_t find_last_not_of(wxUniChar c, size_t nStart = npos) const; + { return m_impl.find_last_not_of((wxChar)c, nStart); } +#else + // we can't use std::string implementation in UTF-8 build, because the + // character sets would be interpreted wrongly: + + // as strpbrk() but starts at nStart, returns npos if not found + size_t find_first_of(const wxString& str, size_t nStart = 0) const + { return find_first_of((const wxChar*)str.c_str(), nStart); } + // same as above + size_t find_first_of(const char* sz, size_t nStart = 0) const; + size_t find_first_of(const wchar_t* sz, size_t nStart = 0) const; + size_t find_first_of(const char* sz, size_t nStart, size_t n) const; + size_t find_first_of(const wchar_t* sz, size_t nStart, size_t n) const; + // same as find(char, size_t) + size_t find_first_of(wxUniChar c, size_t nStart = 0) const + { return find(c, nStart); } + // find the last (starting from nStart) char from str in this string + size_t find_last_of (const wxString& str, size_t nStart = npos) const + { return find_last_of((const wxChar*)str.c_str(), nStart); } + // same as above + size_t find_last_of (const char* sz, size_t nStart = npos) const; + size_t find_last_of (const wchar_t* sz, size_t nStart = npos) const; + size_t find_last_of(const char* sz, size_t nStart, size_t n) const; + size_t find_last_of(const wchar_t* sz, size_t nStart, size_t n) const; + // same as above + size_t find_last_of(wxUniChar c, size_t nStart = npos) const + { return rfind(c, nStart); } + + // find first/last occurence of any character not in the set + + // as strspn() (starting from nStart), returns npos on failure + size_t find_first_not_of(const wxString& str, size_t nStart = 0) const + { return find_first_not_of((const wxChar*)str.c_str(), nStart); } + // same as above + size_t find_first_not_of(const char* sz, size_t nStart = 0) const; + size_t find_first_not_of(const wchar_t* sz, size_t nStart = 0) const; + size_t find_first_not_of(const char* sz, size_t nStart, size_t n) const; + size_t find_first_not_of(const wchar_t* sz, size_t nStart, size_t n) const; + // same as above + size_t find_first_not_of(wxUniChar ch, size_t nStart = 0) const; + // as strcspn() + size_t find_last_not_of(const wxString& str, size_t nStart = npos) const + { return find_last_not_of((const wxChar*)str.c_str(), nStart); } + // same as above + size_t find_last_not_of(const char* sz, size_t nStart = npos) const; + size_t find_last_not_of(const wchar_t* sz, size_t nStart = npos) const; + size_t find_last_not_of(const char* sz, size_t nStart, size_t n) const; + size_t find_last_not_of(const wchar_t* sz, size_t nStart, size_t n) const; + // same as above + size_t find_last_not_of(wxUniChar ch, size_t nStart = npos) const; +#endif // wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 or not + + // provide char/wchar_t/wxUniCharRef overloads for char-finding functions + // above to resolve ambiguities: + size_t find_first_of(wxUniCharRef ch, size_t nStart = 0) const + { return find_first_of(wxUniChar(ch), nStart); } + size_t find_first_of(char ch, size_t nStart = 0) const + { return find_first_of(wxUniChar(ch), nStart); } + size_t find_first_of(wchar_t ch, size_t nStart = 0) const + { return find_first_of(wxUniChar(ch), nStart); } + size_t find_last_of(wxUniCharRef ch, size_t nStart = npos) const + { return find_last_of(wxUniChar(ch), nStart); } + size_t find_last_of(char ch, size_t nStart = npos) const + { return find_last_of(wxUniChar(ch), nStart); } + size_t find_last_of(wchar_t ch, size_t nStart = npos) const + { return find_last_of(wxUniChar(ch), nStart); } + size_t find_first_not_of(wxUniCharRef ch, size_t nStart = 0) const + { return find_first_not_of(wxUniChar(ch), nStart); } + size_t find_first_not_of(char ch, size_t nStart = 0) const + { return find_first_not_of(wxUniChar(ch), nStart); } + size_t find_first_not_of(wchar_t ch, size_t nStart = 0) const + { return find_first_not_of(wxUniChar(ch), nStart); } + size_t find_last_not_of(wxUniCharRef ch, size_t nStart = npos) const + { return find_last_not_of(wxUniChar(ch), nStart); } + size_t find_last_not_of(char ch, size_t nStart = npos) const + { return find_last_not_of(wxUniChar(ch), nStart); } + size_t find_last_not_of(wchar_t ch, size_t nStart = npos) const + { return find_last_not_of(wxUniChar(ch), nStart); } // string += string wxString& operator+=(const wxString& s) - { return (wxString&)wxStringBase::operator+=(s); } + { m_impl += s.m_impl; return *this; } // string += C string - wxString& operator+=(const wxChar *psz) - { return (wxString&)wxStringBase::operator+=(psz); } + wxString& operator+=(const char *psz) + { m_impl += ImplStr(psz); return *this; } + wxString& operator+=(const wchar_t *pwz) + { m_impl += ImplStr(pwz); return *this; } wxString& operator+=(const wxCStrData& s) - { return (wxString&)wxStringBase::operator+=(s.AsString()); } + { m_impl += s.AsString().m_impl; return *this; } // string += char wxString& operator+=(wxUniChar ch) - { return (wxString&)wxStringBase::operator+=(ch); } + { m_impl += EncodeChar(ch); return *this; } wxString& operator+=(wxUniCharRef ch) { return *this += wxUniChar(ch); } wxString& operator+=(char ch) { return *this += wxUniChar(ch); } wxString& operator+=(unsigned char ch) { return *this += wxUniChar(ch); } wxString& operator+=(wchar_t ch) { return *this += wxUniChar(ch); } private: -#if !wxUSE_STL_BASED_WXSTRING +#if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // helpers for wxStringBuffer and wxStringBufferLength - wxChar *DoGetWriteBuf(size_t nLen); - void DoUngetWriteBuf(); - void DoUngetWriteBuf(size_t nLen); + wxStringCharType *DoGetWriteBuf(size_t nLen) + { return m_impl.DoGetWriteBuf(nLen); } + void DoUngetWriteBuf() + { m_impl.DoUngetWriteBuf(); } + void DoUngetWriteBuf(size_t nLen) + { m_impl.DoUngetWriteBuf(nLen); } friend class WXDLLIMPEXP_BASE wxStringBuffer; friend class WXDLLIMPEXP_BASE wxStringBufferLength; -#endif +#endif // !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN int DoPrintf(const wxChar *format, ...) ATTRIBUTE_PRINTF_2; static wxString DoFormat(const wxChar *format, ...) ATTRIBUTE_PRINTF_1; #endif + +#if !wxUSE_STL_BASED_WXSTRING + // check string's data validity + bool IsValid() const { return m_impl.GetStringData()->IsValid(); } +#endif + +private: + wxStringImpl m_impl; }; #ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN @@ -1743,8 +2286,10 @@ private: // here as friend ones are not injected in the enclosing namespace and without // them the code fails to compile with conforming compilers such as xlC or g++4 wxString WXDLLIMPEXP_BASE operator+(const wxString& string1, const wxString& string2); -wxString WXDLLIMPEXP_BASE operator+(const wxString& string, const wxChar *psz); -wxString WXDLLIMPEXP_BASE operator+(const wxChar *psz, const wxString& string); +wxString WXDLLIMPEXP_BASE operator+(const wxString& string, const char *psz); +wxString WXDLLIMPEXP_BASE operator+(const wxString& string, const wchar_t *pwz); +wxString WXDLLIMPEXP_BASE operator+(const char *psz, const wxString& string); +wxString WXDLLIMPEXP_BASE operator+(const wchar_t *pwz, const wxString& string); wxString WXDLLIMPEXP_BASE operator+(const wxString& string, wxUniChar ch); wxString WXDLLIMPEXP_BASE operator+(wxUniChar ch, const wxString& string); @@ -1778,7 +2323,7 @@ inline wxString operator+(wchar_t ch, const wxString& string) // wxStringBuffer: a tiny class allowing to get a writable pointer into string // ---------------------------------------------------------------------------- -#if wxUSE_STL_BASED_WXSTRING +#if wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8 class WXDLLIMPEXP_BASE wxStringBuffer { @@ -1831,7 +2376,7 @@ private: DECLARE_NO_COPY_CLASS(wxStringBufferLength) }; -#else // if !wxUSE_STL_BASED_WXSTRING +#else // if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 class WXDLLIMPEXP_BASE wxStringBuffer { @@ -1879,7 +2424,7 @@ private: DECLARE_NO_COPY_CLASS(wxStringBufferLength) }; -#endif // !wxUSE_STL_BASED_WXSTRING +#endif // !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // --------------------------------------------------------------------------- // wxString comparison functions: operator versions are always case sensitive @@ -2030,7 +2575,7 @@ inline const char* wxCStrData::AsChar() const #endif { if ( m_offset == 0 ) - return m_str->wx_str(); // FIXME + return m_str->wx_str(); // FIXME-UTF8 else return (const wxChar*)(m_str->begin() + m_offset); } @@ -2058,15 +2603,6 @@ inline wxUniChar wxCStrData::operator[](size_t n) const return m_str->at(m_offset + n); } -// ---------------------------------------------------------------------------- -// implementation of wxString inline methods using wxCStrData -// ---------------------------------------------------------------------------- - -inline wxString& wxString::operator=(const wxCStrData& cstr) -{ - return *this = cstr.AsString(); -} - // ---------------------------------------------------------------------------- // implementation of wx[W]CharBuffer inline methods using wxCStrData // ---------------------------------------------------------------------------- diff --git a/include/wx/strvararg.h b/include/wx/strvararg.h index 290614c863..2aab05e478 100644 --- a/include/wx/strvararg.h +++ b/include/wx/strvararg.h @@ -89,27 +89,11 @@ struct wxArgNormalizer // special cases for converting strings: -// FIXME-UTF8: move this to chartype.h! -#if wxUSE_UNICODE - /* for now, all Unicode builds are wchar_t* based: */ - #define wxUSE_UNICODE_WCHAR 1 -#else - #define wxUSE_UNICODE_WCHAR 0 -#endif - -// FIXME-UTF8: include wx/chartype.h and use wxChar after headers split -// FIXME-UTF8: this will be char* in UTF-8 build and wchar_t* on Windows -#if wxUSE_UNICODE_WCHAR - typedef wchar_t wxArgNativeCharType; -#else - typedef char wxArgNativeCharType; -#endif - template<> struct WXDLLIMPEXP_BASE wxArgNormalizer { wxArgNormalizer(const wxCStrData& value) : m_value(value) {} - const wxArgNativeCharType *get() const; + const wxStringCharType *get() const; const wxCStrData& m_value; }; @@ -125,7 +109,7 @@ template<> struct WXDLLIMPEXP_BASE wxArgNormalizer { wxArgNormalizer(const wxString& value) : m_value(value) {} - const wxArgNativeCharType *get() const; + const wxStringCharType *get() const; const wxString& m_value; }; diff --git a/src/common/string.cpp b/src/common/string.cpp index 8d39d9ceea..db4b5fe618 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -52,14 +52,30 @@ // NB: EXTRA_ALLOC must be >= 0! #define EXTRA_ALLOC (19 - nLen % 16) + +// string handling functions used by wxString: +#if wxUSE_UNICODE_UTF8 + #define wxStringMemcpy memcpy + #define wxStringMemcmp memcmp + #define wxStringMemchr memchr + #define wxStringStrlen strlen +#else + #define wxStringMemcpy wxTmemcpy + #define wxStringMemcmp wxTmemcmp + #define wxStringMemchr wxTmemchr + #define wxStringStrlen wxStrlen +#endif + + // --------------------------------------------------------------------------- // static class variables definition // --------------------------------------------------------------------------- #if !wxUSE_STL_BASED_WXSTRING //According to STL _must_ be a -1 size_t - const size_t wxStringBase::npos = (size_t) -1; + const size_t wxStringImpl::npos = (size_t) -1; #endif +const size_t wxString::npos = (size_t) -1; // ---------------------------------------------------------------------------- // static data @@ -153,11 +169,11 @@ void wxStringData::Free() #endif // =========================================================================== -// wxStringBase +// wxStringImpl // =========================================================================== // takes nLength elements of psz starting at nPos -void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) +void wxStringImpl::InitWith(const wxChar *psz, size_t nPos, size_t nLength) { Init(); @@ -173,15 +189,15 @@ void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) if ( nLength > 0 ) { // trailing '\0' is written in AllocBuffer() if ( !AllocBuffer(nLength) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); + wxFAIL_MSG( _T("out of memory in wxStringImpl::InitWith") ); return; } - wxTmemcpy(m_pchData, psz + nPos, nLength); + wxStringMemcpy(m_pchData, psz + nPos, nLength); } } // poor man's iterators are "void *" pointers -wxStringBase::wxStringBase(const void *pStart, const void *pEnd) +wxStringImpl::wxStringImpl(const void *pStart, const void *pEnd) { if ( pEnd >= pStart ) { @@ -195,7 +211,7 @@ wxStringBase::wxStringBase(const void *pStart, const void *pEnd) } } -wxStringBase::wxStringBase(size_type n, wxUniChar ch) +wxStringImpl::wxStringImpl(size_type n, wxStringCharType ch) { Init(); append(n, ch); @@ -206,7 +222,7 @@ wxStringBase::wxStringBase(size_type n, wxUniChar ch) // --------------------------------------------------------------------------- // allocates memory needed to store a C string of length nLen -bool wxStringBase::AllocBuffer(size_t nLen) +bool wxStringImpl::AllocBuffer(size_t nLen) { // allocating 0 sized buffer doesn't make sense, all empty strings should // reuse g_strEmpty @@ -238,7 +254,7 @@ bool wxStringBase::AllocBuffer(size_t nLen) } // must be called before changing this string -bool wxStringBase::CopyBeforeWrite() +bool wxStringImpl::CopyBeforeWrite() { wxStringData* pData = GetStringData(); @@ -249,7 +265,7 @@ bool wxStringBase::CopyBeforeWrite() // allocation failures are handled by the caller return false; } - wxTmemcpy(m_pchData, pData->data(), nLen); + wxStringMemcpy(m_pchData, pData->data(), nLen); } wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner @@ -258,7 +274,7 @@ bool wxStringBase::CopyBeforeWrite() } // must be called before replacing contents of this string -bool wxStringBase::AllocBeforeWrite(size_t nLen) +bool wxStringImpl::AllocBeforeWrite(size_t nLen) { wxASSERT( nLen != 0 ); // doesn't make any sense @@ -304,12 +320,12 @@ bool wxStringBase::AllocBeforeWrite(size_t nLen) return true; } -wxStringBase& wxStringBase::append(size_t n, wxUniChar ch) +wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch) { size_type len = length(); if ( !Alloc(len + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); + wxFAIL_MSG( _T("out of memory in wxStringImpl::append") ); } GetStringData()->nDataLength = len + n; m_pchData[len + n] = '\0'; @@ -318,7 +334,7 @@ wxStringBase& wxStringBase::append(size_t n, wxUniChar ch) return *this; } -void wxStringBase::resize(size_t nSize, wxUniChar ch) +void wxStringImpl::resize(size_t nSize, wxStringCharType ch) { size_t len = length(); @@ -334,7 +350,7 @@ void wxStringBase::resize(size_t nSize, wxUniChar ch) } // allocate enough memory for nLen characters -bool wxStringBase::Alloc(size_t nLen) +bool wxStringImpl::Alloc(size_t nLen) { wxStringData *pData = GetStringData(); if ( pData->nAllocLength <= nLen ) { @@ -388,41 +404,41 @@ bool wxStringBase::Alloc(size_t nLen) return true; } -wxStringBase::iterator wxStringBase::begin() +wxStringImpl::iterator wxStringImpl::begin() { if (length() > 0) CopyBeforeWrite(); return m_pchData; } -wxStringBase::iterator wxStringBase::end() +wxStringImpl::iterator wxStringImpl::end() { if (length() > 0) CopyBeforeWrite(); return m_pchData + length(); } -wxStringBase::iterator wxStringBase::erase(iterator it) +wxStringImpl::iterator wxStringImpl::erase(iterator it) { size_type idx = it - begin(); erase(idx, 1); return begin() + idx; } -wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) +wxStringImpl& wxStringImpl::erase(size_t nStart, size_t nLen) { wxASSERT(nStart <= length()); size_t strLen = length() - nStart; // delete nLen or up to the end of the string characters nLen = strLen < nLen ? strLen : nLen; - wxString strTmp(c_str(), nStart); + wxStringImpl strTmp(c_str(), nStart); strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); swap(strTmp); return *this; } -wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) +wxStringImpl& wxStringImpl::insert(size_t nPos, const wxChar *sz, size_t n) { wxASSERT( nPos <= length() ); @@ -430,7 +446,7 @@ wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) if ( n == 0 ) return *this; if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); + wxFAIL_MSG( _T("out of memory in wxStringImpl::insert") ); } memmove(m_pchData + nPos + n, m_pchData + nPos, @@ -442,14 +458,14 @@ wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) return *this; } -void wxStringBase::swap(wxStringBase& str) +void wxStringImpl::swap(wxStringImpl& str) { - wxChar* tmp = str.m_pchData; + wxStringCharType* tmp = str.m_pchData; str.m_pchData = m_pchData; m_pchData = tmp; } -size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const +size_t wxStringImpl::find(const wxStringImpl& str, size_t nStart) const { // deal with the special case of empty string first const size_t nLen = length(); @@ -470,22 +486,25 @@ size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const wxASSERT( str.GetStringData()->IsValid() ); wxASSERT( nStart <= nLen ); - const wxChar * const other = str.c_str(); + const wxStringCharType * const other = str.c_str(); // anchor - const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, - *other, - nLen - nStart); + const wxStringCharType* p = + (const wxStringCharType*)wxStringMemchr(c_str() + nStart, + *other, + nLen - nStart); if ( !p ) return npos; - while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) + while ( p - c_str() + nLenOther <= nLen && + wxStringMemcmp(p, other, nLenOther) ) { p++; // anchor again - p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); + p = (const wxStringCharType*) + wxStringMemchr(p, *other, nLen - (p - c_str())); if ( !p ) return npos; @@ -494,21 +513,22 @@ size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; } -size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const +size_t wxStringImpl::find(const wxChar* sz, size_t nStart, size_t n) const { - return find(wxStringBase(sz, n), nStart); + return find(wxStringImpl(sz, n), nStart); } -size_t wxStringBase::find(wxUniChar ch, size_t nStart) const +size_t wxStringImpl::find(wxStringCharType ch, size_t nStart) const { wxASSERT( nStart <= length() ); - const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); + const wxStringCharType *p = (const wxStringCharType*) + wxStringMemchr(c_str() + nStart, ch, length() - nStart); return p == NULL ? npos : p - c_str(); } -size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const +size_t wxStringImpl::rfind(const wxStringImpl& str, size_t nStart) const { wxASSERT( str.GetStringData()->IsValid() ); wxASSERT( nStart == npos || nStart <= length() ); @@ -527,11 +547,10 @@ size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const if ( nStart < top ) top = nStart; - const wxChar *cursor = c_str() + top; + const wxStringCharType *cursor = c_str() + top; do { - if ( wxTmemcmp(cursor, str.c_str(), - str.length()) == 0 ) + if ( wxStringMemcmp(cursor, str.c_str(), str.length()) == 0 ) { return cursor - c_str(); } @@ -541,12 +560,12 @@ size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const return npos; } -size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const +size_t wxStringImpl::rfind(const wxChar* sz, size_t nStart, size_t n) const { - return rfind(wxStringBase(sz, n), nStart); + return rfind(wxStringImpl(sz, n), nStart); } -size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const +size_t wxStringImpl::rfind(wxStringCharType ch, size_t nStart) const { if ( nStart == npos ) { @@ -557,7 +576,7 @@ size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const wxASSERT( nStart <= length() ); } - const wxChar *actual; + const wxStringCharType *actual; for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); actual > c_str(); --actual ) { @@ -568,162 +587,15 @@ size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const return npos; } -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const -{ - wxASSERT(nStart <= length()); - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT_MSG( nStart <= length(), - _T("invalid index in find_last_of()") ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( wxTmemchr(sz, *p, len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length(); - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (!wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(wxUniChar ch, size_t nStart) const -{ - wxASSERT( nStart <= length() ); - - for ( const_iterator p = begin() + nStart; (bool)*p; ++p ) // FIXME-DMARS - { - if ( *p != ch ) - return p - begin(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( !wxTmemchr(sz, *p,len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_not_of(wxUniChar ch, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - for ( const_iterator p = begin() + nStart; p != begin(); --p ) - { - if ( *p != ch ) - return p - begin(); - } - - return npos; -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, +wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen, const wxChar *sz) { wxASSERT_MSG( nStart <= length(), - _T("index out of bounds in wxStringBase::replace") ); + _T("index out of bounds in wxStringImpl::replace") ); size_t strLen = length() - nStart; nLen = strLen < nLen ? strLen : nLen; - wxStringBase strTmp; + wxStringImpl strTmp; strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs //This is kind of inefficient, but its pretty good considering... @@ -747,34 +619,34 @@ wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, return *this; } -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - size_t nCount, wxUniChar ch) +wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen, + size_t nCount, wxStringCharType ch) { - return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); + return replace(nStart, nLen, wxStringImpl(nCount, ch).c_str()); } -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxStringBase& str, +wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen, + const wxStringImpl& str, size_t nStart2, size_t nLen2) { return replace(nStart, nLen, str.substr(nStart2, nLen2)); } -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, +wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen, const wxChar* sz, size_t nCount) { - return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); + return replace(nStart, nLen, wxStringImpl(sz, nCount).c_str()); } -wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const +wxStringImpl wxStringImpl::substr(size_t nStart, size_t nLen) const { if ( nLen == npos ) nLen = length() - nStart; - return wxStringBase(*this, nStart, nLen); + return wxStringImpl(*this, nStart, nLen); } // assigns one string to another -wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) +wxStringImpl& wxStringImpl::operator=(const wxStringImpl& stringSrc) { wxASSERT( stringSrc.GetStringData()->IsValid() ); @@ -795,26 +667,26 @@ wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) } // assigns a single character -wxStringBase& wxStringBase::operator=(wxUniChar ch) +wxStringImpl& wxStringImpl::operator=(wxStringCharType ch) { wxChar c(ch); if ( !AssignCopy(1, &c) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); + wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(wxChar)") ); } return *this; } // assigns C string -wxStringBase& wxStringBase::operator=(const wxChar *psz) +wxStringImpl& wxStringImpl::operator=(const wxChar *psz) { if ( !AssignCopy(wxStrlen(psz), psz) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); + wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(const wxChar *)") ); } return *this; } // helper function: does real copy -bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) +bool wxStringImpl::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) { if ( nSrcLen == 0 ) { Reinit(); @@ -836,7 +708,7 @@ bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) // --------------------------------------------------------------------------- // add something to this string -bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, +bool wxStringImpl::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, size_t nMaxLen) { STATISTICS_ADD(SummandLength, nSrcLen); @@ -893,48 +765,113 @@ bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, #endif // !wxUSE_STL_BASED_WXSTRING -#if !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE) +#ifdef HAVE_STD_STRING_COMPARE -#if !wxUSE_STL_BASED_WXSTRING - #define STRINGCLASS wxStringBase -#else - #define STRINGCLASS wxString -#endif +// NB: Comparison code (both if HAVE_STD_STRING_COMPARE and if not) works with +// UTF-8 encoded strings too, thanks to UTF-8's design which allows us to +// sort strings in characters code point order by sorting the byte sequence +// in byte values order (i.e. what strcmp() and memcmp() do). + +int wxString::compare(const wxString& str) const +{ + return m_impl.compare(str.m_impl); +} + +int wxString::compare(size_t nStart, size_t nLen, + const wxString& str) const +{ + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + return m_impl.compare(pos, len, str.m_impl); +} + +int wxString::compare(size_t nStart, size_t nLen, + const wxString& str, + size_t nStart2, size_t nLen2) const +{ + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + size_t pos2, len2; + str.PosLenToImpl(nStart2, nLen2, &pos2, &len2); + + return m_impl.compare(pos, len, str.m_impl, pos2, len2); +} + +int wxString::compare(const char* sz) const +{ + return m_impl.compare(ImplStr(sz)); +} + +int wxString::compare(const wchar_t* sz) const +{ + return m_impl.compare(ImplStr(sz)); +} + +int wxString::compare(size_t nStart, size_t nLen, + const char* sz, size_t nCount) const +{ + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + SubstrBufFromMB str(sz, nCount); -static inline int wxDoCmp(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) + return m_impl.compare(pos, len, str.data, str.len); +} + +int wxString::compare(size_t nStart, size_t nLen, + const wchar_t* sz, size_t nCount) const +{ + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + SubstrBufFromWC str(sz, nCount); + + return m_impl.compare(pos, len, str.data, str.len); +} + +#else // !HAVE_STD_STRING_COMPARE + +static inline int wxDoCmp(const wxStringCharType* s1, size_t l1, + const wxStringCharType* s2, size_t l2) { if( l1 == l2 ) - return wxTmemcmp(s1, s2, l1); + return wxStringMemcmp(s1, s2, l1); else if( l1 < l2 ) { - int ret = wxTmemcmp(s1, s2, l1); + int ret = wxStringMemcmp(s1, s2, l1); return ret == 0 ? -1 : ret; } else { - int ret = wxTmemcmp(s1, s2, l2); + int ret = wxStringMemcmp(s1, s2, l2); return ret == 0 ? +1 : ret; } } -int STRINGCLASS::compare(const wxStringBase& str) const +int wxString::compare(const wxString& str) const { - return ::wxDoCmp(data(), length(), str.data(), str.length()); + return ::wxDoCmp(m_impl.data(), m_impl.length(), + str.m_impl.data(), str.m_impl.length()); } -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str) const +int wxString::compare(size_t nStart, size_t nLen, + const wxString& str) const { wxASSERT(nStart <= length()); size_type strLen = length() - nStart; nLen = strLen < nLen ? strLen : nLen; - return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); + + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + return ::wxDoCmp(m_impl.data() + pos, len, + str.m_impl.data(), str.m_impl.length()); } -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str, - size_t nStart2, size_t nLen2) const +int wxString::compare(size_t nStart, size_t nLen, + const wxString& str, + size_t nStart2, size_t nLen2) const { wxASSERT(nStart <= length()); wxASSERT(nStart2 <= str.length()); @@ -942,30 +879,67 @@ int STRINGCLASS::compare(size_t nStart, size_t nLen, strLen2 = str.length() - nStart2; nLen = strLen < nLen ? strLen : nLen; nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; - return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); + + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + size_t pos2, len2; + str.PosLenToImpl(nStart2, nLen2, &pos2, &len2); + + return ::wxDoCmp(m_impl.data() + pos, len, + str.m_impl.data() + pos2, len2); +} + +int wxString::compare(const char* sz) const +{ + SubstrBufFromMB str(ImplStr(sz, npos)); + if ( str.len == npos ) + str.len = wxStringStrlen(str.data); + return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len); } -int STRINGCLASS::compare(const wxChar* sz) const +int wxString::compare(const wchar_t* sz) const { - size_t nLen = wxStrlen(sz); - return ::wxDoCmp(data(), length(), sz, nLen); + SubstrBufFromWC str(ImplStr(sz, npos)); + if ( str.len == npos ) + str.len = wxStringStrlen(str.data); + return ::wxDoCmp(m_impl.data(), m_impl.length(), str.data, str.len); } -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) const +int wxString::compare(size_t nStart, size_t nLen, + const char* sz, size_t nCount) const { wxASSERT(nStart <= length()); size_type strLen = length() - nStart; nLen = strLen < nLen ? strLen : nLen; - if( nCount == npos ) - nCount = wxStrlen(sz); - return ::wxDoCmp(data() + nStart, nLen, sz, nCount); + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + SubstrBufFromMB str(ImplStr(sz, nCount)); + if ( str.len == npos ) + str.len = wxStringStrlen(str.data); + + return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len); } -#undef STRINGCLASS +int wxString::compare(size_t nStart, size_t nLen, + const wchar_t* sz, size_t nCount) const +{ + wxASSERT(nStart <= length()); + size_type strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + + size_t pos, len; + PosLenToImpl(nStart, nLen, &pos, &len); + + SubstrBufFromWC str(ImplStr(sz, nCount)); + if ( str.len == npos ) + str.len = wxStringStrlen(str.data); + + return ::wxDoCmp(m_impl.data() + pos, len, str.data, str.len); +} -#endif // !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE) +#endif // HAVE_STD_STRING_COMPARE/!HAVE_STD_STRING_COMPARE // =========================================================================== // wxString class core @@ -975,11 +949,54 @@ int STRINGCLASS::compare(size_t nStart, size_t nLen, // construction and conversion // --------------------------------------------------------------------------- +#if wxUSE_UNICODE +/* static */ +wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength, + const wxMBConv& conv) +{ + // anything to do? + if ( !psz || nLength == 0 ) + return SubstrBufFromMB(); + + if ( nLength == npos ) + nLength = wxNO_LEN; + + size_t wcLen; + wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen)); + if ( !wcLen ) + return SubstrBufFromMB(); + else + return SubstrBufFromMB(wcBuf, wcLen); +} +#else +/* static */ +wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLength, + const wxMBConv& conv) +{ + // anything to do? + if ( !pwz || nLength == 0 ) + return SubstrBufFromWC(); + + if ( nLength == npos ) + nLength = wxNO_LEN; + + size_t mbLen; + wxCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen)); + if ( !mbLen ) + return SubstrBufFromWC(); + else + return SubstrBufFromWC(mbBuf, mbLen); +} +#endif + + #if wxUSE_UNICODE // from multibyte string wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) { + // FIXME-UTF8: this will need changes + // anything to do? if ( psz && nLength != 0 ) { @@ -996,6 +1013,11 @@ wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) } } +wxString::wxString(const char *psz, size_t nLength) +{ + assign(psz, nLength); +} + //Convert wxString in Unicode mode to a multi-byte string const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const { @@ -1009,6 +1031,8 @@ const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const // from wide string wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) { + // FIXME-UTF8: this will need changes + // anything to do? if ( pwz && nLength != 0 ) { @@ -1023,6 +1047,12 @@ wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) if ( nLenMB ) assign(buf, nLenMB); } + +} + +wxString::wxString(const wchar_t *pwz, size_t nLength) +{ + assign(pwz, nLength); } //Converts this string to a wide character string if unicode @@ -1044,9 +1074,9 @@ bool wxString::Shrink() return tmp.length() == length(); } -#if !wxUSE_STL_BASED_WXSTRING +#if !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // get the pointer to writable buffer of (at least) nLen bytes -wxChar *wxString::DoGetWriteBuf(size_t nLen) +wxChar *wxStringImpl::DoGetWriteBuf(size_t nLen) { if ( !AllocBeforeWrite(nLen) ) { // allocation failure handled by caller @@ -1060,12 +1090,12 @@ wxChar *wxString::DoGetWriteBuf(size_t nLen) } // put string back in a reasonable state after GetWriteBuf -void wxString::DoUngetWriteBuf() +void wxStringImpl::DoUngetWriteBuf() { DoUngetWriteBuf(wxStrlen(m_pchData)); } -void wxString::DoUngetWriteBuf(size_t nLen) +void wxStringImpl::DoUngetWriteBuf(size_t nLen) { wxStringData * const pData = GetStringData(); @@ -1095,7 +1125,7 @@ void wxString::UngetWriteBuf(size_t nLen) } #endif // WXWIN_COMPATIBILITY_2_8 -#endif // !wxUSE_STL_BASED_WXSTRING +#endif // !wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // --------------------------------------------------------------------------- @@ -1138,8 +1168,8 @@ wxString& wxString::operator=(const wchar_t *pwz) wxString operator+(const wxString& str1, const wxString& str2) { #if !wxUSE_STL_BASED_WXSTRING - wxASSERT( str1.GetStringData()->IsValid() ); - wxASSERT( str2.GetStringData()->IsValid() ); + wxASSERT( str1.IsValid() ); + wxASSERT( str2.IsValid() ); #endif wxString s = str1; @@ -1151,7 +1181,7 @@ wxString operator+(const wxString& str1, const wxString& str2) wxString operator+(const wxString& str, wxUniChar ch) { #if !wxUSE_STL_BASED_WXSTRING - wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( str.IsValid() ); #endif wxString s = str; @@ -1163,7 +1193,7 @@ wxString operator+(const wxString& str, wxUniChar ch) wxString operator+(wxUniChar ch, const wxString& str) { #if !wxUSE_STL_BASED_WXSTRING - wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( str.IsValid() ); #endif wxString s = ch; @@ -1172,14 +1202,14 @@ wxString operator+(wxUniChar ch, const wxString& str) return s; } -wxString operator+(const wxString& str, const wxChar *psz) +wxString operator+(const wxString& str, const char *psz) { #if !wxUSE_STL_BASED_WXSTRING - wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( str.IsValid() ); #endif wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + if ( !s.Alloc(strlen(psz) + str.length()) ) { wxFAIL_MSG( _T("out of memory in wxString::operator+") ); } s += str; @@ -1188,14 +1218,30 @@ wxString operator+(const wxString& str, const wxChar *psz) return s; } -wxString operator+(const wxChar *psz, const wxString& str) +wxString operator+(const wxString& str, const wchar_t *pwz) { #if !wxUSE_STL_BASED_WXSTRING - wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( str.IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s += str; + s += pwz; + + return s; +} + +wxString operator+(const char *psz, const wxString& str) +{ +#if !wxUSE_STL_BASED_WXSTRING + wxASSERT( str.IsValid() ); #endif wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + if ( !s.Alloc(strlen(psz) + str.length()) ) { wxFAIL_MSG( _T("out of memory in wxString::operator+") ); } s = psz; @@ -1204,64 +1250,236 @@ wxString operator+(const wxChar *psz, const wxString& str) return s; } -// =========================================================================== -// other common string functions -// =========================================================================== +wxString operator+(const wchar_t *pwz, const wxString& str) +{ +#if !wxUSE_STL_BASED_WXSTRING + wxASSERT( str.IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxWcslen(pwz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s = pwz; + s += str; + + return s; +} + +// --------------------------------------------------------------------------- +// find_{first,last}_[not]_of functions +// --------------------------------------------------------------------------- -int wxString::Cmp(const wxString& s) const +#if !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8 + +// NB: All these functions are implemented with the argument being wxChar*, +// i.e. widechar string in any Unicode build, even though native string +// representation is char* in the UTF-8 build. This is because we couldn't +// use memchr() to determine if a character is in a set encoded as UTF-8. + +size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const { - return compare(s); + return find_first_of(sz, nStart, wxStrlen(sz)); } -int wxString::Cmp(const wxChar* psz) const +size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const { - return compare(psz); + return find_first_not_of(sz, nStart, wxStrlen(sz)); } -static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) +size_t wxString::find_first_of(const wxChar* sz, size_t nStart, size_t n) const { - size_t i; + wxASSERT_MSG( nStart <= length(), _T("invalid index") ); - if( l1 == l2 ) + size_t idx = nStart; + for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i ) { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + if ( wxTmemchr(sz, *i, n) ) + return idx; } - else if( l1 < l2 ) + + return npos; +} + +size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart, size_t n) const +{ + wxASSERT_MSG( nStart <= length(), _T("invalid index") ); + + size_t idx = nStart; + for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i ) { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + if ( !wxTmemchr(sz, *i, n) ) + return idx; + } + + return npos; +} + + +size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const +{ + return find_last_of(sz, nStart, wxStrlen(sz)); +} + +size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const +{ + return find_last_not_of(sz, nStart, wxStrlen(sz)); +} + +size_t wxString::find_last_of(const wxChar* sz, size_t nStart, size_t n) const +{ + size_t len = length(); + + if ( nStart == npos ) + { + nStart = len - 1; } else { - for(i = 0; i < l2; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + wxASSERT_MSG( nStart <= len, _T("invalid index") ); + } + + size_t idx = nStart; + for ( const_reverse_iterator i = rbegin() + (len - nStart - 1); + i != rend(); --idx, ++i ) + { + if ( wxTmemchr(sz, *i, n) ) + return idx; } + + return npos; } -int wxString::CmpNoCase(const wxString& s) const +size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart, size_t n) const +{ + size_t len = length(); + + if ( nStart == npos ) + { + nStart = len - 1; + } + else + { + wxASSERT_MSG( nStart <= len, _T("invalid index") ); + } + + size_t idx = nStart; + for ( const_reverse_iterator i = rbegin() + (len - nStart - 1); + i != rend(); --idx, ++i ) + { + if ( !wxTmemchr(sz, *i, n) ) + return idx; + } + + return npos; +} + +size_t wxString::find_first_not_of(wxUniChar ch, size_t nStart) const { - return wxDoCmpNoCase(data(), length(), s.data(), s.length()); + wxASSERT_MSG( nStart <= length(), _T("invalid index") ); + + size_t idx = nStart; + for ( const_iterator i = begin() + nStart; i != end(); ++idx, ++i ) + { + if ( *i != ch ) + return idx; + } + + return npos; } -int wxString::CmpNoCase(const wxChar* psz) const +size_t wxString::find_last_not_of(wxUniChar ch, size_t nStart) const { - int nLen = wxStrlen(psz); + size_t len = length(); + + if ( nStart == npos ) + { + nStart = len - 1; + } + else + { + wxASSERT_MSG( nStart <= len, _T("invalid index") ); + } + + size_t idx = nStart; + for ( const_reverse_iterator i = rbegin() + (len - nStart - 1); + i != rend(); --idx, ++i ) + { + if ( *i != ch ) + return idx; + } + + return npos; +} + +// the functions above were implemented for wchar_t* arguments in Unicode +// build and char* in ANSI build; below are implementations for the other +// version: +#if wxUSE_UNICODE + #define wxOtherCharType char + #define STRCONV (const wxChar*)wxConvLibc.cMB2WC +#else + #define wxOtherCharType wchar_t + #define STRCONV (const wxChar*)wxConvLibc.cWC2MB +#endif + +size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart) const + { return find_first_of(STRCONV(sz), nStart); } + +size_t wxString::find_first_of(const wxOtherCharType* sz, size_t nStart, + size_t n) const + { return find_first_of(STRCONV(sz, n, NULL), nStart, n); } +size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart) const + { return find_last_of(STRCONV(sz), nStart); } +size_t wxString::find_last_of(const wxOtherCharType* sz, size_t nStart, + size_t n) const + { return find_last_of(STRCONV(sz, n, NULL), nStart, n); } +size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart) const + { return find_first_not_of(STRCONV(sz), nStart); } +size_t wxString::find_first_not_of(const wxOtherCharType* sz, size_t nStart, + size_t n) const + { return find_first_not_of(STRCONV(sz, n, NULL), nStart, n); } +size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart) const + { return find_last_not_of(STRCONV(sz), nStart); } +size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart, + size_t n) const + { return find_last_not_of(STRCONV(sz, n, NULL), nStart, n); } + +#undef wxOtherCharType +#undef STRCONV + +#endif // !wxUSE_STL_BASED_WXSTRING || wxUSE_UNICODE_UTF8 + +// =========================================================================== +// other common string functions +// =========================================================================== + +int wxString::CmpNoCase(const wxString& s) const +{ + // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added + + size_t idx = 0; + const_iterator i1 = begin(); + const_iterator end1 = end(); + const_iterator i2 = s.begin(); + const_iterator end2 = s.end(); + + for ( ; i1 != end1 && i2 != end2; ++idx, ++i1, ++i2 ) + { + wxUniChar lower1 = (wxChar)wxTolower(*i1); + wxUniChar lower2 = (wxChar)wxTolower(*i2); + if ( lower1 != lower2 ) + return lower1 < lower2 ? -1 : 1; + } + + size_t len1 = length(); + size_t len2 = s.length(); - return wxDoCmpNoCase(data(), length(), psz, nLen); + if ( len1 < len2 ) + return -1; + else if ( len1 > len2 ) + return 1; + return 0; } @@ -2041,10 +2259,9 @@ match: int wxString::Freq(wxUniChar ch) const { int count = 0; - int len = length(); - for (int i = 0; i < len; i++) + for ( const_iterator i = begin(); i != end(); ++i ) { - if (GetChar(i) == ch) + if ( *i == ch ) count ++; } return count; diff --git a/src/common/strvararg.cpp b/src/common/strvararg.cpp index e3435e6713..00e30cbf84 100644 --- a/src/common/strvararg.cpp +++ b/src/common/strvararg.cpp @@ -32,14 +32,14 @@ // implementation // ============================================================================ -const wxArgNativeCharType *wxArgNormalizer::get() const +const wxStringCharType *wxArgNormalizer::get() const { return m_value; } -const wxArgNativeCharType *wxArgNormalizer::get() const +const wxStringCharType *wxArgNormalizer::get() const { - return m_value.c_str(); + return m_value.wx_str(); } #if wxUSE_UNICODE_WCHAR -- 2.45.2