-// ----------------------------------------------------------------------------
-// global functions
-// ----------------------------------------------------------------------------
-
-#if wxUSE_STD_IOSTREAM
-
-#include <iostream>
-
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
-{
-#ifdef __BORLANDC__
- os << str.mb_str();
-#else
- os << str.c_str();
-#endif
- return os;
-}
-
-#endif // wxUSE_STD_IOSTREAM
-
-// ----------------------------------------------------------------------------
-// private classes
-// ----------------------------------------------------------------------------
-
-// this small class is used to gather statistics for performance tuning
-//#define WXSTRING_STATISTICS
-#ifdef WXSTRING_STATISTICS
- class Averager
- {
- public:
- Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
- ~Averager()
- { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
-
- void Add(size_t n) { m_nTotal += n; m_nCount++; }
-
- private:
- size_t m_nCount, m_nTotal;
- const wxChar *m_sz;
- } g_averageLength("allocation size"),
- g_averageSummandLength("summand length"),
- g_averageConcatHit("hit probability in concat"),
- g_averageInitialLength("initial string length");
-
- #define STATISTICS_ADD(av, val) g_average##av.Add(val)
-#else
- #define STATISTICS_ADD(av, val)
-#endif // WXSTRING_STATISTICS
-
-#if !wxUSE_STL
-
-// ===========================================================================
-// wxStringData class deallocation
-// ===========================================================================
-
-#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL)
-# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!")
-void wxStringData::Free()
-{
- free(this);
-}
-#endif
-
-// ===========================================================================
-// wxStringBase
-// ===========================================================================
-
-// takes nLength elements of psz starting at nPos
-void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
-{
- Init();
-
- // if the length is not given, assume the string to be NUL terminated
- if ( nLength == npos ) {
- wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
-
- nLength = wxStrlen(psz + nPos);
- }
-
- STATISTICS_ADD(InitialLength, nLength);
-
- if ( nLength > 0 ) {
- // trailing '\0' is written in AllocBuffer()
- if ( !AllocBuffer(nLength) ) {
- wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") );
- return;
- }
- wxTmemcpy(m_pchData, psz + nPos, nLength);
- }
-}
-
-// poor man's iterators are "void *" pointers
-wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
-{
- if ( pEnd >= pStart )
- {
- InitWith((const wxChar *)pStart, 0,
- (const wxChar *)pEnd - (const wxChar *)pStart);
- }
- else
- {
- wxFAIL_MSG( _T("pStart is not before pEnd") );
- Init();
- }
-}
-
-wxStringBase::wxStringBase(size_type n, wxChar ch)
-{
- Init();
- append(n, ch);
-}
-
-// ---------------------------------------------------------------------------
-// memory allocation
-// ---------------------------------------------------------------------------
-
-// allocates memory needed to store a C string of length nLen
-bool wxStringBase::AllocBuffer(size_t nLen)
-{
- // allocating 0 sized buffer doesn't make sense, all empty strings should
- // reuse g_strEmpty
- wxASSERT( nLen > 0 );
-
- // make sure that we don't overflow
- wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
- (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
-
- STATISTICS_ADD(Length, nLen);
-
- // allocate memory:
- // 1) one extra character for '\0' termination
- // 2) sizeof(wxStringData) for housekeeping info
- wxStringData* pData = (wxStringData*)
- malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
-
- if ( pData == NULL ) {
- // allocation failures are handled by the caller
- return false;
- }
-
- pData->nRefs = 1;
- pData->nDataLength = nLen;
- pData->nAllocLength = nLen + EXTRA_ALLOC;
- m_pchData = pData->data(); // data starts after wxStringData
- m_pchData[nLen] = wxT('\0');
- return true;
-}
-
-// must be called before changing this string
-bool wxStringBase::CopyBeforeWrite()
-{
- wxStringData* pData = GetStringData();
-
- if ( pData->IsShared() ) {
- pData->Unlock(); // memory not freed because shared
- size_t nLen = pData->nDataLength;
- if ( !AllocBuffer(nLen) ) {
- // allocation failures are handled by the caller
- return false;
- }
- wxTmemcpy(m_pchData, pData->data(), nLen);
- }
-
- wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
-
- return true;
-}
-
-// must be called before replacing contents of this string
-bool wxStringBase::AllocBeforeWrite(size_t nLen)
-{
- wxASSERT( nLen != 0 ); // doesn't make any sense
-
- // must not share string and must have enough space
- wxStringData* pData = GetStringData();
- if ( pData->IsShared() || pData->IsEmpty() ) {
- // can't work with old buffer, get new one
- pData->Unlock();
- if ( !AllocBuffer(nLen) ) {
- // allocation failures are handled by the caller
- return false;
- }
- }
- else {
- if ( nLen > pData->nAllocLength ) {
- // realloc the buffer instead of calling malloc() again, this is more
- // efficient
- STATISTICS_ADD(Length, nLen);
-
- nLen += EXTRA_ALLOC;
-
- pData = (wxStringData*)
- realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
-
- if ( pData == NULL ) {
- // allocation failures are handled by the caller
- // keep previous data since reallocation failed
- return false;
- }
-
- pData->nAllocLength = nLen;
- m_pchData = pData->data();
- }
- }
-
- wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
-
- // it doesn't really matter what the string length is as it's going to be
- // overwritten later but, for extra safety, set it to 0 for now as we may
- // have some junk in m_pchData
- GetStringData()->nDataLength = 0;
-
- return true;
-}
-
-wxStringBase& wxStringBase::append(size_t n, wxChar ch)
-{
- size_type len = length();
-
- if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
- wxFAIL_MSG( _T("out of memory in wxStringBase::append") );
- }
- GetStringData()->nDataLength = len + n;
- m_pchData[len + n] = '\0';
- for ( size_t i = 0; i < n; ++i )
- m_pchData[len + i] = ch;
- return *this;
-}
-
-void wxStringBase::resize(size_t nSize, wxChar ch)
-{
- size_t len = length();
-
- if ( nSize < len )
- {
- erase(begin() + nSize, end());
- }
- else if ( nSize > len )
- {
- append(nSize - len, ch);
- }
- //else: we have exactly the specified length, nothing to do
-}
-
-// allocate enough memory for nLen characters
-bool wxStringBase::Alloc(size_t nLen)
-{
- wxStringData *pData = GetStringData();
- if ( pData->nAllocLength <= nLen ) {
- if ( pData->IsEmpty() ) {
- nLen += EXTRA_ALLOC;
-
- pData = (wxStringData *)
- malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
-
- if ( pData == NULL ) {
- // allocation failure handled by caller
- return false;
- }
-
- pData->nRefs = 1;
- pData->nDataLength = 0;
- pData->nAllocLength = nLen;
- m_pchData = pData->data(); // data starts after wxStringData
- m_pchData[0u] = wxT('\0');
- }
- else if ( pData->IsShared() ) {
- pData->Unlock(); // memory not freed because shared
- size_t nOldLen = pData->nDataLength;
- if ( !AllocBuffer(nLen) ) {
- // allocation failure handled by caller
- return false;
- }
- // +1 to copy the terminator, too
- memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar));
- GetStringData()->nDataLength = nOldLen;
- }
- else {
- nLen += EXTRA_ALLOC;
-
- pData = (wxStringData *)
- realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
-
- if ( pData == NULL ) {
- // allocation failure handled by caller
- // keep previous data since reallocation failed
- return false;
- }
-
- // 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
-{
- // deal with the special case of empty string first
- const size_t nLen = length();
- const size_t nLenOther = str.length();
-
- if ( !nLenOther )
- {
- // empty string is a substring of anything
- return 0;
- }
-
- if ( !nLen )
- {
- // the other string is non empty so can't be our substring
- return npos;
- }
-
- wxASSERT( str.GetStringData()->IsValid() );
- wxASSERT( nStart <= nLen );
-
- const wxChar * const other = str.c_str();
-
- // anchor
- const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
- *other,
- nLen - nStart);
-
- if ( !p )
- return npos;
-
- while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
- {
- p++;
-
- // anchor again
- p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str()));
-
- if ( !p )
- return npos;
- }
-
- return p - c_str() + nLenOther <= nLen ? 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;
- }
- }
- else {
- STATISTICS_ADD(ConcatHit, 1);
-
- // the buffer is already big enough
- }
-
- // should be enough space
- wxASSERT( nNewLen <= GetStringData()->nAllocLength );
-
- // fast concatenation - all is done in our buffer
- memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
-
- m_pchData[nNewLen] = wxT('\0'); // put terminating '\0'
- GetStringData()->nDataLength = nNewLen; // and fix the length
- }
- //else: the string to append was empty
- return true;
-}
-
-// ---------------------------------------------------------------------------
-// simple sub-string extraction
-// ---------------------------------------------------------------------------
-
-// helper function: clone the data attached to this string
-bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
-{
- if ( nCopyLen == 0 ) {
- dest.Init();
- }
- else {
- if ( !dest.AllocBuffer(nCopyLen) ) {
- // allocation failure handled by caller
- return false;
- }
- memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
- }
- return true;
-}
-
-#endif // !wxUSE_STL
-
-#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
-
-#if !wxUSE_STL
- #define STRINGCLASS wxStringBase
-#else
- #define STRINGCLASS wxString
-#endif