Unify QLatin1String and QLatin1Literal

Unify the two classes and get rid of one
TODO item for Qt 5.

Using strlen in the constructor of QLatin1String works,
as the compiler can do the calculation at compile time.

Change-Id: I59d98c71a34b86d4211fa0d8cfd40b7d612c5a78
Reviewed-on: http://codereview.qt.nokia.com/1219
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Olivier Goffart <olivier.goffart@nokia.com>
This commit is contained in:
Lars Knoll 2011-07-04 12:21:06 +02:00 committed by Qt by Nokia
parent ee85e9cc10
commit f4c07fe721
4 changed files with 57 additions and 123 deletions

View File

@ -720,6 +720,18 @@ const QString::Null QString::null = { };
\section1 More Efficient String Construction
Many strings are known at compile time. But the trivial
constructor QString("Hello"), will convert the string literal
to a QString using the codecForCStrings(). To avoid this one
can use the QStringLiteral macro to directly create the required
data at compile time. Constructing a QString out of the literal
does then not cause any overhead at runtime.
A slightly less efficient way is to use QLatin1String. This class wraps
a C string literal, precalculates it length at compile time and can
then be used for faster comparison with QStrings and conversion to
QStrings than a regular C string literal.
Using the QString \c{'+'} operator, it is easy to construct a
complex string from multiple substrings. You will often write code
like this:
@ -735,9 +747,6 @@ const QString::Null QString::null = { };
where \e{n > 2}, there can be as many as \e{n - 1} calls to the
memory allocator.
Second, QLatin1String does not store its length internally but
calls qstrlen() when it needs to know its length.
In 4.6, an internal template class \c{QStringBuilder} has been
added along with a few helper functions. This class is marked
internal and does not appear in the documentation, because you
@ -755,12 +764,6 @@ const QString::Null QString::null = { };
then called \e{once} to get the required space, and the substrings
are copied into it one by one.
\c{QLatin1Literal} is a second internal class that can replace
QLatin1String, which can't be changed for compatibility reasons.
\c{QLatin1Literal} stores its length, thereby saving time when
\c{QStringBuilder} computes the amount of memory required for the
final string.
Additional efficiency is gained by inlining and reduced reference
counting (the QString created from a \c{QStringBuilder} typically
has a ref count of 1, whereas QString::append() needs an extra
@ -2076,7 +2079,7 @@ QString &QString::replace(const QLatin1String &before,
const QString &after,
Qt::CaseSensitivity cs)
{
int blen = qstrlen(before.latin1());
int blen = before.size();
QVarLengthArray<ushort> b(blen);
for (int i = 0; i < blen; ++i)
b[i] = (uchar)before.latin1()[i];
@ -2099,7 +2102,7 @@ QString &QString::replace(const QString &before,
const QLatin1String &after,
Qt::CaseSensitivity cs)
{
int alen = qstrlen(after.latin1());
int alen = after.size();
QVarLengthArray<ushort> a(alen);
for (int i = 0; i < alen; ++i)
a[i] = (uchar)after.latin1()[i];
@ -2120,7 +2123,7 @@ QString &QString::replace(const QString &before,
*/
QString &QString::replace(QChar c, const QLatin1String &after, Qt::CaseSensitivity cs)
{
int alen = qstrlen(after.latin1());
int alen = after.size();
QVarLengthArray<ushort> a(alen);
for (int i = 0; i < alen; ++i)
a[i] = (uchar)after.latin1()[i];
@ -2150,20 +2153,23 @@ bool QString::operator==(const QString &other) const
*/
bool QString::operator==(const QLatin1String &other) const
{
if (d->size != other.size())
return false;
if (!other.size())
return isEmpty();
const ushort *uc = d->data();
const ushort *e = uc + d->size;
const uchar *c = (uchar *)other.latin1();
if (!c)
return isEmpty();
while (*c) {
if (uc == e || *uc != *c)
while (uc < e) {
if (*uc != *c)
return false;
++uc;
++c;
}
return (uc == e);
return true;
}
/*! \fn bool QString::operator==(const QByteArray &other) const
@ -2212,20 +2218,20 @@ bool QString::operator<(const QString &other) const
*/
bool QString::operator<(const QLatin1String &other) const
{
const ushort *uc = d->data();
const ushort *e = uc + d->size;
const uchar *c = (uchar *) other.latin1();
if (!c || *c == 0)
return false;
while (*c) {
if (uc == e || *uc != *c)
const ushort *uc = d->data();
const ushort *e = uc + qMin(d->size, other.size());
while (uc < e) {
if (*uc != *c)
break;
++uc;
++c;
}
return (uc == e ? *c : *uc < *c);
return (uc == (d->data() + d->size) ? *c : *uc < *c);
}
/*! \fn bool QString::operator<(const QByteArray &other) const
@ -2314,20 +2320,20 @@ bool QString::operator<(const QLatin1String &other) const
*/
bool QString::operator>(const QLatin1String &other) const
{
const ushort *uc = d->data();;
const ushort *e = uc + d->size;
const uchar *c = (uchar *) other.latin1();
if (!c || *c == '\0')
return !isEmpty();
while (*c) {
if (uc == e || *uc != *c)
const ushort *uc = d->data();;
const ushort *e = uc + qMin(d->size, other.size());
while (uc < e) {
if (*uc != *c)
break;
++uc;
++c;
}
return (uc == e ? false : *uc > *c);
return (uc == (d->data() + d->size) ? false : *uc > *c);
}
/*! \fn bool QString::operator>(const QByteArray &other) const
@ -2696,7 +2702,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c
*/
int QString::lastIndexOf(const QLatin1String &str, int from, Qt::CaseSensitivity cs) const
{
const int sl = qstrlen(str.latin1());
const int sl = str.size();
if (sl == 1)
return lastIndexOf(QLatin1Char(str.latin1()[0]), from, cs);
@ -3832,7 +3838,7 @@ QString QString::fromLocal8Bit(const char *str, int size)
if (!str)
return QString();
if (size == 0 || (!*str && size < 0))
return QLatin1String("");
return QString(shared_empty);
#if !defined(QT_NO_TEXTCODEC)
if (size < 0)
size = qstrlen(str);
@ -7468,7 +7474,7 @@ QDataStream &operator>>(QDataStream &in, QString &str)
}
}
} else {
str = QLatin1String("");
str = QString(QLatin1String(""));
}
}
return in;
@ -8440,7 +8446,7 @@ int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
*/
int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
{
const int sl = qstrlen(str.latin1());
const int sl = str.size();
if (sl == 1)
return lastIndexOf(QLatin1Char(str.latin1()[0]), from, cs);
@ -8793,7 +8799,7 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size,
int from, Qt::CaseSensitivity cs)
{
const char *latin1 = needle.latin1();
int len = qstrlen(latin1);
int len = needle.size();
QVarLengthArray<ushort> s(len);
for (int i = 0; i < len; ++i)
s[i] = latin1[i];
@ -8834,7 +8840,7 @@ static inline bool qt_starts_with(const QChar *haystack, int haystackLen,
return !needle.latin1();
if (haystackLen == 0)
return !needle.latin1() || *needle.latin1() == 0;
const int slen = qstrlen(needle.latin1());
const int slen = needle.size();
if (slen > haystackLen)
return false;
const ushort *data = reinterpret_cast<const ushort*>(haystack);
@ -8885,7 +8891,7 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
return !needle.latin1();
if (haystackLen == 0)
return !needle.latin1() || *needle.latin1() == 0;
const int slen = qstrlen(needle.latin1());
const int slen = needle.size();
int pos = haystackLen - slen;
if (pos < 0)
return false;

View File

@ -610,11 +610,11 @@ public:
class Q_CORE_EXPORT QLatin1String
{
public:
inline explicit QLatin1String(const char *s) : chars(s) {}
inline QLatin1String &operator=(const QLatin1String &other)
{ chars = other.chars; return *this; }
inline explicit QLatin1String(const char *s) : m_size(s ? strlen(s) : 0), m_data(s) {}
inline const char *latin1() const { return chars; }
inline const char *latin1() const { return m_data; }
inline int size() const { return m_size; }
inline const char *data() const { return m_data; }
inline bool operator==(const QString &s) const
{ return s == *this; }
@ -642,9 +642,12 @@ public:
inline QT_ASCII_CAST_WARN bool operator>=(const char *s) const
{ return QString::fromAscii(s) <= *this; }
private:
const char *chars;
int m_size;
const char *m_data;
};
// Qt 4.x compatibility
typedef QLatin1String QLatin1Literal;
inline QString::QString(const QLatin1String &aLatin1) : d(fromLatin1_helper(aLatin1.latin1()))

View File

@ -44,47 +44,6 @@
QT_BEGIN_NAMESPACE
/*!
\class QLatin1Literal
\internal
\reentrant
\since 4.6
\brief The QLatin1Literal class provides a thin wrapper around string
literals used in source code.
\ingroup tools
\ingroup shared
\ingroup string-processing
Unlike \c QLatin1String, a \c QLatin1Literal can retrieve its size
without iterating over the literal.
The main use of \c QLatin1Literal is in conjunction with \c QStringBuilder
to reduce the number of reallocations needed to build up a string from
smaller chunks.
\sa QStringBuilder, QLatin1String, QString, QStringRef
*/
/*! \fn int QLatin1Literal::size() const
Returns the number of characters in the literal \e{excluding} the trailing
NULL char.
*/
/*! \fn QLatin1Literal::QLatin1Literal(const char str)
Constructs a new literal from the string \a str.
*/
/*! \fn const char *QLatin1Literal::data() const
Returns a pointer to the first character of the string literal.
The string literal is terminated by a NUL character.
*/
/*!
\class QStringBuilder
\internal
@ -110,7 +69,7 @@ QT_BEGIN_NAMESPACE
The QStringBuilder class is not to be used explicitly in user
code. Instances of the class are created as return values of the
operator%() function, acting on objects of type QString,
QLatin1String, QLatin1Literal, QStringRef, QChar, QCharRef,
QLatin1String, QStringRef, QChar, QCharRef,
QLatin1Char, and \c char.
Concatenating strings with operator%() generally yields better
@ -118,7 +77,7 @@ QT_BEGIN_NAMESPACE
if there are three or more of them, and performs equally well in other
cases.
\sa QLatin1Literal, QString
\sa QLatin1String, QString
*/
/*! \fn QStringBuilder::QStringBuilder(const A &a, const B &b)
@ -132,7 +91,7 @@ QT_BEGIN_NAMESPACE
takes a QString parameter.
This function is usable with arguments of type \c QString,
\c QLatin1String, \c QLatin1Literal, \c QStringRef,
\c QLatin1String, \c QStringRef,
\c QChar, \c QCharRef, \c QLatin1Char, and \c char.
*/
@ -145,7 +104,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn operator QStringBuilder::QString() const
Converts the \c QLatin1Literal into a \c QString object.
Converts the \c QLatin1String into a \c QString object.
*/
/*! \internal

View File

@ -59,22 +59,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Core)
// ### Qt 5: merge with QLatin1String
class QLatin1Literal
{
public:
int size() const { return m_size; }
const char *data() const { return m_data; }
template <int N>
QLatin1Literal(const char (&str)[N])
: m_size(N - 1), m_data(str) {}
private:
const int m_size;
const char * const m_data;
};
struct Q_CORE_EXPORT QAbstractConcatenable
{
protected:
@ -234,31 +218,13 @@ template <> struct QConcatenable<QLatin1String>
typedef QLatin1String type;
typedef QString ConvertTo;
enum { ExactSize = true };
static int size(const QLatin1String &a) { return qstrlen(a.latin1()); }
static int size(const QLatin1String &a) { return a.size(); }
static inline void appendTo(const QLatin1String &a, QChar *&out)
{
for (const char *s = a.latin1(); *s; )
*out++ = QLatin1Char(*s++);
}
static inline void appendTo(const QLatin1String &a, char *&out)
{
for (const char *s = a.latin1(); *s; )
*out++ = *s++;
}
};
template <> struct QConcatenable<QLatin1Literal>
{
typedef QLatin1Literal type;
typedef QString ConvertTo;
enum { ExactSize = true };
static int size(const QLatin1Literal &a) { return a.size(); }
static inline void appendTo(const QLatin1Literal &a, QChar *&out)
{
for (const char *s = a.data(); *s; )
*out++ = QLatin1Char(*s++);
}
static inline void appendTo(const QLatin1Literal &a, char *&out)
static inline void appendTo(const QLatin1String &a, char *&out)
{
for (const char *s = a.data(); *s; )
*out++ = *s++;