summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qstring.h
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2011-07-06 09:21:10 +0200
committerQt by Nokia <qt-info@nokia.com>2011-07-07 12:30:00 +0200
commitee85e9cc10bc6874c892b09fa54b5dbd79854069 (patch)
treeabc628be1f6a35ce12bda3d5f7ca7297dfb4d65c /src/corelib/tools/qstring.h
parentfcca106e590ba550c536a6b8de1b011ccc2c0d30 (diff)
Support for compile time generated QStrings
use with QString string(QStringLiteral("foo")) or QString string(qs("foo")). qs(...) can in almost all places replace QLatin1String. the Macro qs requires c++0x support or a compiler where sizeof(wchar_t) == 2. In case these conditions are not met, qs simply falls back to QLatin1String. The commit also cleans up the QStringData structure significantly, now using only 16 bytes for the header on 32 bit systems. The bitflags to store unicode directionality of the string and whether the string would require complex text processing to render are removed. They don't really belong here and the result can be calculated very fast in any case. Added an internal QRefCount class the encapsulates the reference counting semantics required where a negative refcount is never changed. This is required to be able to put the string data into a constant POD object. Change-Id: I5b1395213deca48b2d582a036a0e8a8358d26d14 Reviewed-on: http://codereview.qt.nokia.com/1218 Reviewed-by: Olivier Goffart <olivier.goffart@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'src/corelib/tools/qstring.h')
-rw-r--r--src/corelib/tools/qstring.h130
1 files changed, 88 insertions, 42 deletions
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 154012d132..81dff3d309 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -44,7 +44,7 @@
#include <QtCore/qchar.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qatomic.h>
+#include <QtCore/qrefcount.h>
#include <QtCore/qnamespace.h>
#ifndef QT_NO_STL
@@ -77,9 +77,65 @@ class QLatin1String;
class QStringRef;
template <typename T> class QVector;
+struct QStringData {
+ QtPrivate::RefCount ref;
+ int size;
+ uint alloc : 31;
+ uint capacityReserved : 1;
+ union {
+ qptrdiff offset; // will always work as we add/subtract from a ushort ptr
+ ushort d[sizeof(qptrdiff)/sizeof(ushort)];
+ };
+ inline ushort *data() { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; }
+ inline const ushort *data() const { return d + sizeof(qptrdiff)/sizeof(ushort) + offset; }
+};
+
+
+#if defined(Q_COMPILER_UNICODE_STRINGS)
+
+template<int n> struct QConstStringData
+{
+ const QStringData str;
+ const char16_t data[n];
+ operator const QStringData &() const { return str; }
+};
+#define QStringLiteral(str) (const QConstStringData<sizeof(u"" str)/2>) \
+{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(u"" str)/2 -1, 0, 0, { 0 } }, u"" str }
+
+// wchar_t is 2 bytes
+#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536)
+
+template<int n> struct QConstStringData
+{
+ const QStringData str;
+ const wchar_t data[n];
+ operator const QStringData &() const { return str; }
+};
+#define QStringLiteral(str) (const QConstStringData<sizeof(L"" str)/2>) \
+{ { Q_REFCOUNT_INITIALIZER(-1), sizeof(L"" str)/2 -1, 0, 0, { 0 } }, L"" str }
+
+// fallback, uses QLatin1String as next best options
+#else
+
+template<int n> struct QConstStringData
+{
+ const QStringData str;
+ const ushort data[n];
+ operator const QStringData &() const { return str; }
+};
+#define QStringLiteral(str) QLatin1String(str)
+
+#endif
+
+#ifndef QT_NO_KEYWORDS
+#define qs(str) QStringLiteral(str)
+#endif
+
class Q_CORE_EXPORT QString
{
public:
+ typedef QStringData Data;
+
inline QString();
QString(const QChar *unicode, int size); // Qt5: don't cap size < 0
explicit QString(const QChar *unicode); // Qt5: merge with the above
@@ -108,7 +164,7 @@ public:
int capacity() const;
inline void reserve(int size);
- inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacity = 0;}
+ inline void squeeze() { if (d->size < d->alloc || d->ref != 1) realloc(); d->capacityReserved = false;}
inline const QChar *unicode() const;
inline QChar *data();
@@ -262,8 +318,8 @@ public:
inline QString &operator+=(QChar c) {
if (d->ref != 1 || d->size + 1 > d->alloc)
realloc(grow(d->size + 1));
- d->data[d->size++] = c.unicode();
- d->data[d->size] = '\0';
+ d->data()[d->size++] = c.unicode();
+ d->data()[d->size] = '\0';
return *this;
}
@@ -491,15 +547,17 @@ public:
// compatibility
struct Null { };
static const Null null;
- inline QString(const Null &): d(&shared_null) { d->ref.ref(); }
+ inline QString(const Null &): d(const_cast<Data *>(&shared_null.str)) {}
inline QString &operator=(const Null &) { *this = QString(); return *this; }
- inline bool isNull() const { return d == &shared_null; }
+ inline bool isNull() const { return d == &shared_null.str; }
- bool isSimpleText() const { if (!d->clean) updateProperties(); return d->simpletext; }
+ bool isSimpleText() const;
bool isRightToLeft() const;
QString(int size, Qt::Initialization);
+ template <int n>
+ inline QString(const QConstStringData<n> &dd) : d(const_cast<QStringData *>(&dd.str)) {}
private:
#if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED)
@@ -511,22 +569,11 @@ private:
QString &operator=(const QByteArray &a);
#endif
- struct Data {
- QBasicAtomicInt ref;
- int alloc, size;
- ushort *data; // QT5: put that after the bit field to fill alignment gap; don't use sizeof any more then
- ushort clean : 1;
- ushort simpletext : 1;
- ushort righttoleft : 1;
- ushort capacity : 1;
- ushort reserved : 11;
- // ### Qt5: try to ensure that "array" is aligned to 16 bytes on both 32- and 64-bit
- ushort array[1];
- };
- static Data shared_null;
- static Data shared_empty;
+ static const QConstStringData<1> shared_null;
+ static const QConstStringData<1> shared_empty;
Data *d;
- QString(Data *dd, int /*dummy*/) : d(dd) {}
+ inline QString(Data *dd, int /*dummy*/) : d(dd) {}
+
#ifndef QT_NO_TEXTCODEC
static QTextCodec *codecForCStrings;
#endif
@@ -605,23 +652,23 @@ inline QString::QString(const QLatin1String &aLatin1) : d(fromLatin1_helper(aLat
inline int QString::length() const
{ return d->size; }
inline const QChar QString::at(int i) const
-{ Q_ASSERT(uint(i) < uint(size())); return d->data[i]; }
+{ Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; }
inline const QChar QString::operator[](int i) const
-{ Q_ASSERT(uint(i) < uint(size())); return d->data[i]; }
+{ Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; }
inline const QChar QString::operator[](uint i) const
-{ Q_ASSERT(i < uint(size())); return d->data[i]; }
+{ Q_ASSERT(i < uint(size())); return d->data()[i]; }
inline bool QString::isEmpty() const
{ return d->size == 0; }
inline const QChar *QString::unicode() const
-{ return reinterpret_cast<const QChar*>(d->data); }
+{ return reinterpret_cast<const QChar*>(d->data()); }
inline const QChar *QString::data() const
-{ return reinterpret_cast<const QChar*>(d->data); }
+{ return reinterpret_cast<const QChar*>(d->data()); }
inline QChar *QString::data()
-{ detach(); return reinterpret_cast<QChar*>(d->data); }
+{ detach(); return reinterpret_cast<QChar*>(d->data()); }
inline const QChar *QString::constData() const
-{ return reinterpret_cast<const QChar*>(d->data); }
+{ return reinterpret_cast<const QChar*>(d->data()); }
inline void QString::detach()
-{ if (d->ref != 1 || d->data != d->array) realloc(); }
+{ if (d->ref != 1 || d->offset) realloc(); }
inline bool QString::isDetached() const
{ return d->ref == 1; }
inline QString &QString::operator=(const QLatin1String &s)
@@ -703,10 +750,10 @@ public:
// all this is not documented: We just say "like QChar" and let it be.
inline operator QChar() const
- { return i < s.d->size ? s.d->data[i] : 0; }
+ { return i < s.d->size ? s.d->data()[i] : 0; }
inline QCharRef &operator=(const QChar &c)
{ if (i >= s.d->size) s.expand(i); else s.detach();
- s.d->data[i] = c.unicode(); return *this; }
+ s.d->data()[i] = c.unicode(); return *this; }
// An operator= for each QChar cast constructors
#ifndef QT_NO_CAST_FROM_ASCII
@@ -773,9 +820,9 @@ inline void QCharRef::setRow(uchar arow) { QChar(*this).setRow(arow); }
inline void QCharRef::setCell(uchar acell) { QChar(*this).setCell(acell); }
-inline QString::QString() : d(&shared_null) { d->ref.ref(); }
+inline QString::QString() : d(const_cast<Data *>(&shared_null.str)) {}
inline QString::~QString() { if (!d->ref.deref()) free(d); }
-inline void QString::reserve(int asize) { if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacity = 1;}
+inline void QString::reserve(int asize) { if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true;}
inline QString &QString::setUtf16(const ushort *autf16, int asize)
{ return setUnicode(reinterpret_cast<const QChar *>(autf16), asize); }
inline QCharRef QString::operator[](int i)
@@ -783,17 +830,17 @@ inline QCharRef QString::operator[](int i)
inline QCharRef QString::operator[](uint i)
{ return QCharRef(*this, i); }
inline QString::iterator QString::begin()
-{ detach(); return reinterpret_cast<QChar*>(d->data); }
+{ detach(); return reinterpret_cast<QChar*>(d->data()); }
inline QString::const_iterator QString::begin() const
-{ return reinterpret_cast<const QChar*>(d->data); }
+{ return reinterpret_cast<const QChar*>(d->data()); }
inline QString::const_iterator QString::constBegin() const
-{ return reinterpret_cast<const QChar*>(d->data); }
+{ return reinterpret_cast<const QChar*>(d->data()); }
inline QString::iterator QString::end()
-{ detach(); return reinterpret_cast<QChar*>(d->data + d->size); }
+{ detach(); return reinterpret_cast<QChar*>(d->data() + d->size); }
inline QString::const_iterator QString::end() const
-{ return reinterpret_cast<const QChar*>(d->data + d->size); }
+{ return reinterpret_cast<const QChar*>(d->data() + d->size); }
inline QString::const_iterator QString::constEnd() const
-{ return reinterpret_cast<const QChar*>(d->data + d->size); }
+{ return reinterpret_cast<const QChar*>(d->data() + d->size); }
inline QBool QString::contains(const QString &s, Qt::CaseSensitivity cs) const
{ return QBool(indexOf(s, 0, cs) != -1); }
inline QBool QString::contains(const QStringRef &s, Qt::CaseSensitivity cs) const
@@ -1024,7 +1071,7 @@ public:
inline const QChar *unicode() const {
if (!m_string)
- return reinterpret_cast<const QChar *>(QString::shared_null.data);
+ return reinterpret_cast<const QChar *>(QString::shared_null.str.data());
return m_string->unicode() + m_position;
}
inline const QChar *data() const { return unicode(); }
@@ -1154,7 +1201,6 @@ inline QBool QStringRef::contains(const QStringRef &s, Qt::CaseSensitivity cs) c
{ return QBool(indexOf(s, 0, cs) != -1); }
-
QT_END_NAMESPACE
QT_END_HEADER