add cache for last used position and string length to UTF-8 wxString, dramatically improving performance of the code using indices to iterate over strings

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55333 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2008-08-28 19:19:11 +00:00
parent 8fad8b2e52
commit 68482dc584
4 changed files with 877 additions and 188 deletions

View File

@ -84,11 +84,12 @@ struct wxIsMovable<const T*>
#endif // !VC++ < 7
// Our implementation of wxString is written in such way that it's safe to move
// it around. OTOH, we don't know anything about std::string.
// it around (unless position cache is used which unfortunately breaks this).
// OTOH, we don't know anything about std::string.
// (NB: we don't put this into string.h and choose to include wx/string.h from
// here instead so that rarely-used wxIsMovable<T> code isn't included by
// everything)
#if !wxUSE_STL
#if !wxUSE_STL && !wxUSE_STRING_POS_CACHE
WX_DECLARE_TYPE_MOVABLE(wxString)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -58,6 +58,80 @@
//According to STL _must_ be a -1 size_t
const size_t wxString::npos = (size_t) -1;
#if wxUSE_STRING_POS_CACHE
wxTLS_TYPE(wxString::Cache) wxString::ms_cache;
// 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::ms_cache.cached[n];
printf("\t%u%s\t%p: pos=(%lu, %lu), len=%ld\n",
n,
n == wxString::ms_cache.lastUsed ? " [*]" : "",
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;
namespace
{
struct ShowCacheStats
{
~ShowCacheStats()
{
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);
}
}
} s_showCacheStats;
} // anonymous namespace
#endif // wxPROFILE_STRING_CACHE
#endif // wxUSE_STRING_POS_CACHE
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
@ -123,22 +197,30 @@ void wxString::PosLenToImpl(size_t pos, size_t len,
size_t *implPos, size_t *implLen) const
{
if ( pos == npos )
*implPos = npos;
else
{
const_iterator i = begin() + pos;
*implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
*implPos = npos;
}
else // have valid start position
{
const const_iterator b = GetIterForNthChar(pos);
*implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
if ( len == npos )
*implLen = npos;
else
{
// 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 = npos;
}
else // have valid length too
{
// 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 + len).impl() - i.impl();
*implLen = i.impl() - b.impl();
}
}
}
@ -1237,6 +1319,8 @@ size_t wxString::Replace(const wxString& strOld,
wxCHECK_MSG( !strOld.empty(), 0,
_T("wxString::Replace(): invalid parameter") );
wxSTRING_INVALIDATE_CACHE();
size_t uiCount = 0; // count of replacements made
// optimize the special common case: replacement of one character by

View File

@ -100,7 +100,7 @@ wxUniCharRef& wxUniCharRef::operator=(const wxUniChar& c)
for ( size_t i = 0; i < lenNew; ++i, ++pos )
*pos = utf[i];
}
else
else // length of character encoding in UTF-8 changed
{
// the worse case is when the new value has either longer or shorter
// code -- in that case, we have to use wxStringImpl::replace() and
@ -148,6 +148,10 @@ wxUniCharRef& wxUniCharRef::operator=(const wxUniChar& c)
// update the string:
strimpl.replace(m_pos, m_pos + lenOld, utf, lenNew);
#if wxUSE_STRING_POS_CACHE
m_str.InvalidateCache();
#endif // wxUSE_STRING_POS_CACHE
// finally, set the iterators to valid values again (note that this
// updates m_pos as well):
size_t i;