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:
parent
6c3129b972
commit
82fcb1ef0b
51
src/Utils.cc
51
src/Utils.cc
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue