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:
parent
8fad8b2e52
commit
68482dc584
@ -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
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user