Simplified cleanup_cursor() implementation

I hit this performance bug when I cloneda 40G NTFS partition. The actual
copy was done in under 11 minutes. After that I was shocked to find that
gparted would spend over 12 minutes in cleanup_cursor, pegging a CPU
core. (On a quad core desktop...)

Simply replacing the ustring with std::string would reduce the time to
about 1.5 minutes. Still bad. Also, I didn't want to lose UTF8
awareness.

So I rewrote the algorithm in 'streaming mode'. This has the (potential)
drawback that locale conversions are done, but performs well and
- IMHO - is a lot more readable.

On a minor note: this implementation correctly handles backspaces at the
start of a line.
This commit is contained in:
Seth Heeren 2010-12-17 15:45:47 +01:00 committed by Curtis Gedak
parent 6c3129b972
commit 82fcb1ef0b

View file

@ -422,34 +422,33 @@ Glib::ustring Utils::trim( const Glib::ustring & src, const Glib::ustring & c /*
Glib::ustring Utils::cleanup_cursor( const Glib::ustring & text )
{
//Clean up text for commands that use cursoring to display progress.
Glib::ustring str = text;
//remove backspace '\b' and delete previous character. Used in mke2fs output.
for ( unsigned int index = str .find( "\b" ) ; index < str .length() ; index = str .find( "\b" ) ) {
if ( index > 0 )
str .erase( index - 1, 2 ) ;
else
str .erase( index, 1 ) ;
std::istringstream in(text);
std::ostringstream out;
char ch;
std::streampos startofline = out.tellp();
while (in.get(ch))
{
switch(ch)
{
case '\r':
if ('\n' != in.peek()) // for windows CRLF
out.seekp(startofline);
else
out.put(ch);
break;
case '\b':
if (out.tellp() > startofline)
out.seekp(out.tellp()-1ll);
break;
default:
out.put(ch);
}
if (ch == '\n')
startofline = out.tellp();
}
//Remove carriage return and line up to previous line feed. Used in ntfsclone output.
//NOTE: Normal linux line end is line feed. DOS uses CR + LF.
for ( unsigned int index1 = str .find( "\r") ; index1 < str .length() ; index1 = str .find( "\r" ) )
{
//Only process if next character is not a LF.
if ( str .at(index1 + 1) != '\n')
{
//find point to start erase from.
unsigned int index2 = str .rfind( "\n", index1 ) ;
//find end point to erase up to.
unsigned int index3 = str .find( "\n", index1 ) ;
unsigned int index4 = str .rfind( "\r", index3 ) ;
//perform erase if indices are valid
if ( ( index2 <= index1 ) && ( index4 > index2 ) && ( index4 < str .length() ) )
str .erase( index2 + 1, index4 - index2 ) ;
}
}
return str;
return out.str();
}
Glib::ustring Utils::get_lang()