+ // it's not important if the pointer changed or not (the check for this
+ // is not faster than assigning to m_pchData in all cases)
+ pData->nAllocLength = nLen;
+ m_pchData = pData->data();
+ }
+ }
+ //else: we've already got enough
+ return true;
+}
+
+wxStringBase::iterator wxStringBase::begin()
+{
+ if (length() > 0)
+ CopyBeforeWrite();
+ return m_pchData;
+}
+
+wxStringBase::iterator wxStringBase::end()
+{
+ if (length() > 0)
+ CopyBeforeWrite();
+ return m_pchData + length();
+}
+
+wxStringBase::iterator wxStringBase::erase(iterator it)
+{
+ size_type idx = it - begin();
+ erase(idx, 1);
+ return begin() + idx;
+}
+
+wxStringBase& wxStringBase::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);
+ 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)
+{
+ wxASSERT( nPos <= length() );
+
+ if ( n == npos ) n = wxStrlen(sz);
+ if ( n == 0 ) return *this;
+
+ if ( !Alloc(length() + n) || !CopyBeforeWrite() ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::insert") );
+ }
+
+ memmove(m_pchData + nPos + n, m_pchData + nPos,
+ (length() - nPos) * sizeof(wxChar));
+ memcpy(m_pchData + nPos, sz, n * sizeof(wxChar));
+ GetStringData()->nDataLength = length() + n;
+ m_pchData[length()] = '\0';
+
+ return *this;
+}
+
+void wxStringBase::swap(wxStringBase& str)
+{
+ wxChar* tmp = str.m_pchData;
+ str.m_pchData = m_pchData;
+ m_pchData = tmp;
+}
+
+size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
+{
+ wxASSERT( str.GetStringData()->IsValid() );
+ wxASSERT( nStart <= length() );
+
+ //anchor
+ const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
+ str.c_str()[0],
+ length() - nStart);
+
+ if(!p)
+ return npos;
+
+ while(p - c_str() + str.length() <= length() &&
+ wxTmemcmp(p, str.c_str(), str.length()) )
+ {
+ //Previosly passed as the first argument to wxTmemchr,
+ //but C/C++ standard does not specify evaluation order
+ //of arguments to functions -
+ //http://embedded.com/showArticle.jhtml?articleID=9900607
+ ++p;
+
+ //anchor again
+ p = (const wxChar*)wxTmemchr(p,
+ str.c_str()[0],
+ length() - (p - c_str()));
+
+ if(!p)
+ return npos;
+ }
+
+ return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
+}
+
+size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
+{
+ return find(wxStringBase(sz, n), nStart);
+}
+
+size_t wxStringBase::find(wxChar ch, size_t nStart) const
+{
+ wxASSERT( nStart <= length() );
+
+ const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart);
+
+ return p == NULL ? npos : p - c_str();
+}
+
+size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const
+{
+ wxASSERT( str.GetStringData()->IsValid() );
+ wxASSERT( nStart == npos || nStart <= length() );
+
+ if ( length() >= str.length() )
+ {
+ // avoids a corner case later
+ if ( length() == 0 && str.length() == 0 )
+ return 0;
+
+ // "top" is the point where search starts from
+ size_t top = length() - str.length();
+
+ if ( nStart == npos )
+ nStart = length() - 1;
+ if ( nStart < top )
+ top = nStart;
+
+ const wxChar *cursor = c_str() + top;
+ do
+ {
+ if ( wxTmemcmp(cursor, str.c_str(),
+ str.length()) == 0 )
+ {
+ return cursor - c_str();
+ }
+ } while ( cursor-- > c_str() );
+ }
+
+ return npos;
+}
+
+size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
+{
+ return rfind(wxStringBase(sz, n), nStart);
+}
+
+size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
+{
+ if ( nStart == npos )
+ {
+ nStart = length();
+ }
+ else
+ {
+ wxASSERT( nStart <= length() );
+ }
+
+ const wxChar *actual;
+ for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 );
+ actual > c_str(); --actual )
+ {
+ if ( *(actual - 1) == ch )
+ return (actual - 1) - c_str();
+ }
+
+ 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(wxChar ch, size_t nStart) const
+{
+ wxASSERT( nStart <= length() );
+
+ for ( const wxChar *p = c_str() + nStart; *p; p++ )
+ {
+ if ( *p != ch )
+ return p - c_str();
+ }
+
+ 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(wxChar ch, size_t nStart) const
+{
+ if ( nStart == npos )
+ {
+ nStart = length() - 1;
+ }
+ else
+ {
+ wxASSERT( nStart <= length() );
+ }
+
+ for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
+ {
+ if ( *p != ch )
+ return p - c_str();
+ }
+
+ return npos;
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ const wxChar *sz)
+{
+ wxASSERT_MSG( nStart <= length(),
+ _T("index out of bounds in wxStringBase::replace") );
+ size_t strLen = length() - nStart;
+ nLen = strLen < nLen ? strLen : nLen;
+
+ wxStringBase strTmp;
+ strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs
+
+ //This is kind of inefficient, but its pretty good considering...
+ //we don't want to use character access operators here because on STL
+ //it will freeze the reference count of strTmp, which means a deep copy
+ //at the end when swap is called
+ //
+ //Also, we can't use append with the full character pointer and must
+ //do it manually because this string can contain null characters
+ for(size_t i1 = 0; i1 < nStart; ++i1)
+ strTmp.append(1, this->c_str()[i1]);
+
+ //its safe to do the full version here because
+ //sz must be a normal c string
+ strTmp.append(sz);
+
+ for(size_t i2 = nStart + nLen; i2 < length(); ++i2)
+ strTmp.append(1, this->c_str()[i2]);
+
+ swap(strTmp);
+ return *this;
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ size_t nCount, wxChar ch)
+{
+ return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ const wxStringBase& str,
+ size_t nStart2, size_t nLen2)
+{
+ return replace(nStart, nLen, str.substr(nStart2, nLen2));
+}
+
+wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
+ const wxChar* sz, size_t nCount)
+{
+ return replace(nStart, nLen, wxStringBase(sz, nCount).c_str());
+}
+
+wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const
+{
+ if ( nLen == npos )
+ nLen = length() - nStart;
+ return wxStringBase(*this, nStart, nLen);
+}
+
+// assigns one string to another
+wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
+{
+ wxASSERT( stringSrc.GetStringData()->IsValid() );
+
+ // don't copy string over itself
+ if ( m_pchData != stringSrc.m_pchData ) {
+ if ( stringSrc.GetStringData()->IsEmpty() ) {
+ Reinit();
+ }
+ else {
+ // adjust references
+ GetStringData()->Unlock();
+ m_pchData = stringSrc.m_pchData;
+ GetStringData()->Lock();
+ }
+ }
+
+ return *this;
+}
+
+// assigns a single character
+wxStringBase& wxStringBase::operator=(wxChar ch)
+{
+ if ( !AssignCopy(1, &ch) ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
+ }
+ return *this;
+}
+
+// assigns C string
+wxStringBase& wxStringBase::operator=(const wxChar *psz)
+{
+ if ( !AssignCopy(wxStrlen(psz), psz) ) {
+ wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") );
+ }
+ return *this;
+}
+
+// helper function: does real copy
+bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
+{
+ if ( nSrcLen == 0 ) {
+ Reinit();
+ }
+ else {
+ if ( !AllocBeforeWrite(nSrcLen) ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
+ GetStringData()->nDataLength = nSrcLen;
+ m_pchData[nSrcLen] = wxT('\0');
+ }
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+// string concatenation
+// ---------------------------------------------------------------------------
+
+// add something to this string
+bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData,
+ size_t nMaxLen)
+{
+ STATISTICS_ADD(SummandLength, nSrcLen);
+
+ nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen;
+
+ // concatenating an empty string is a NOP
+ if ( nSrcLen > 0 ) {
+ wxStringData *pData = GetStringData();
+ size_t nLen = pData->nDataLength;
+ size_t nNewLen = nLen + nSrcLen;
+
+ // alloc new buffer if current is too small
+ if ( pData->IsShared() ) {
+ STATISTICS_ADD(ConcatHit, 0);
+
+ // we have to allocate another buffer
+ wxStringData* pOldData = GetStringData();
+ if ( !AllocBuffer(nNewLen) ) {
+ // allocation failure handled by caller
+ return false;
+ }
+ memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
+ pOldData->Unlock();
+ }
+ else if ( nNewLen > pData->nAllocLength ) {
+ STATISTICS_ADD(ConcatHit, 0);
+
+ reserve(nNewLen);
+ // we have to grow the buffer
+ if ( capacity() < nNewLen ) {
+ // allocation failure handled by caller
+ return false;