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:
@@ -84,11 +84,12 @@ struct wxIsMovable<const T*>
|
|||||||
#endif // !VC++ < 7
|
#endif // !VC++ < 7
|
||||||
|
|
||||||
// Our implementation of wxString is written in such way that it's safe to move
|
// 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
|
// (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
|
// here instead so that rarely-used wxIsMovable<T> code isn't included by
|
||||||
// everything)
|
// everything)
|
||||||
#if !wxUSE_STL
|
#if !wxUSE_STL && !wxUSE_STRING_POS_CACHE
|
||||||
WX_DECLARE_TYPE_MOVABLE(wxString)
|
WX_DECLARE_TYPE_MOVABLE(wxString)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,80 @@
|
|||||||
//According to STL _must_ be a -1 size_t
|
//According to STL _must_ be a -1 size_t
|
||||||
const size_t wxString::npos = (size_t) -1;
|
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
|
// global functions
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -123,22 +197,30 @@ void wxString::PosLenToImpl(size_t pos, size_t len,
|
|||||||
size_t *implPos, size_t *implLen) const
|
size_t *implPos, size_t *implLen) const
|
||||||
{
|
{
|
||||||
if ( pos == npos )
|
if ( pos == npos )
|
||||||
*implPos = npos;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
const_iterator i = begin() + pos;
|
*implPos = npos;
|
||||||
*implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
|
}
|
||||||
|
else // have valid start position
|
||||||
|
{
|
||||||
|
const const_iterator b = GetIterForNthChar(pos);
|
||||||
|
*implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
|
||||||
if ( len == npos )
|
if ( len == npos )
|
||||||
*implLen = npos;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// too large length is interpreted as "to the end of the string"
|
*implLen = npos;
|
||||||
// FIXME-UTF8: verify this is the case in std::string, assert
|
}
|
||||||
// otherwise
|
else // have valid length too
|
||||||
if ( pos + len > length() )
|
{
|
||||||
len = length() - pos;
|
// 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,
|
wxCHECK_MSG( !strOld.empty(), 0,
|
||||||
_T("wxString::Replace(): invalid parameter") );
|
_T("wxString::Replace(): invalid parameter") );
|
||||||
|
|
||||||
|
wxSTRING_INVALIDATE_CACHE();
|
||||||
|
|
||||||
size_t uiCount = 0; // count of replacements made
|
size_t uiCount = 0; // count of replacements made
|
||||||
|
|
||||||
// optimize the special common case: replacement of one character by
|
// 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 )
|
for ( size_t i = 0; i < lenNew; ++i, ++pos )
|
||||||
*pos = utf[i];
|
*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
|
// the worse case is when the new value has either longer or shorter
|
||||||
// code -- in that case, we have to use wxStringImpl::replace() and
|
// code -- in that case, we have to use wxStringImpl::replace() and
|
||||||
@@ -148,6 +148,10 @@ wxUniCharRef& wxUniCharRef::operator=(const wxUniChar& c)
|
|||||||
// update the string:
|
// update the string:
|
||||||
strimpl.replace(m_pos, m_pos + lenOld, utf, lenNew);
|
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
|
// finally, set the iterators to valid values again (note that this
|
||||||
// updates m_pos as well):
|
// updates m_pos as well):
|
||||||
size_t i;
|
size_t i;
|
||||||
|
Reference in New Issue
Block a user