optimize Replace() to use a linear algorithm (closes #9135)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59420 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-03-07 16:07:58 +00:00
parent 101b242093
commit 072682ce44
4 changed files with 70 additions and 20 deletions

View File

@ -373,6 +373,7 @@ All:
- Added wxLog::Log().
- Added wxProtocolLog and use it in wxFTP.
- Added wxXmlResource::GetResourceNode().
- Optimize wxString::Replace() to use an O(N) algorithm (Kuang-che Wu).
All (Unix):

View File

@ -36,6 +36,7 @@
#include <stdlib.h>
#include "wx/hashmap.h"
#include "wx/vector.h"
// string handling functions used by wxString:
#if wxUSE_UNICODE_UTF8
@ -1397,30 +1398,62 @@ size_t wxString::Replace(const wxString& strOld,
break;
}
}
else // general case
else if ( !bReplaceAll)
{
size_t pos = m_impl.find(strOld, 0);
if ( pos != npos )
{
m_impl.replace(pos, strOld.m_impl.length(), strNew.m_impl);
uiCount = 1;
}
}
else // replace all occurrences
{
const size_t uiOldLen = strOld.m_impl.length();
const size_t uiNewLen = strNew.m_impl.length();
for ( size_t pos = 0; ; )
// first scan the string to find all positions at which the replacement
// should be made
wxVector<size_t> replacePositions;
size_t pos;
for ( pos = m_impl.find(strOld.m_impl, 0);
pos != npos;
pos = m_impl.find(strOld.m_impl, pos + uiOldLen))
{
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
pos += uiNewLen;
// increase replace count
uiCount++;
// stop after the first one?
if ( !bReplaceAll )
break;
replacePositions.push_back(pos);
++uiCount;
}
if ( !uiCount )
return 0;
// allocate enough memory for the whole new string
wxString tmp;
tmp.m_impl.reserve(m_impl.length() + uiCount*(uiNewLen - uiOldLen));
// copy this string to tmp doing replacements on the fly
size_t replNum = 0;
for ( pos = 0; replNum < uiCount; replNum++ )
{
const size_t nextReplPos = replacePositions[replNum];
if ( pos != nextReplPos )
{
tmp.m_impl.append(m_impl, pos, nextReplPos - pos);
}
tmp.m_impl.append(strNew.m_impl);
pos = nextReplPos + uiOldLen;
}
if ( pos != m_impl.length() )
{
// append the rest of the string unchanged
tmp.m_impl.append(m_impl, pos, m_impl.length() - pos);
}
swap(tmp);
}
return uiCount;

View File

@ -281,6 +281,18 @@ BENCHMARK_FUNC(ReplaceAll)
return str.Replace("x", "y") != 0;
}
BENCHMARK_FUNC(ReplaceLonger)
{
wxString str('x', ASCIISTR_LEN);
return str.Replace("x", "yy") != 0;
}
BENCHMARK_FUNC(ReplaceShorter)
{
wxString str('x', ASCIISTR_LEN);
return str.Replace("xx", "y") != 0;
}
// ----------------------------------------------------------------------------
// string buffers: wx[W]CharBuffer

View File

@ -318,7 +318,7 @@ void StringTestCase::Replace()
{ \
wxString s(o,olen); \
s.replace( pos , len , replacement ); \
CPPUNIT_ASSERT( s == wxString(r,rlen) ); \
CPPUNIT_ASSERT_EQUAL( wxString(r,rlen), s ); \
}
TEST_NULLCHARREPLACE( _T("null\0char"), 9, 5, 1, _T("d"),
@ -328,7 +328,7 @@ void StringTestCase::Replace()
{ \
wxString s(o,olen); \
s.Replace( olds, news, all ); \
CPPUNIT_ASSERT( s == wxString(r,rlen) ); \
CPPUNIT_ASSERT_EQUAL( wxString(r,rlen), s ); \
}
TEST_WXREPLACE( _T("null\0char"), 9, _T("c"), _T("de"), true,
@ -338,6 +338,10 @@ void StringTestCase::Replace()
_T("null\0char"), 9 );
TEST_WXREPLACE( "life", 4, "f", "", false, "lie", 3 );
TEST_WXREPLACE( "life", 4, "f", "", true, "lie", 3 );
TEST_WXREPLACE( "life", 4, "fe", "ve", true, "live", 4 );
TEST_WXREPLACE( "xx", 2, "x", "yy", true, "yyyy", 4 );
TEST_WXREPLACE( "xxx", 3, "xx", "z", true, "zx", 2 );
#undef TEST_WXREPLACE
#undef TEST_NULLCHARREPLACE