implicit QChar constructors
Oswald Buddenhagen
kde-optimize@mail.kde.org
Thu, 23 Jan 2003 03:29:32 +0100
On Wed, Jan 22, 2003 at 01:18:23AM +0100, Oswald Buddenhagen wrote:
> just an optimization hint,
>
and another one: don't use QString::mid() if you merely want to compare
the resulting string (or do something else short-lived and read-only
with it, like indexing a qmap (yes matthias, i was enlightened ...
finally :})). in such cases, use a construct like
if (QConstString(str.unicode() + pos, len).string() == <value>)
(instead of if (str.mid(pos, len) == <value>) ).
the left() and right() equality cases are covered by startsWith() and
endsWith() - i'm wondering, why there is no subStrIs() (midsWith()
is sort of a dumb name *g*)?
now let's discuss the opposite direction: concatenation.
str += foo + bar;
vs.
( str += foo ) += bar; // more readable: str.append(foo).append(bar);
the first form is mostly the same as
QString tstr(foo);
tstr += bar;
str += tstr;
the second form avoids creating a temporary object and is therefore
favorable ... unless str was already quite long: resizing a long string
is an expensive operation. therefore the cost of composing a short
"appendage" in a temporary string and then appending it at once is
smaller than appending two small chunks. typical tradeoff ...
note that this recursively applies to creating the "appendage":
str += foo + ( bar + baz );
will be faster than
str += ( foo + bar ) += baz;
if foo happens to be long.
to have something fast, trolltech could provide a function like
#include <stdarg.h> // i'd prefer varargs.h, but hey ...
const QString &
QString::append(const QString &a1, ...)
{
if (!a1)
return *this;
va_list ap;
uint clen = length();
uint len = clen + a1->length();
const QString *tp;
va_start(ap, a1);
while ((tp = va_arg(ap, const QString *)))
len += tp->length();
va_end(ap);
setLength(len);
memcpy((void*)(unicode() + clen), a1->unicode(), a1->length() * sizeof(QChar));
clen += a1->length();
va_start(ap, a1);
while ((tp = va_arg(ap, const QString *))) {
memcpy((void*)(unicode() + clen), tp->unicode(), tp->length() * sizeof(QChar));
clen += tp->length();
}
va_end(ap);
return *this;
}
which could be used like
QString a1("trolltech rocks");
QString a2(" (sometimes)");
str.append( &a1, &a2, 0L );
it's a bit ugly, because a) you have no type safety and b) you have to
explicitly create temporary objects (otherwise you get a compiler
warning).
the alternative would be to provide 10 overloaded const QString &
variants, duplicate tons of code and to hope nobody tries to add more
than 10 elements. :)
if you repeatedly append small chunks to an already long string (like,
say, you're reading a file line by line and appending the processed
results to a target string), theoretically you'd be better off
(speed-wise, not memory-wise) storing the lines in a QStringList and
then join()ing it at the end - too bad that qt's join() implementation
plainly sucks - it's a simple loop with incremental concat, instead of
a two-pass construct like the above function.
btw, QString::sprintf could also be made work in two passes, but i have
some doubts that doing all conversions twice is a gain over resizing a
(usually short) QString a few (usually ...) times. the third way is of
course storing all substrings in a QStringList and joining them with the
new, optimized ;) join() function - however, creating tons of small
objects is probably no gain over a few resizes, either. the last
possibility that comes to mind is what the setLength docu says:
preallocate a bigger string and truncate it later. the problem here is
only, how to predict the size halfways reasonably ...
ergo: simply try to avoid using strings at all. :)
i hope i confused everybody sufficiently. good night. :)
greetings
--
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
--
Chaos, panic, and disorder - my work here is done.