- #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 wxStringImpl::npos = (size_t) -1;
-#endif
-const size_t wxString::npos = (size_t) -1;
-
-// ----------------------------------------------------------------------------
-// static data
-// ----------------------------------------------------------------------------
-
-#if wxUSE_STL_BASED_WXSTRING
-
-extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
-
-#else
-
-// for an empty string, GetStringData() will return this address: this
-// structure has the same layout as wxStringData and it's data() method will
-// return the empty string (dummy pointer)
-static const struct
-{
- wxStringData data;
- wxChar dummy;
-} g_strEmpty = { {-1, 0, 0}, wxT('\0') };
-
-// empty C style string: points to 'string data' byte of g_strEmpty
-extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
-
-#endif
-
-// ----------------------------------------------------------------------------
-// global functions
-// ----------------------------------------------------------------------------
-
-#if wxUSE_STD_IOSTREAM
-
-#include <iostream>
-
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
-{
- return os << str.c_str();
-}
-
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
-{
-#if wxUSE_UNICODE && !defined(__BORLANDC__)
- return os << str.AsWChar();
-#else
- return os << str.AsChar();
-#endif
-}
-
-#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_BASED_WXSTRING
-
-// ===========================================================================
-// 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
-
-// ===========================================================================
-// wxStringImpl
-// ===========================================================================
-
-// takes nLength elements of psz starting at nPos
-void wxStringImpl::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 wxStringImpl::InitWith") );
- return;
- }
- wxStringMemcpy(m_pchData, psz + nPos, nLength);
- }
-}
-
-// poor man's iterators are "void *" pointers
-wxStringImpl::wxStringImpl(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();
- }
-}
-
-wxStringImpl::wxStringImpl(size_type n, wxStringCharType ch)
-{
- Init();
- append(n, ch);
-}
-
-// ---------------------------------------------------------------------------
-// memory allocation
-// ---------------------------------------------------------------------------
-
-// allocates memory needed to store a C string of length nLen
-bool wxStringImpl::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 wxStringImpl::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;
- }
- wxStringMemcpy(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 wxStringImpl::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;
-}
-
-wxStringImpl& wxStringImpl::append(size_t n, wxStringCharType ch)
-{
- size_type len = length();
-
- if ( !Alloc(len + n) || !CopyBeforeWrite() ) {
- wxFAIL_MSG( _T("out of memory in wxStringImpl::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 wxStringImpl::resize(size_t nSize, wxStringCharType 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 wxStringImpl::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;
-}
-
-wxStringImpl::iterator wxStringImpl::begin()
-{
- if (length() > 0)
- CopyBeforeWrite();
- return m_pchData;
-}
-
-wxStringImpl::iterator wxStringImpl::end()
-{
- if (length() > 0)
- CopyBeforeWrite();
- return m_pchData + length();
-}
-
-wxStringImpl::iterator wxStringImpl::erase(iterator it)
-{
- size_type idx = it - begin();
- erase(idx, 1);
- return begin() + idx;
-}
-
-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;
- wxStringImpl strTmp(c_str(), nStart);
- strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen);
-
- swap(strTmp);
- return *this;
-}
-
-wxStringImpl& wxStringImpl::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 wxStringImpl::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 wxStringImpl::swap(wxStringImpl& str)
-{
- wxStringCharType* tmp = str.m_pchData;
- str.m_pchData = m_pchData;
- m_pchData = tmp;
-}
-
-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();
- 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 wxStringCharType * const other = str.c_str();
-
- // anchor
- const wxStringCharType* p =
- (const wxStringCharType*)wxStringMemchr(c_str() + nStart,
- *other,
- nLen - nStart);
-
- if ( !p )
- return npos;
-
- while ( p - c_str() + nLenOther <= nLen &&
- wxStringMemcmp(p, other, nLenOther) )
- {
- p++;
-
- // anchor again
- p = (const wxStringCharType*)
- wxStringMemchr(p, *other, nLen - (p - c_str()));
-
- if ( !p )
- return npos;
- }
-
- return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
-}
-
-size_t wxStringImpl::find(const wxChar* sz, size_t nStart, size_t n) const
-{
- return find(wxStringImpl(sz, n), nStart);
-}
-
-size_t wxStringImpl::find(wxStringCharType ch, size_t nStart) const
-{
- wxASSERT( nStart <= length() );
-
- const wxStringCharType *p = (const wxStringCharType*)
- wxStringMemchr(c_str() + nStart, ch, length() - nStart);
-
- return p == NULL ? npos : p - c_str();
-}
-
-size_t wxStringImpl::rfind(const wxStringImpl& 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 wxStringCharType *cursor = c_str() + top;
- do
- {
- if ( wxStringMemcmp(cursor, str.c_str(), str.length()) == 0 )
- {
- return cursor - c_str();
- }
- } while ( cursor-- > c_str() );
- }
-
- return npos;
-}
-
-size_t wxStringImpl::rfind(const wxChar* sz, size_t nStart, size_t n) const
-{
- return rfind(wxStringImpl(sz, n), nStart);
-}
-
-size_t wxStringImpl::rfind(wxStringCharType ch, size_t nStart) const
-{
- if ( nStart == npos )
- {
- nStart = length();
- }
- else
- {
- wxASSERT( nStart <= length() );
- }
-
- const wxStringCharType *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;
-}
-
-wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
- const wxChar *sz)
-{
- wxASSERT_MSG( nStart <= length(),
- _T("index out of bounds in wxStringImpl::replace") );
- size_t strLen = length() - nStart;
- nLen = strLen < nLen ? strLen : nLen;
-
- wxStringImpl 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;
-}
-
-wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
- size_t nCount, wxStringCharType ch)
-{
- return replace(nStart, nLen, wxStringImpl(nCount, ch).c_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));
-}
-
-wxStringImpl& wxStringImpl::replace(size_t nStart, size_t nLen,
- const wxChar* sz, size_t nCount)
-{
- return replace(nStart, nLen, wxStringImpl(sz, nCount).c_str());
-}
-
-wxStringImpl wxStringImpl::substr(size_t nStart, size_t nLen) const
-{
- if ( nLen == npos )
- nLen = length() - nStart;
- return wxStringImpl(*this, nStart, nLen);
-}
-
-// assigns one string to another
-wxStringImpl& wxStringImpl::operator=(const wxStringImpl& 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
-wxStringImpl& wxStringImpl::operator=(wxStringCharType ch)
-{
- wxChar c(ch);
- if ( !AssignCopy(1, &c) ) {
- wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(wxChar)") );
- }
- return *this;
-}
-
-// assigns C string
-wxStringImpl& wxStringImpl::operator=(const wxChar *psz)
-{
- if ( !AssignCopy(wxStrlen(psz), psz) ) {
- wxFAIL_MSG( _T("out of memory in wxStringImpl::operator=(const wxChar *)") );
- }
- return *this;
-}
-
-// helper function: does real copy
-bool wxStringImpl::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 wxStringImpl::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;
-}
-
-#endif // !wxUSE_STL_BASED_WXSTRING
-
-#ifdef HAVE_STD_STRING_COMPARE
-
-// 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(ImplStr(sz, nCount));
-
- 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(ImplStr(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 wxStringMemcmp(s1, s2, l1);
- else if( l1 < l2 )
- {
- int ret = wxStringMemcmp(s1, s2, l1);
- return ret == 0 ? -1 : ret;
- }
- else
- {
- int ret = wxStringMemcmp(s1, s2, l2);
- return ret == 0 ? +1 : ret;
- }
-}
-
-int wxString::compare(const wxString& str) const
-{
- return ::wxDoCmp(m_impl.data(), m_impl.length(),
- str.m_impl.data(), str.m_impl.length());
-}
-
-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;
-
- 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 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());
- size_type strLen = length() - nStart,
- strLen2 = str.length() - nStart2;
- nLen = strLen < nLen ? strLen : nLen;
- nLen2 = strLen2 < nLen2 ? strLen2 : nLen2;
-
- size_t pos, len;
- PosLenToImpl(nStart, nLen, &pos, &len);
- size_t pos2, len2;
- str.PosLenToImpl(nStart2, nLen2, &pos2, &len2);