//According to STL _must_ be a -1 size_t
const size_t wxString::npos = (size_t) -1;
+#if wxUSE_STRING_POS_CACHE
+
+#ifdef wxHAS_COMPILER_TLS
+
+wxTLS_TYPE(wxString::Cache) wxString::ms_cache;
+
+#else // !wxHAS_COMPILER_TLS
+
+struct wxStrCacheInitializer
+{
+ wxStrCacheInitializer()
+ {
+ // calling this function triggers s_cache initialization in it, and
+ // from now on it becomes safe to call from multiple threads
+ wxString::GetCache();
+ }
+};
+
+/*
+wxString::Cache& wxString::GetCache()
+{
+ static wxTLS_TYPE(Cache) s_cache;
+
+ return wxTLS_VALUE(s_cache);
+}
+*/
+
+static wxStrCacheInitializer gs_stringCacheInit;
+
+#endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS
+
+// gdb seems to be unable to display thread-local variables correctly, at least
+// not my 6.4.98 version under amd64, so provide this debugging helper to do it
+#ifdef __WXDEBUG__
+
+struct wxStrCacheDumper
+{
+ static void ShowAll()
+ {
+ puts("*** wxString cache dump:");
+ for ( unsigned n = 0; n < wxString::Cache::SIZE; n++ )
+ {
+ const wxString::Cache::Element&
+ c = wxString::GetCacheBegin()[n];
+
+ printf("\t%u%s\t%p: pos=(%lu, %lu), len=%ld\n",
+ n,
+ n == wxString::LastUsedCacheElement() ? " [*]" : "",
+ c.str,
+ (unsigned long)c.pos,
+ (unsigned long)c.impl,
+ (long)c.len);
+ }
+ }
+};
+
+void wxDumpStrCache() { wxStrCacheDumper::ShowAll(); }
+
+#endif // __WXDEBUG__
+
+#ifdef wxPROFILE_STRING_CACHE
+
+wxString::CacheStats wxString::ms_cacheStats;
+
+struct wxStrCacheStatsDumper
+{
+ ~wxStrCacheStatsDumper()
+ {
+ const wxString::CacheStats& stats = wxString::ms_cacheStats;
+
+ if ( stats.postot )
+ {
+ puts("*** wxString cache statistics:");
+ printf("\tTotal non-trivial calls to PosToImpl(): %u\n",
+ stats.postot);
+ printf("\tHits %u (of which %u not used) or %.2f%%\n",
+ stats.poshits,
+ stats.mishits,
+ 100.*float(stats.poshits - stats.mishits)/stats.postot);
+ printf("\tAverage position requested: %.2f\n",
+ float(stats.sumpos) / stats.postot);
+ printf("\tAverage offset after cached hint: %.2f\n",
+ float(stats.sumofs) / stats.postot);
+ }
+
+ if ( stats.lentot )
+ {
+ printf("\tNumber of calls to length(): %u, hits=%.2f%%\n",
+ stats.lentot, 100.*float(stats.lenhits)/stats.lentot);
+ }
+ }
+};
+
+static wxStrCacheStatsDumper s_showCacheStats;
+
+#endif // wxPROFILE_STRING_CACHE
+
+#endif // wxUSE_STRING_POS_CACHE
+
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
size_t *implPos, size_t *implLen) const
{
if ( pos == npos )
+ {
*implPos = npos;
- else
+ }
+ else // have valid start position
{
- const_iterator i = begin() + pos;
- *implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
+ const const_iterator b = GetIterForNthChar(pos);
+ *implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
if ( len == npos )
+ {
*implLen = npos;
- else
+ }
+ else // have valid length too
{
- // too large length is interpreted as "to the end of the string"
- // FIXME-UTF8: verify this is the case in std::string, assert
- // otherwise
- if ( pos + len > length() )
- len = length() - pos;
-
- *implLen = (i + len).impl() - i.impl();
+ // we need to handle the case of length specifying a substring
+ // going beyond the end of the string, just as std::string does
+ const const_iterator e(end());
+ const_iterator i(b);
+ while ( len && i <= e )
+ {
+ ++i;
+ --len;
+ }
+
+ *implLen = i.impl() - b.impl();
}
}
}
// UTF-8 sequence and psz may be invalid:
if ( wxStringOperations::IsValidUtf8String(psz, nLength) )
{
+ // we must pass the real string length to SubstrBufFromMB ctor
+ if ( nLength == npos )
+ nLength = psz ? strlen(psz) : 0;
return SubstrBufFromMB(wxCharBuffer::CreateNonOwned(psz), nLength);
}
// else: do the roundtrip through wchar_t*
wxCHECK_MSG( !strOld.empty(), 0,
_T("wxString::Replace(): invalid parameter") );
+ wxSTRING_INVALIDATE_CACHE();
+
size_t uiCount = 0; // count of replacements made
- size_t uiOldLen = strOld.length();
- size_t uiNewLen = strNew.length();
+ // optimize the special common case: replacement of one character by
+ // another one (in UTF-8 case we can only do this for ASCII characters)
+ //
+ // benchmarks show that this special version is around 3 times faster
+ // (depending on the proportion of matching characters and UTF-8/wchar_t
+ // build)
+ if ( strOld.m_impl.length() == 1 && strNew.m_impl.length() == 1 )
+ {
+ const wxStringCharType chOld = strOld.m_impl[0],
+ chNew = strNew.m_impl[0];
+
+ // this loop is the simplified version of the one below
+ for ( size_t pos = 0; ; )
+ {
+ pos = m_impl.find(chOld, pos);
+ if ( pos == npos )
+ break;
- size_t dwPos = 0;
+ m_impl[pos++] = chNew;
- while ( (*this)[dwPos] != wxT('\0') )
+ uiCount++;
+
+ if ( !bReplaceAll )
+ break;
+ }
+ }
+ else // general case
{
- //DO NOT USE STRSTR HERE
- //this string can contain embedded null characters,
- //so strstr will function incorrectly
- dwPos = find(strOld, dwPos);
- if ( dwPos == npos )
- break; // exit the loop
- else
+ const size_t uiOldLen = strOld.m_impl.length();
+ const size_t uiNewLen = strNew.m_impl.length();
+
+ for ( size_t pos = 0; ; )
{
- //replace this occurance of the old string with the new one
- replace(dwPos, uiOldLen, strNew, uiNewLen);
+ pos = m_impl.find(strOld.m_impl, pos);
+ if ( pos == npos )
+ break;
+
+ // replace this occurrence of the old string with the new one
+ m_impl.replace(pos, uiOldLen, strNew.m_impl);
- //move up pos past the string that was replaced
- dwPos += uiNewLen;
+ // move up pos past the string that was replaced
+ pos += uiNewLen;
- //increase replace count
- ++uiCount;
+ // increase replace count
+ uiCount++;
- // stop now?
+ // stop after the first one?
if ( !bReplaceAll )
- break; // exit the loop
+ break;
}
}
return *this;
}
+wxString& wxString::MakeCapitalized()
+{
+ const iterator en = end();
+ iterator it = begin();
+ if ( it != en )
+ {
+ *it = (wxChar)wxToupper(*it);
+ for ( ++it; it != en; ++it )
+ *it = (wxChar)wxTolower(*it);
+ }
+
+ return *this;
+}
+
// ---------------------------------------------------------------------------
// trimming and padding
// ---------------------------------------------------------------------------
return count;
}
-// convert to upper case, return the copy of the string
-wxString wxString::Upper() const
-{ wxString s(*this); return s.MakeUpper(); }
-
-// convert to lower case, return the copy of the string
-wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
-
// ----------------------------------------------------------------------------
// wxUTF8StringBuffer
// ----------------------------------------------------------------------------
wbuf.SetLength(wlen);
}
#endif // wxUSE_UNICODE_WCHAR
+
+// ----------------------------------------------------------------------------
+// wxCharBufferType<T>
+// ----------------------------------------------------------------------------
+
+#ifndef __VMS_BROKEN_TEMPLATES
+template<>
+#endif
+wxCharTypeBuffer<char>::Data
+wxCharTypeBuffer<char>::NullData(NULL);
+
+#ifndef __VMS_BROKEN_TEMPLATES
+template<>
+#endif
+wxCharTypeBuffer<wchar_t>::Data
+wxCharTypeBuffer<wchar_t>::NullData(NULL);