diff options
Diffstat (limited to 'src/corelib')
23 files changed, 797 insertions, 692 deletions
diff --git a/src/corelib/concurrent/qtconcurrentexception.cpp b/src/corelib/concurrent/qtconcurrentexception.cpp index 933ad3c264..237152c0d3 100644 --- a/src/corelib/concurrent/qtconcurrentexception.cpp +++ b/src/corelib/concurrent/qtconcurrentexception.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qtconcurrentexception.h" +#include "QtCore/qshareddata.h" #ifndef QT_NO_QFUTURE #ifndef QT_NO_EXCEPTIONS @@ -141,15 +142,14 @@ Exception *UnhandledException::clone() const namespace internal { -class Base +class Base : public QSharedData { public: Base(Exception *exception) - : exception(exception), refCount(1), hasThrown(false) { } + : exception(exception), hasThrown(false) { } ~Base() { delete exception; } Exception *exception; - QAtomicInt refCount; bool hasThrown; }; @@ -158,27 +158,15 @@ ExceptionHolder::ExceptionHolder(Exception *exception) ExceptionHolder::ExceptionHolder(const ExceptionHolder &other) : base(other.base) -{ - base->refCount.ref(); -} +{} void ExceptionHolder::operator=(const ExceptionHolder &other) { - if (base == other.base) - return; - - if (base->refCount.deref() == false) - delete base; - base = other.base; - base->refCount.ref(); } ExceptionHolder::~ExceptionHolder() -{ - if (base->refCount.deref() == 0) - delete base; -} +{} Exception *ExceptionHolder::exception() const { diff --git a/src/corelib/concurrent/qtconcurrentexception.h b/src/corelib/concurrent/qtconcurrentexception.h index b58b3ba23a..1c100a5206 100644 --- a/src/corelib/concurrent/qtconcurrentexception.h +++ b/src/corelib/concurrent/qtconcurrentexception.h @@ -47,6 +47,7 @@ #ifndef QT_NO_QFUTURE #include <QtCore/qatomic.h> +#include <QtCore/qshareddata.h> #ifndef QT_NO_EXCEPTIONS # include <exception> @@ -87,7 +88,7 @@ public: void operator=(const ExceptionHolder &other); ~ExceptionHolder(); Exception *exception() const; - Base *base; + QExplicitlySharedDataPointer<Base> base; }; class Q_CORE_EXPORT ExceptionStore diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ca8b30fc00..bbc9a15e74 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1642,6 +1642,21 @@ bool qSharedBuild() \sa Q_WS_MAC, Q_WS_WIN, Q_WS_X11, Q_WS_QWS */ +/*! + \macro QT_DISABLE_DEPRECATED_BEFORE + \relates <QtGlobal> + + This macro can be defined in the project file to disable functions deprecated in + a specified version of Qt or any earlier version. The default version number is 5.0, + meaning that functions deprecated in or before Qt 5.0 will not be included. + + Examples: + When using a future release of Qt 5, set QT_DISABLE_DEPRECATED_BEFORE=0x050100 to + disable functions deprecated in Qt 5.1 and earlier. In any release, set + QT_DISABLE_DEPRECATED_BEFORE=0x000000 to enable any functions, including the ones + deprecated in Qt 5.0 + */ + #if defined(QT_BUILD_QMAKE) // needed to bootstrap qmake static const unsigned int qt_one = 1; diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index af9d86c2ca..844fe0528e 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -54,6 +54,23 @@ */ #define QT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) +#ifndef QT_DISABLE_DEPRECATED_BEFORE +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(5, 0, 0) +#endif + +/* + QT_DEPRECATED_SINCE(major, minor) evaluates as true if the Qt version is greater than + the deprecation point specified. + + Use it to specify from which version of Qt a function or class has been deprecated + + Example: + #if QT_DEPRECATED_SINCE(5,1) + QT_DEPRECATED void deprecatedFunction(); //function deprecated sine Qt 5.1 + #endif + */ +#define QT_DEPRECATED_SINCE(major, minor) (QT_VERSION_CHECK(major, minor, 0) > QT_DISABLE_DEPRECATED_BEFORE) + #define QT_PACKAGEDATE_STR "YYYY-MM-DD" #define QT_PACKAGE_TAG "" @@ -516,6 +533,7 @@ namespace QT_NAMESPACE {} # endif # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 404 /* C++0x features supported in GCC 4.4: */ +# define Q_COMPILER_UNICODE_STRINGS # define Q_COMPILER_VARIADIC_TEMPLATES # define Q_COMPILER_AUTO_TYPE # define Q_COMPILER_EXTERN_TEMPLATES @@ -526,8 +544,12 @@ namespace QT_NAMESPACE {} # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 /* C++0x features supported in GCC 4.5: */ # define Q_COMPILER_LAMBDA -# define Q_COMPILER_UNICODE_STRINGS # endif +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 + /* C++0x features supported in GCC 4.6: */ +# define Q_COMPILER_CONSTEXPR +# endif + # endif /* IBM compiler versions are a bit messy. There are actually two products: @@ -961,6 +983,7 @@ QT_END_INCLUDE_NAMESPACE #error "Compiler doesn't support the bool type" #endif + /* Constant bool values */ @@ -1091,6 +1114,12 @@ redefine to built-in booleans to make autotests work properly */ # define QT_FASTCALL #endif +#ifdef Q_COMPILER_CONSTEXPR +# define Q_DECL_CONSTEXPR constexpr +#else +# define Q_DECL_CONSTEXPR +#endif + //defines the type for the WNDPROC on windows //the alignment needs to be forced for sse2 to not crash with mingw #if defined(Q_OS_WIN) @@ -1104,10 +1133,6 @@ redefine to built-in booleans to make autotests work properly */ typedef int QNoImplicitBoolCast; -#if defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_MIPS) && (defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_WINCE))) || defined(QT_ARCH_SH) || defined(QT_ARCH_SH4A) -#define QT_NO_FPU -#endif - // This logic must match the one in qmetatype.h #if defined(QT_COORD_TYPE) typedef QT_COORD_TYPE qreal; @@ -1122,25 +1147,25 @@ typedef double qreal; */ template <typename T> -inline T qAbs(const T &t) { return t >= 0 ? t : -t; } +Q_DECL_CONSTEXPR inline T qAbs(const T &t) { return t >= 0 ? t : -t; } -inline int qRound(qreal d) +Q_DECL_CONSTEXPR inline int qRound(qreal d) { return d >= qreal(0.0) ? int(d + qreal(0.5)) : int(d - int(d-1) + qreal(0.5)) + int(d-1); } #if defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN) -inline qint64 qRound64(double d) +Q_DECL_CONSTEXPR inline qint64 qRound64(double d) { return d >= 0.0 ? qint64(d + 0.5) : qint64(d - qreal(qint64(d-1)) + 0.5) + qint64(d-1); } #else -inline qint64 qRound64(qreal d) +Q_DECL_CONSTEXPR inline qint64 qRound64(qreal d) { return d >= qreal(0.0) ? qint64(d + qreal(0.5)) : qint64(d - qreal(qint64(d-1)) + qreal(0.5)) + qint64(d-1); } #endif template <typename T> -inline const T &qMin(const T &a, const T &b) { if (a < b) return a; return b; } +Q_DECL_CONSTEXPR inline const T &qMin(const T &a, const T &b) { return (a < b) ? a : b; } template <typename T> -inline const T &qMax(const T &a, const T &b) { if (a < b) return b; return a; } +Q_DECL_CONSTEXPR inline const T &qMax(const T &a, const T &b) { return (a < b) ? b : a; } template <typename T> -inline const T &qBound(const T &min, const T &val, const T &max) +Q_DECL_CONSTEXPR inline const T &qBound(const T &min, const T &val, const T &max) { return qMax(min, qMin(max, val)); } /* @@ -1914,12 +1939,12 @@ inline bool operator!=(QBool b1, bool b2) { return !b1 != !b2; } inline bool operator!=(bool b1, QBool b2) { return !b1 != !b2; } inline bool operator!=(QBool b1, QBool b2) { return !b1 != !b2; } -static inline bool qFuzzyCompare(double p1, double p2) +Q_DECL_CONSTEXPR static inline bool qFuzzyCompare(double p1, double p2) { return (qAbs(p1 - p2) <= 0.000000000001 * qMin(qAbs(p1), qAbs(p2))); } -static inline bool qFuzzyCompare(float p1, float p2) +Q_DECL_CONSTEXPR static inline bool qFuzzyCompare(float p1, float p2) { return (qAbs(p1 - p2) <= 0.00001f * qMin(qAbs(p1), qAbs(p2))); } @@ -1927,7 +1952,7 @@ static inline bool qFuzzyCompare(float p1, float p2) /*! \internal */ -static inline bool qFuzzyIsNull(double d) +Q_DECL_CONSTEXPR static inline bool qFuzzyIsNull(double d) { return qAbs(d) <= 0.000000000001; } @@ -1935,7 +1960,7 @@ static inline bool qFuzzyIsNull(double d) /*! \internal */ -static inline bool qFuzzyIsNull(float f) +Q_DECL_CONSTEXPR static inline bool qFuzzyIsNull(float f) { return qAbs(f) <= 0.00001f; } @@ -2203,9 +2228,9 @@ class QFlags int i; public: typedef Enum enum_type; - inline QFlags(const QFlags &f) : i(f.i) {} - inline QFlags(Enum f) : i(f) {} - inline QFlags(Zero = 0) : i(0) {} + Q_DECL_CONSTEXPR inline QFlags(const QFlags &f) : i(f.i) {} + Q_DECL_CONSTEXPR inline QFlags(Enum f) : i(f) {} + Q_DECL_CONSTEXPR inline QFlags(Zero = 0) : i(0) {} inline QFlags(QFlag f) : i(f) {} inline QFlags &operator=(const QFlags &f) { i = f.i; return *this; } @@ -2216,18 +2241,18 @@ public: inline QFlags &operator^=(QFlags f) { i ^= f.i; return *this; } inline QFlags &operator^=(Enum f) { i ^= f; return *this; } - inline operator int() const { return i; } + Q_DECL_CONSTEXPR inline operator int() const { return i; } - inline QFlags operator|(QFlags f) const { QFlags g; g.i = i | f.i; return g; } - inline QFlags operator|(Enum f) const { QFlags g; g.i = i | f; return g; } - inline QFlags operator^(QFlags f) const { QFlags g; g.i = i ^ f.i; return g; } - inline QFlags operator^(Enum f) const { QFlags g; g.i = i ^ f; return g; } - inline QFlags operator&(int mask) const { QFlags g; g.i = i & mask; return g; } - inline QFlags operator&(uint mask) const { QFlags g; g.i = i & mask; return g; } - inline QFlags operator&(Enum f) const { QFlags g; g.i = i & f; return g; } - inline QFlags operator~() const { QFlags g; g.i = ~i; return g; } + Q_DECL_CONSTEXPR inline QFlags operator|(QFlags f) const { return QFlags(Enum(i | f.i)); } + Q_DECL_CONSTEXPR inline QFlags operator|(Enum f) const { return QFlags(Enum(i | f)); } + Q_DECL_CONSTEXPR inline QFlags operator^(QFlags f) const { return QFlags(Enum(i ^ f.i)); } + Q_DECL_CONSTEXPR inline QFlags operator^(Enum f) const { return QFlags(Enum(i ^ f)); } + Q_DECL_CONSTEXPR inline QFlags operator&(int mask) const { return QFlags(Enum(i & mask)); } + Q_DECL_CONSTEXPR inline QFlags operator&(uint mask) const { return QFlags(Enum(i & mask)); } + Q_DECL_CONSTEXPR inline QFlags operator&(Enum f) const { return QFlags(Enum(i & f)); } + Q_DECL_CONSTEXPR inline QFlags operator~() const { return QFlags(Enum(~i)); } - inline bool operator!() const { return !i; } + Q_DECL_CONSTEXPR inline bool operator!() const { return !i; } inline bool testFlag(Enum f) const { return (i & f) == f && (f != 0 || i == int(f) ); } }; @@ -2240,9 +2265,9 @@ inline QIncompatibleFlag operator|(Flags::enum_type f1, int f2) \ { return QIncompatibleFlag(int(f1) | f2); } #define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) \ -inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) \ +Q_DECL_CONSTEXPR inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) \ { return QFlags<Flags::enum_type>(f1) | f2; } \ -inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) \ +Q_DECL_CONSTEXPR inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) \ { return f2 | f1; } Q_DECLARE_INCOMPATIBLE_FLAGS(Flags) diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 5333b71d7b..88f12ab1f7 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -297,11 +297,6 @@ QLibraryInfo::location(LibraryLocation loc) path = QT_CONFIGURE_EXAMPLES_PATH; break; #endif -#ifdef QT_CONFIGURE_DEMOS_PATH - case DemosPath: - path = QT_CONFIGURE_DEMOS_PATH; - break; -#endif default: break; } @@ -352,9 +347,6 @@ QLibraryInfo::location(LibraryLocation loc) case ExamplesPath: key = QLatin1String("Examples"); break; - case DemosPath: - key = QLatin1String("Demos"); - break; default: break; } @@ -500,7 +492,6 @@ QLibraryInfo::location(LibraryLocation loc) \value TranslationsPath The location of translation information for Qt strings. \value SettingsPath The location for Qt settings. \value ExamplesPath The location for examples upon install. - \value DemosPath The location for demos upon install. \sa location() */ diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index 9af53c315c..a8fb90968c 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -75,7 +75,6 @@ public: DataPath, TranslationsPath, SettingsPath, - DemosPath, ExamplesPath, ImportsPath }; diff --git a/src/corelib/io/qtldurl.cpp b/src/corelib/io/qtldurl.cpp index 7db4bbddd5..7d06ca4b17 100644 --- a/src/corelib/io/qtldurl.cpp +++ b/src/corelib/io/qtldurl.cpp @@ -7,29 +7,29 @@ ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** ** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. ** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. ** ** ** diff --git a/src/corelib/io/qtldurl_p.h b/src/corelib/io/qtldurl_p.h index 152ffa0f63..77c0a15823 100644 --- a/src/corelib/io/qtldurl_p.h +++ b/src/corelib/io/qtldurl_p.h @@ -7,29 +7,29 @@ ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** ** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. ** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. ** ** ** diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index c134881f31..d12391914b 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -805,7 +805,16 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) // call overhead. QObjectPrivate *d = receiver->d_func(); QThreadData *threadData = d->threadData; - ++threadData->loopLevel; + + // Exception-safety without try/catch + struct Incrementer { + int &variable; + inline Incrementer(int &variable) : variable(variable) + { ++variable; } + inline ~Incrementer() + { --variable; } + }; + Incrementer inc(threadData->loopLevel); #ifdef QT_JAMBI_BUILD int deleteWatch = 0; @@ -816,12 +825,7 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) #endif bool returnValue; - QT_TRY { - returnValue = notify(receiver, event); - } QT_CATCH (...) { - --threadData->loopLevel; - QT_RETHROW; - } + returnValue = notify(receiver, event); #ifdef QT_JAMBI_BUILD // Restore the previous state if the object was not deleted.. @@ -830,7 +834,6 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) } QObjectPrivate::resetDeleteWatch(d, oldDeleteWatch, deleteWatch); #endif - --threadData->loopLevel; return returnValue; } @@ -1373,6 +1376,40 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset; data->postEventList.insertionOffset = data->postEventList.size(); + // Exception-safe cleaning up without the need for a try/catch block + struct CleanUp { + QObject *receiver; + int event_type; + QThreadData *data; + bool exceptionCaught; + + inline CleanUp(QObject *receiver, int event_type, QThreadData *data) : + receiver(receiver), event_type(event_type), data(data), exceptionCaught(true) + {} + inline ~CleanUp() + { + if (exceptionCaught) { + // since we were interrupted, we need another pass to make sure we clean everything up + data->canWait = false; + } + + --data->postEventList.recursion; + if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) + data->eventDispatcher->wakeUp(); + + // clear the global list, i.e. remove everything that was + // delivered. + if (!event_type && !receiver && data->postEventList.startOffset >= 0) { + const QPostEventList::iterator it = data->postEventList.begin(); + data->postEventList.erase(it, it + data->postEventList.startOffset); + data->postEventList.insertionOffset -= data->postEventList.startOffset; + Q_ASSERT(data->postEventList.insertionOffset >= 0); + data->postEventList.startOffset = 0; + } + } + }; + CleanUp cleanup(receiver, event_type, data); + while (i < data->postEventList.size()) { // avoid live-lock if (i >= data->postEventList.insertionOffset) @@ -1411,7 +1448,7 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type // first, we diddle the event so that we can deliver // it, and that no one will try to touch it later. pe.event->posted = false; - QEvent * e = pe.event; + QScopedPointer<QEvent> e(pe.event); QObject * r = pe.receiver; --r->d_func()->postedEvents; @@ -1421,49 +1458,23 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type // for the next event. const_cast<QPostEvent &>(pe).event = 0; - locker.unlock(); - // after all that work, it's time to deliver the event. -#ifdef QT_NO_EXCEPTIONS - QCoreApplication::sendEvent(r, e); -#else - try { - QCoreApplication::sendEvent(r, e); - } catch (...) { - delete e; - locker.relock(); - - // since we were interrupted, we need another pass to make sure we clean everything up - data->canWait = false; - - // uglehack: copied from below - --data->postEventList.recursion; - if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) - data->eventDispatcher->wakeUp(); - throw; // rethrow - } -#endif + struct MutexUnlocker + { + QMutexLocker &m; + MutexUnlocker(QMutexLocker &m) : m(m) { m.unlock(); } + ~MutexUnlocker() { m.relock(); } + }; + MutexUnlocker unlocker(locker); - delete e; - locker.relock(); + // after all that work, it's time to deliver the event. + QCoreApplication::sendEvent(r, e.data()); // careful when adding anything below this point - the // sendEvent() call might invalidate any invariants this // function depends on. } - --data->postEventList.recursion; - if (!data->postEventList.recursion && !data->canWait && data->eventDispatcher) - data->eventDispatcher->wakeUp(); - - // clear the global list, i.e. remove everything that was - // delivered. - if (!event_type && !receiver && data->postEventList.startOffset >= 0) { - const QPostEventList::iterator it = data->postEventList.begin(); - data->postEventList.erase(it, it + data->postEventList.startOffset); - data->postEventList.insertionOffset -= data->postEventList.startOffset; - Q_ASSERT(data->postEventList.insertionOffset >= 0); - data->postEventList.startOffset = 0; - } + cleanup.exceptionCaught = false; } /*! diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index 5a4ce973bc..37c06a2093 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -184,49 +184,47 @@ int QEventLoop::exec(ProcessEventsFlags flags) qWarning("QEventLoop::exec: instance %p has already called exec()", this); return -1; } - d->inExec = true; - d->exit = false; - ++d->threadData->loopLevel; - d->threadData->eventLoops.push(this); - locker.unlock(); + + struct LoopReference { + QEventLoopPrivate *d; + QMutexLocker &locker; + + bool exceptionCaught; + LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true) + { + d->inExec = true; + d->exit = false; + ++d->threadData->loopLevel; + d->threadData->eventLoops.push(d->q_func()); + locker.unlock(); + } + + ~LoopReference() + { + if (exceptionCaught) { + qWarning("Qt has caught an exception thrown from an event handler. Throwing\n" + "exceptions from an event handler is not supported in Qt. You must\n" + "reimplement QApplication::notify() and catch all exceptions there.\n"); + } + locker.relock(); + QEventLoop *eventLoop = d->threadData->eventLoops.pop(); + Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error"); + Q_UNUSED(eventLoop); // --release warning + d->inExec = false; + --d->threadData->loopLevel; + } + }; + LoopReference ref(d, locker); // remove posted quit events when entering a new event loop QCoreApplication *app = QCoreApplication::instance(); if (app && app->thread() == thread()) QCoreApplication::removePostedEvents(app, QEvent::Quit); -#if defined(QT_NO_EXCEPTIONS) while (!d->exit) processEvents(flags | WaitForMoreEvents | EventLoopExec); -#else - try { - while (!d->exit) - processEvents(flags | WaitForMoreEvents | EventLoopExec); - } catch (...) { - qWarning("Qt has caught an exception thrown from an event handler. Throwing\n" - "exceptions from an event handler is not supported in Qt. You must\n" - "reimplement QApplication::notify() and catch all exceptions there.\n"); - - // copied from below - locker.relock(); - QEventLoop *eventLoop = d->threadData->eventLoops.pop(); - Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); - Q_UNUSED(eventLoop); // --release warning - d->inExec = false; - --d->threadData->loopLevel; - - throw; - } -#endif - - // copied above - locker.relock(); - QEventLoop *eventLoop = d->threadData->eventLoops.pop(); - Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); - Q_UNUSED(eventLoop); // --release warning - d->inExec = false; - --d->threadData->loopLevel; + ref.exceptionCaught = false; return d->returnCode; } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index d573741654..08236a3fec 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -125,6 +125,39 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) } } +struct QConnectionSenderSwitcher { + QObject *receiver; + QObjectPrivate::Sender *previousSender; + QObjectPrivate::Sender currentSender; + bool switched; + + inline QConnectionSenderSwitcher() : switched(false) {} + + inline QConnectionSenderSwitcher(QObject *receiver, QObject *sender, int signal_absolute_id) + { + switchSender(receiver, sender, signal_absolute_id); + } + + inline void switchSender(QObject *receiver, QObject *sender, int signal_absolute_id) + { + this->receiver = receiver; + currentSender.sender = sender; + currentSender.signal = signal_absolute_id; + currentSender.ref = 1; + previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); + switched = true; + } + + inline ~QConnectionSenderSwitcher() + { + if (switched) + QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); + } +private: + Q_DISABLE_COPY(QConnectionSenderSwitcher) +}; + + void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0; @@ -1084,23 +1117,10 @@ bool QObject::event(QEvent *e) d_func()->inEventHandler = false; #endif QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e); - QObjectPrivate::Sender currentSender; - currentSender.sender = const_cast<QObject*>(mce->sender()); - currentSender.signal = mce->signalId(); - currentSender.ref = 1; - QObjectPrivate::Sender * const previousSender = - QObjectPrivate::setCurrentSender(this, ¤tSender); -#if defined(QT_NO_EXCEPTIONS) + + QConnectionSenderSwitcher sw(this, const_cast<QObject*>(mce->sender()), mce->signalId()); + mce->placeMetaCall(this); -#else - QT_TRY { - mce->placeMetaCall(this); - } QT_CATCH(...) { - QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); - QT_RETHROW; - } -#endif - QObjectPrivate::resetCurrentSender(this, ¤tSender, previousSender); break; } @@ -2977,7 +2997,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, type &= Qt::UniqueConnection - 1; } - QObjectPrivate::Connection *c = new QObjectPrivate::Connection; + QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection); c->sender = s; c->receiver = r; c->method_relative = method_index; @@ -2987,16 +3007,11 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, c->nextConnectionList = 0; c->callFunction = callFunction; - QT_TRY { - QObjectPrivate::get(s)->addConnection(signal_index, c); - } QT_CATCH(...) { - delete c; - QT_RETHROW; - } + QObjectPrivate::get(s)->addConnection(signal_index, c.data()); c->prev = &(QObjectPrivate::get(r)->senders); c->next = *c->prev; - *c->prev = c; + *c->prev = c.data(); if (c->next) c->next->prev = &c->next; @@ -3007,6 +3022,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f)); } + c.take(); // stop tracking return true; } @@ -3265,16 +3281,37 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign Qt::HANDLE currentThreadId = QThread::currentThreadId(); + { QMutexLocker locker(signalSlotLock(sender)); - QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; - if (!connectionLists) { + struct ConnectionListsRef { + QObjectConnectionListVector *connectionLists; + ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists) + { + if (connectionLists) + ++connectionLists->inUse; + } + ~ConnectionListsRef() + { + if (!connectionLists) + return; + + --connectionLists->inUse; + Q_ASSERT(connectionLists->inUse >= 0); + if (connectionLists->orphaned) { + if (!connectionLists->inUse) + delete connectionLists; + } + } + + QObjectConnectionListVector *operator->() const { return connectionLists; } + }; + ConnectionListsRef connectionLists = sender->d_func()->connectionLists; + if (!connectionLists.connectionLists) { locker.unlock(); if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); return; } - ++connectionLists->inUse; - const QObjectPrivate::ConnectionList *list; if (signal_index < connectionLists->count()) @@ -3324,13 +3361,10 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign #endif } - QObjectPrivate::Sender currentSender; - QObjectPrivate::Sender *previousSender = 0; + QConnectionSenderSwitcher sw; + if (receiverInSameThread) { - currentSender.sender = sender; - currentSender.signal = signal_absolute_index; - currentSender.ref = 1; - previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); + sw.switchSender(receiver, sender, signal_absolute_index); } const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; const int method_relative = c->method_relative; @@ -3355,23 +3389,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign argv ? argv : empty_argv); } -#if defined(QT_NO_EXCEPTIONS) metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); -#else - QT_TRY { - metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); - } QT_CATCH(...) { - locker.relock(); - if (receiverInSameThread) - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); - - --connectionLists->inUse; - Q_ASSERT(connectionLists->inUse >= 0); - if (connectionLists->orphaned && !connectionLists->inUse) - delete connectionLists; - QT_RETHROW; - } -#endif if (qt_signal_spy_callback_set.slot_end_callback != 0) qt_signal_spy_callback_set.slot_end_callback(receiver, method); @@ -3379,9 +3397,6 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign locker.relock(); } - if (receiverInSameThread) - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); - if (connectionLists->orphaned) break; } while (c != last && (c = c->nextConnectionList) != 0); @@ -3392,17 +3407,8 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign //start over for all signals; ((list = &connectionLists->allsignals), true)); - --connectionLists->inUse; - Q_ASSERT(connectionLists->inUse >= 0); - if (connectionLists->orphaned) { - if (!connectionLists->inUse) - delete connectionLists; - } else if (connectionLists->dirty) { - sender->d_func()->cleanConnectionLists(); } - locker.unlock(); - if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 9f54f1a831..26cf2af59c 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -172,15 +172,9 @@ public: inline bool isSharedWith(const QByteArray &other) const { return d == other.d; } void clear(); -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char at(int i) const; - const char operator[](int i) const; - const char operator[](uint i) const; -#else char at(int i) const; char operator[](int i) const; char operator[](uint i) const; -#endif QByteRef operator[](int i); QByteRef operator[](uint i); @@ -359,21 +353,12 @@ inline QByteArray::~QByteArray() { if (!d->ref.deref()) qFree(d); } inline int QByteArray::size() const { return d->size; } -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -inline const char QByteArray::at(int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } -inline const char QByteArray::operator[](int i) const -{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } -inline const char QByteArray::operator[](uint i) const -{ Q_ASSERT(i < uint(size())); return d->data[i]; } -#else inline char QByteArray::at(int i) const { Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } inline char QByteArray::operator[](int i) const { Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } inline char QByteArray::operator[](uint i) const { Q_ASSERT(i < uint(size())); return d->data[i]; } -#endif inline bool QByteArray::isEmpty() const { return d->size == 0; } @@ -412,13 +397,8 @@ class Q_CORE_EXPORT QByteRef { : a(array),i(idx) {} friend class QByteArray; public: -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - inline operator const char() const - { return i < a.d->size ? a.d->data[i] : char(0); } -#else inline operator char() const { return i < a.d->size ? a.d->data[i] : char(0); } -#endif inline QByteRef &operator=(char c) { if (i >= a.d->size) a.expand(i); else a.detach(); a.d->data[i] = c; return *this; } diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 9db7d1ae83..475bd55de4 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1295,11 +1295,7 @@ ushort QChar::toCaseFolded(ushort ucs2) \sa toLatin1(), unicode(), QTextCodec::codecForCStrings() */ -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -const char QChar::toAscii() const -#else char QChar::toAscii() const -#endif { #ifndef QT_NO_CODEC_FOR_C_STRINGS if (QTextCodec::codecForCStrings()) diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index b7793403bd..d6db72d5ac 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -56,13 +56,8 @@ struct QLatin1Char { public: inline explicit QLatin1Char(char c) : ch(c) {} -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - inline const char toLatin1() const { return ch; } - inline const ushort unicode() const { return ushort(uchar(ch)); } -#else inline char toLatin1() const { return ch; } inline ushort unicode() const { return ushort(uchar(ch)); } -#endif private: char ch; @@ -230,20 +225,10 @@ public: UnicodeVersion unicodeVersion() const; -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char toAscii() const; - inline const char toLatin1() const; - inline const ushort unicode() const { return ucs; } -#else char toAscii() const; inline char toLatin1() const; inline ushort unicode() const { return ucs; } -#endif -#ifdef Q_NO_PACKED_REFERENCE - inline ushort &unicode() { return const_cast<ushort&>(ucs); } -#else inline ushort &unicode() { return ucs; } -#endif static QChar fromAscii(char c); static QChar fromLatin1(char c); @@ -339,11 +324,7 @@ Q_DECLARE_TYPEINFO(QChar, Q_MOVABLE_TYPE); inline QChar::QChar() : ucs(0) {} -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE -inline const char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } -#else inline char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } -#endif inline QChar QChar::fromLatin1(char c) { return QChar(ushort(uchar(c))); } inline QChar::QChar(uchar c, uchar r) : ucs(ushort((r << 8) | c)){} diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 80c610be36..14dfc6a139 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -164,7 +164,7 @@ void **QListData::append(int n) if (b - n >= 2 * d->alloc / 3) { // we have enough space. Just not at the end -> move it. e -= b; - ::memcpy(d->array, d->array + b, e * sizeof(void *)); + ::memmove(d->array, d->array + b, e * sizeof(void *)); d->begin = 0; } else { realloc(grow(d->alloc + n)); diff --git a/src/corelib/tools/qrefcount.cpp b/src/corelib/tools/qrefcount.cpp new file mode 100644 index 0000000000..c40214b2ab --- /dev/null +++ b/src/corelib/tools/qrefcount.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QtPrivate::RefCount + \internal + + QRefCount implements atomic ref counting for Qt's shared classes. It behaves very similar + to QAtomicInt, but ignores negative ref counts. + + This can be used to allow to implement e.g. const read-only QStringData objects. QString::shared_null and + the qs(...) macro make use of this feature. +*/ diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h new file mode 100644 index 0000000000..9223cfe352 --- /dev/null +++ b/src/corelib/tools/qrefcount.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREFCOUNT_H +#define QREFCOUNT_H + +#include <QtCore/qatomic.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtPrivate +{ + +class RefCount +{ +public: + inline void ref() { + if (atomic >= 0) + atomic.ref(); + } + + inline bool deref() { + if (atomic < 0) + return true; + return atomic.deref(); + } + + inline bool operator==(int value) const + { return atomic.operator ==(value); } + inline bool operator!=(int value) const + { return atomic.operator !=(value); } + inline bool operator!() const + { return atomic.operator !(); } + inline operator int() const + { return atomic.operator int(); } + inline RefCount &operator=(int value) + { atomic = value; return *this; } + + QBasicAtomicInt atomic; +}; + +#define Q_REFCOUNT_INITIALIZER(a) { Q_BASIC_ATOMIC_INITIALIZER(a) } + +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index afb396ce50..dab281cdf8 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -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 @@ -797,10 +800,8 @@ const QString::Null QString::null = { }; \sa split() */ -QString::Data QString::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_null.array, 0, 0, 0, 0, 0, {0} }; -QString::Data QString::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), - 0, 0, shared_empty.array, 0, 0, 0, 0, 0, {0} }; +const QConstStringData<1> QString::shared_null = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; +const QConstStringData<1> QString::shared_empty = { { Q_REFCOUNT_INITIALIZER(-1), 0, 0, false, { 0 } }, { 0 } }; int QString::grow(int size) { @@ -1044,20 +1045,15 @@ int QString::toWCharArray(wchar_t *array) const QString::QString(const QChar *unicode, int size) { if (!unicode) { - d = &shared_null; - d->ref.ref(); + d = const_cast<Data *>(&shared_null.str); } else if (size <= 0) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - memcpy(d->array, unicode, size * sizeof(QChar)); - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + memcpy(d->data(), unicode, size * sizeof(QChar)); + d->data()[size] = '\0'; } } @@ -1073,24 +1069,19 @@ QString::QString(const QChar *unicode, int size) QString::QString(const QChar *unicode) { if (!unicode) { - d = &shared_null; - d->ref.ref(); + d = const_cast<Data *>(&shared_null.str); } else { int size = 0; while (unicode[size] != 0) ++size; if (!size) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - memcpy(d->array, unicode, size * sizeof(QChar)); - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + memcpy(d->data(), unicode, size * sizeof(QChar)); + d->data()[size] = '\0'; } } } @@ -1105,18 +1096,14 @@ QString::QString(const QChar *unicode) QString::QString(int size, QChar ch) { if (size <= 0) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; - ushort *i = d->array + size; - ushort *b = d->array; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; + ushort *i = d->data() + size; + ushort *b = d->data(); const ushort value = ch.unicode(); while (i != b) *--i = value; @@ -1131,13 +1118,10 @@ QString::QString(int size, QChar ch) */ QString::QString(int size, Qt::Initialization) { - d = (Data*) qMalloc(sizeof(Data)+size*sizeof(QChar)); + d = (Data*) qMalloc(sizeof(Data)+(size+1)*sizeof(QChar)); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; } /*! \fn QString::QString(const QLatin1String &str) @@ -1152,15 +1136,11 @@ QString::QString(int size, Qt::Initialization) */ QString::QString(QChar ch) { - void *buf = qMalloc(sizeof(Data) + sizeof(QChar)); - Q_CHECK_PTR(buf); - d = reinterpret_cast<Data *>(buf); - d->ref = 1; - d->alloc = d->size = 1; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[0] = ch.unicode(); - d->array[1] = '\0'; + d = (Data *) qMalloc(sizeof(Data) + 2*sizeof(QChar)); + Q_CHECK_PTR(d); + *d = (Data) { Q_REFCOUNT_INITIALIZER(1), 1, 1, false, { 0 } }; + d->data()[0] = ch.unicode(); + d->data()[1] = '\0'; } /*! \fn QString::QString(const QByteArray &ba) @@ -1256,21 +1236,23 @@ void QString::resize(int size) if (size < 0) size = 0; - if (size == 0 && !d->capacity) { - Data *x = &shared_empty; - x->ref.ref(); + if (d->offset && d->ref == 1 && size < d->size) { + d->size = size; + return; + } + + if (size == 0 && !d->capacityReserved) { + Data *x = const_cast<Data *>(&shared_empty.str); if (!d->ref.deref()) QString::free(d); d = x; } else { if (d->ref != 1 || size > d->alloc || - (!d->capacity && size < d->size && size < d->alloc >> 1)) + (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) realloc(grow(size)); if (d->alloc >= size) { d->size = size; - if (d->data == d->array) { - d->array[size] = '\0'; - } + d->data()[size] = '\0'; } } } @@ -1328,28 +1310,21 @@ void QString::resize(int size) // ### Qt 5: rename reallocData() to avoid confusion. 197625 void QString::realloc(int alloc) { - if (d->ref != 1 || d->data != d->array) { - Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc * sizeof(QChar))); + if (d->ref != 1 || d->offset) { + Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + (alloc+1) * sizeof(QChar))); Q_CHECK_PTR(x); - x->size = qMin(alloc, d->size); - ::memcpy(x->array, d->data, x->size * sizeof(QChar)); - x->array[x->size] = 0; - x->ref = 1; - x->alloc = alloc; - x->clean = d->clean; - x->simpletext = d->simpletext; - x->righttoleft = d->righttoleft; - x->capacity = d->capacity; - x->data = x->array; + *x = (Data){ Q_REFCOUNT_INITIALIZER(1), qMin(alloc, d->size), alloc, d->capacityReserved, { 0 } }; + ::memcpy(x->data(), d->data(), x->size * sizeof(QChar)); + x->data()[x->size] = 0; if (!d->ref.deref()) QString::free(d); d = x; } else { - Data *p = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc * sizeof(QChar))); + Data *p = static_cast<Data *>(qRealloc(d, sizeof(Data) + (alloc+1) * sizeof(QChar))); Q_CHECK_PTR(p); d = p; d->alloc = alloc; - d->data = d->array; + d->offset = 0; } } @@ -1363,8 +1338,8 @@ void QString::expand(int i) int sz = d->size; resize(qMax(i + 1, sz)); if (d->size - 1 > sz) { - ushort *n = d->data + d->size - 1; - ushort *e = d->data + sz; + ushort *n = d->data() + d->size - 1; + ushort *e = d->data() + sz; while (n != e) * --n = ' '; } @@ -1482,9 +1457,9 @@ QString &QString::insert(int i, const QLatin1String &str) int len = qstrlen(str.latin1()); expand(qMax(d->size, i) + len - 1); - ::memmove(d->data + i + len, d->data + i, (d->size - i - len) * sizeof(QChar)); + ::memmove(d->data() + i + len, d->data() + i, (d->size - i - len) * sizeof(QChar)); for (int j = 0; j < len; ++j) - d->data[i + j] = s[j]; + d->data()[i + j] = s[j]; return *this; } @@ -1501,7 +1476,7 @@ QString& QString::insert(int i, const QChar *unicode, int size) return *this; const ushort *s = (const ushort *)unicode; - if (s >= d->data && s < d->data + d->alloc) { + if (s >= d->data() && s < d->data() + d->alloc) { // Part of me - take a copy ushort *tmp = static_cast<ushort *>(qMalloc(size * sizeof(QChar))); Q_CHECK_PTR(tmp); @@ -1513,8 +1488,8 @@ QString& QString::insert(int i, const QChar *unicode, int size) expand(qMax(d->size, i) + size - 1); - ::memmove(d->data + i + size, d->data + i, (d->size - i - size) * sizeof(QChar)); - memcpy(d->data + i, s, size * sizeof(QChar)); + ::memmove(d->data() + i + size, d->data() + i, (d->size - i - size) * sizeof(QChar)); + memcpy(d->data() + i, s, size * sizeof(QChar)); return *this; } @@ -1532,8 +1507,8 @@ QString& QString::insert(int i, QChar ch) if (i < 0) return *this; expand(qMax(i, d->size)); - ::memmove(d->data + i + 1, d->data + i, (d->size - i) * sizeof(QChar)); - d->data[i] = ch.unicode(); + ::memmove(d->data() + i + 1, d->data() + i, (d->size - i) * sizeof(QChar)); + d->data()[i] = ch.unicode(); return *this; } @@ -1557,15 +1532,15 @@ QString& QString::insert(int i, QChar ch) */ QString &QString::append(const QString &str) { - if (str.d != &shared_null) { - if (d == &shared_null) { + if (str.d != &shared_null.str) { + if (d == &shared_null.str) { operator=(str); } else { if (d->ref != 1 || d->size + str.d->size > d->alloc) realloc(grow(d->size + str.d->size)); - memcpy(d->data + d->size, str.d->data, str.d->size * sizeof(QChar)); + memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; - d->data[d->size] = '\0'; + d->data()[d->size] = '\0'; } } return *this; @@ -1583,7 +1558,7 @@ QString &QString::append(const QLatin1String &str) int len = qstrlen((char *)s); if (d->ref != 1 || d->size + len > d->alloc) realloc(grow(d->size + len)); - ushort *i = d->data + d->size; + ushort *i = d->data() + d->size; while ((*i++ = *s++)) ; d->size += len; @@ -1626,8 +1601,8 @@ QString &QString::append(QChar ch) { if (d->ref != 1 || d->size + 1 > d->alloc) realloc(grow(d->size + 1)); - d->data[d->size++] = ch.unicode(); - d->data[d->size] = '\0'; + d->data()[d->size++] = ch.unicode(); + d->data()[d->size] = '\0'; return *this; } @@ -1707,7 +1682,7 @@ QString &QString::remove(int pos, int len) resize(pos); // truncate } else if (len > 0) { detach(); - memmove(d->data + pos, d->data + pos + len, + memmove(d->data() + pos, d->data() + pos + len, (d->size - pos - len + 1) * sizeof(ushort)); d->size -= len; } @@ -1756,14 +1731,14 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) ushort c = ch.unicode(); if (cs == Qt::CaseSensitive) { while (i < d->size) - if (d->data[i] == ch) + if (d->data()[i] == ch) remove(i, 1); else i++; } else { c = foldCase(c); while (i < d->size) - if (foldCase(d->data[i]) == c) + if (foldCase(d->data()[i]) == c) remove(i, 1); else i++; @@ -1859,10 +1834,10 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS */ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen) { - // copy *after in case it lies inside our own d->data area + // copy *after in case it lies inside our own d->data() area // (which we could possibly invalidate via a realloc or corrupt via memcpy operations.) QChar *afterBuffer = const_cast<QChar *>(after); - if (after >= reinterpret_cast<QChar *>(d->data) && after < reinterpret_cast<QChar *>(d->data) + d->size) { + if (after >= reinterpret_cast<QChar *>(d->data()) && after < reinterpret_cast<QChar *>(d->data()) + d->size) { afterBuffer = static_cast<QChar *>(qMalloc(alen*sizeof(QChar))); Q_CHECK_PTR(afterBuffer); ::memcpy(afterBuffer, after, alen*sizeof(QChar)); @@ -1873,30 +1848,30 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar // replace in place detach(); for (int i = 0; i < nIndices; ++i) - memcpy(d->data + indices[i], afterBuffer, alen * sizeof(QChar)); + memcpy(d->data() + indices[i], afterBuffer, alen * sizeof(QChar)); } else if (alen < blen) { // replace from front detach(); uint to = indices[0]; if (alen) - memcpy(d->data+to, after, alen*sizeof(QChar)); + memcpy(d->data()+to, after, alen*sizeof(QChar)); to += alen; uint movestart = indices[0] + blen; for (int i = 1; i < nIndices; ++i) { int msize = indices[i] - movestart; if (msize > 0) { - memmove(d->data + to, d->data + movestart, msize * sizeof(QChar)); + memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar)); to += msize; } if (alen) { - memcpy(d->data + to, afterBuffer, alen*sizeof(QChar)); + memcpy(d->data() + to, afterBuffer, alen*sizeof(QChar)); to += alen; } movestart = indices[i] + blen; } int msize = d->size - movestart; if (msize > 0) - memmove(d->data + to, d->data + movestart, msize * sizeof(QChar)); + memmove(d->data() + to, d->data() + movestart, msize * sizeof(QChar)); resize(d->size - nIndices*(blen-alen)); } else { // replace from back @@ -1910,9 +1885,9 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar int movestart = indices[nIndices] + blen; int insertstart = indices[nIndices] + nIndices*(alen-blen); int moveto = insertstart + alen; - memmove(d->data + moveto, d->data + movestart, + memmove(d->data() + moveto, d->data() + movestart, (moveend - movestart)*sizeof(QChar)); - memcpy(d->data + insertstart, afterBuffer, alen*sizeof(QChar)); + memcpy(d->data() + insertstart, afterBuffer, alen*sizeof(QChar)); moveend = movestart-blen; } } @@ -1994,7 +1969,7 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs return remove(ch, cs); if (after.d->size == 1) - return replace(ch, after.d->data[0], cs); + return replace(ch, after.d->data()[0], cs); if (d->size == 0) return *this; @@ -2007,13 +1982,13 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs uint pos = 0; if (cs == Qt::CaseSensitive) { while (pos < 1023 && index < d->size) { - if (d->data[index] == cc) + if (d->data()[index] == cc) indices[pos++] = index; index++; } } else { while (pos < 1023 && index < d->size) { - if (QChar::toCaseFolded(d->data[index]) == cc) + if (QChar::toCaseFolded(d->data()[index]) == cc) indices[pos++] = index; index++; } @@ -2045,7 +2020,7 @@ QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs) ushort b = before.unicode(); if (d->size) { detach(); - ushort *i = d->data; + ushort *i = d->data(); const ushort *e = i + d->size; if (cs == Qt::CaseSensitive) { for (; i != e; ++i) @@ -2104,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]; @@ -2127,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]; @@ -2148,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]; @@ -2170,7 +2145,7 @@ bool QString::operator==(const QString &other) const if (d->size != other.d->size) return false; - return qMemEquals(d->data, other.d->data, d->size); + return qMemEquals(d->data(), other.d->data(), d->size); } /*! @@ -2178,20 +2153,23 @@ 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 (d->size != other.size()) + return false; - if (!c) + if (!other.size()) return isEmpty(); - while (*c) { - if (uc == e || *uc != *c) + const ushort *uc = d->data(); + const ushort *e = uc + d->size; + const uchar *c = (uchar *)other.latin1(); + + while (uc < e) { + if (*uc != *c) return false; ++uc; ++c; } - return (uc == e); + return true; } /*! \fn bool QString::operator==(const QByteArray &other) const @@ -2240,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 @@ -2342,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 @@ -2687,7 +2665,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c { const int sl = str.d->size; if (sl == 1) - return lastIndexOf(QChar(str.d->data[0]), from, cs); + return lastIndexOf(QChar(str.d->data()[0]), from, cs); const int l = d->size; if (from < 0) @@ -2700,7 +2678,7 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c if (from > delta) from = delta; - return lastIndexOfHelper(d->data, from, str.d->data, str.d->size, cs); + return lastIndexOfHelper(d->data(), from, str.d->data(), str.d->size, cs); } /*! @@ -2724,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); @@ -2743,7 +2721,7 @@ int QString::lastIndexOf(const QLatin1String &str, int from, Qt::CaseSensitivity for (int i = 0; i < sl; ++i) s[i] = str.latin1()[i]; - return lastIndexOfHelper(d->data, from, s.data(), sl, cs); + return lastIndexOfHelper(d->data(), from, s.data(), sl, cs); } /*! @@ -2789,7 +2767,7 @@ int QString::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs if (from > delta) from = delta; - return lastIndexOfHelper(d->data, from, reinterpret_cast<const ushort*>(str.unicode()), + return lastIndexOfHelper(d->data(), from, reinterpret_cast<const ushort*>(str.unicode()), str.size(), cs); } @@ -2940,14 +2918,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after) while (i < pos) { int copyend = replacements[i].pos; int size = copyend - copystart; - memcpy(uc, d->data + copystart, size * sizeof(QChar)); + memcpy(uc, d->data() + copystart, size * sizeof(QChar)); uc += size; - memcpy(uc, after.d->data, al * sizeof(QChar)); + memcpy(uc, after.d->data(), al * sizeof(QChar)); uc += al; copystart = copyend + replacements[i].length; i++; } - memcpy(uc, d->data + copystart, (d->size - copystart) * sizeof(QChar)); + memcpy(uc, d->data() + copystart, (d->size - copystart) * sizeof(QChar)); newstring.resize(newlen); *this = newstring; caretMode = QRegExp::CaretWontMatch; @@ -3366,7 +3344,7 @@ QString QString::left(int n) const { if (n >= d->size || n < 0) return *this; - return QString((const QChar*) d->data, n); + return QString((const QChar*) d->data(), n); } /*! @@ -3384,7 +3362,7 @@ QString QString::right(int n) const { if (n >= d->size || n < 0) return *this; - return QString((const QChar*) d->data + d->size - n, n); + return QString((const QChar*) d->data() + d->size - n, n); } /*! @@ -3406,7 +3384,7 @@ QString QString::right(int n) const QString QString::mid(int position, int n) const { - if (d == &shared_null || position >= d->size) + if (d == &shared_null.str || position >= d->size) return QString(); if (n < 0) n = d->size - position; @@ -3418,7 +3396,7 @@ QString QString::mid(int position, int n) const n = d->size - position; if (position == 0 && n == d->size) return *this; - return QString((const QChar*) d->data + position, n); + return QString((const QChar*) d->data() + position, n); } /*! @@ -3456,8 +3434,8 @@ bool QString::startsWith(const QChar &c, Qt::CaseSensitivity cs) const { return d->size && (cs == Qt::CaseSensitive - ? d->data[0] == c - : foldCase(d->data[0]) == foldCase(c.unicode())); + ? d->data()[0] == c + : foldCase(d->data()[0]) == foldCase(c.unicode())); } /*! @@ -3530,8 +3508,8 @@ bool QString::endsWith(const QChar &c, Qt::CaseSensitivity cs) const { return d->size && (cs == Qt::CaseSensitive - ? d->data[d->size - 1] == c - : foldCase(d->data[d->size - 1]) == foldCase(c.unicode())); + ? d->data()[d->size - 1] == c + : foldCase(d->data()[d->size - 1]) == foldCase(c.unicode())); } /*! \fn const char *QString::ascii() const @@ -3658,10 +3636,6 @@ QByteArray QString::toLatin1() const return toLatin1_helper(unicode(), length()); } -// ### Qt 5: Change the return type of at least toAscii(), -// toLatin1() and unicode() such that the use of Q_COMPILER_MANGLES_RETURN_TYPE -// isn't necessary in the header. See task 177402. - /*! Returns an 8-bit representation of the string as a QByteArray. @@ -3765,22 +3739,17 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size) { Data *d; if (!str) { - d = &shared_null; - d->ref.ref(); + d = const_cast<Data *>(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { if (size < 0) size = qstrlen(str); - d = static_cast<Data *>(qMalloc(sizeof(Data) + size * sizeof(QChar))); + d = static_cast<Data *>(qMalloc(sizeof(Data) + (size+1) * sizeof(QChar))); Q_CHECK_PTR(d); - d->ref = 1; - d->alloc = d->size = size; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; - d->data = d->array; - d->array[size] = '\0'; - ushort *dst = d->data; + *d = (Data){ Q_REFCOUNT_INITIALIZER(1), size, size, false, { 0 } }; + d->data()[size] = '\0'; + ushort *dst = d->data(); /* SIMD: * Unpacking with SSE has been shown to improve performance on recent CPUs * The same method gives no improvement with NEON. @@ -3818,11 +3787,9 @@ QString::Data *QString::fromAscii_helper(const char *str, int size) if (codecForCStrings) { Data *d; if (!str) { - d = &shared_null; - d->ref.ref(); + d = const_cast<Data *>(&shared_null.str); } else if (size == 0 || (!*str && size < 0)) { - d = &shared_empty; - d->ref.ref(); + d = const_cast<Data *>(&shared_empty.str); } else { if (size < 0) size = qstrlen(str); @@ -3867,7 +3834,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); @@ -3995,7 +3962,7 @@ QString& QString::setUnicode(const QChar *unicode, int size) { resize(size); if (unicode && size) - memcpy(d->data, unicode, size * sizeof(QChar)); + memcpy(d->data(), unicode, size * sizeof(QChar)); return *this; } @@ -4034,7 +4001,7 @@ QString QString::simplified() const if (d->size == 0) return *this; - const QChar * const start = reinterpret_cast<QChar *>(d->data); + const QChar * const start = reinterpret_cast<QChar *>(d->data()); const QChar *from = start; const QChar *fromEnd = start + d->size; forever { @@ -4043,8 +4010,7 @@ QString QString::simplified() const break; if (++from == fromEnd) { // All-whitespace string - shared_empty.ref.ref(); - return QString(&shared_empty, 0); + return QString(shared_empty); } } // This loop needs no underflow check, as we already determined that @@ -4079,7 +4045,7 @@ QString QString::simplified() const // of already simplified characters - at least one, obviously - // without a trailing space. QString result((fromEnd - from) + copyCount, Qt::Uninitialized); - QChar *to = reinterpret_cast<QChar *>(result.d->data); + QChar *to = reinterpret_cast<QChar *>(result.d->data()); ::memcpy(to, copyFrom, copyCount * 2); to += copyCount; fromEnd--; @@ -4100,7 +4066,7 @@ QString QString::simplified() const } done: *to++ = ch; - result.truncate(to - reinterpret_cast<QChar *>(result.d->data)); + result.truncate(to - reinterpret_cast<QChar *>(result.d->data())); return result; } @@ -4124,7 +4090,7 @@ QString QString::trimmed() const { if (d->size == 0) return *this; - const QChar *s = (const QChar*)d->data; + const QChar *s = (const QChar*)d->data(); if (!s->isSpace() && !s[d->size-1].isSpace()) return *this; int start = 0; @@ -4137,8 +4103,7 @@ QString QString::trimmed() const } int l = end - start + 1; if (l <= 0) { - shared_empty.ref.ref(); - return QString(&shared_empty, 0); + return QString(shared_empty); } return QString(s + start, l); } @@ -4250,8 +4215,8 @@ QString& QString::fill(QChar ch, int size) { resize(size < 0 ? d->size : size); if (d->size) { - QChar *i = (QChar*)d->data + d->size; - QChar *b = (QChar*)d->data; + QChar *i = (QChar*)d->data() + d->size; + QChar *b = (QChar*)d->data(); while (i != b) *--i = ch; } @@ -4597,7 +4562,7 @@ int QString::compare(const QString &other, Qt::CaseSensitivity cs) const { if (cs == Qt::CaseSensitive) return ucstrcmp(constData(), length(), other.constData(), other.length()); - return ucstricmp(d->data, d->data + d->size, other.d->data, other.d->data + other.d->size); + return ucstricmp(d->data(), d->data() + d->size, other.d->data(), other.d->data() + other.d->size); } /*! @@ -4828,12 +4793,9 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, const ushort *QString::utf16() const { - if (d->data != d->array) { - QString *that = const_cast<QString*>(this); - that->realloc(); // ensure '\\0'-termination for ::fromRawData strings - return that->d->data; - } - return d->array; + if (d->offset) + const_cast<QString*>(this)->realloc(); // ensure '\\0'-termination for ::fromRawData strings + return d->data(); } /*! @@ -4862,8 +4824,8 @@ QString QString::leftJustified(int width, QChar fill, bool truncate) const if (padlen > 0) { result.resize(len+padlen); if (len) - memcpy(result.d->data, d->data, sizeof(QChar)*len); - QChar *uc = (QChar*)result.d->data + len; + memcpy(result.d->data(), d->data(), sizeof(QChar)*len); + QChar *uc = (QChar*)result.d->data() + len; while (padlen--) * uc++ = fill; } else { @@ -4900,11 +4862,11 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const int padlen = width - len; if (padlen > 0) { result.resize(len+padlen); - QChar *uc = (QChar*)result.d->data; + QChar *uc = (QChar*)result.d->data(); while (padlen--) * uc++ = fill; if (len) - memcpy(uc, d->data, sizeof(QChar)*len); + memcpy(uc, d->data(), sizeof(QChar)*len); } else { if (truncate) result = left(width); @@ -4924,7 +4886,7 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const QString QString::toLower() const { - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; if (!d->size) @@ -4939,7 +4901,7 @@ QString QString::toLower() const } #endif - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; // this avoids one out of bounds check in the loop if (QChar(*p).isLowSurrogate()) @@ -4952,17 +4914,17 @@ QString QString::toLower() const const QUnicodeTables::Properties *prop = qGetProp(c); if (prop->lowerCaseDiff || prop->lowerCaseSpecial) { QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort)); - ushort *pp = s.d->data + (p - d->data); + memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); + ushort *pp = s.d->data() + (p - d->data()); while (p < e) { uint c = *p; if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate()) c = QChar::surrogateToUcs4(*(p - 1), c); prop = qGetProp(c); if (prop->lowerCaseSpecial) { - int pos = pp - s.d->data; + int pos = pp - s.d->data(); s.resize(s.d->size + SPECIAL_CASE_MAX_LEN); - pp = s.d->data + pos; + pp = s.d->data() + pos; const ushort *specialCase = specialCaseMap + prop->lowerCaseDiff; while (*specialCase) *pp++ = *specialCase++; @@ -4971,7 +4933,7 @@ QString QString::toLower() const } ++p; } - s.truncate(pp - s.d->data); + s.truncate(pp - s.d->data()); return s; } ++p; @@ -4988,11 +4950,11 @@ QString QString::toCaseFolded() const if (!d->size) return *this; - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; uint last = 0; while (p < e) { @@ -5000,9 +4962,9 @@ QString QString::toCaseFolded() const if (folded != *p) { QString s(*this); s.detach(); - ushort *pp = s.d->data + (p - d->data); - const ushort *ppe = s.d->data + s.d->size; - last = pp > s.d->data ? *(pp - 1) : 0; + ushort *pp = s.d->data() + (p - d->data()); + const ushort *ppe = s.d->data() + s.d->size; + last = pp > s.d->data() ? *(pp - 1) : 0; while (pp < ppe) { *pp = foldCase(*pp, last); ++pp; @@ -5024,7 +4986,7 @@ QString QString::toCaseFolded() const QString QString::toUpper() const { - const ushort *p = d->data; + const ushort *p = d->data(); if (!p) return *this; if (!d->size) @@ -5039,7 +5001,7 @@ QString QString::toUpper() const } #endif - const ushort *e = d->data + d->size; + const ushort *e = d->data() + d->size; // this avoids one out of bounds check in the loop if (QChar(*p).isLowSurrogate()) @@ -5052,17 +5014,17 @@ QString QString::toUpper() const const QUnicodeTables::Properties *prop = qGetProp(c); if (prop->upperCaseDiff || prop->upperCaseSpecial) { QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data, d->data, (p - d->data)*sizeof(ushort)); - ushort *pp = s.d->data + (p - d->data); + memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); + ushort *pp = s.d->data() + (p - d->data()); while (p < e) { uint c = *p; if (QChar(c).isLowSurrogate() && QChar(*(p - 1)).isHighSurrogate()) c = QChar::surrogateToUcs4(*(p - 1), c); prop = qGetProp(c); if (prop->upperCaseSpecial) { - int pos = pp - s.d->data; + int pos = pp - s.d->data(); s.resize(s.d->size + SPECIAL_CASE_MAX_LEN); - pp = s.d->data + pos; + pp = s.d->data() + pos; const ushort *specialCase = specialCaseMap + prop->upperCaseDiff; while (*specialCase) *pp++ = *specialCase++; @@ -5071,7 +5033,7 @@ QString QString::toUpper() const } ++p; } - s.truncate(pp - s.d->data); + s.truncate(pp - s.d->data()); return s; } ++p; @@ -6196,19 +6158,19 @@ QString QString::repeated(int times) const if (result.d->alloc != resultSize) return QString(); // not enough memory - memcpy(result.d->data, d->data, d->size * sizeof(ushort)); + memcpy(result.d->data(), d->data(), d->size * sizeof(ushort)); int sizeSoFar = d->size; - ushort *end = result.d->data + sizeSoFar; + ushort *end = result.d->data() + sizeSoFar; const int halfResultSize = resultSize >> 1; while (sizeSoFar <= halfResultSize) { - memcpy(end, result.d->data, sizeSoFar * sizeof(ushort)); + memcpy(end, result.d->data(), sizeSoFar * sizeof(ushort)); end += sizeSoFar; sizeSoFar <<= 1; } - memcpy(end, result.d->data, (resultSize - sizeSoFar) * sizeof(ushort)); - result.d->data[resultSize] = '\0'; + memcpy(end, result.d->data(), (resultSize - sizeSoFar) * sizeof(ushort)); + result.d->data()[resultSize] = '\0'; result.d->size = resultSize; return result; } @@ -6902,7 +6864,7 @@ QString QString::multiArg(int numArgs, const QString **args) const { QString result; QMap<int, int> numbersUsed; - const QChar *uc = (const QChar *) d->data; + const QChar *uc = (const QChar *) d->data(); const int len = d->size; const int end = len - 1; int lastNumber = -1; @@ -6951,62 +6913,50 @@ QString QString::multiArg(int numArgs, const QString **args) const return result; } -static bool isStringRightToLeft(const ushort *p, const ushort *end) -{ - bool righttoleft = false; - while (p < end) { - switch(QChar::direction(*p)) - { - case QChar::DirL: - goto end; - case QChar::DirR: - case QChar::DirAL: - righttoleft = true; - goto end; - default: - break; - } - ++p; - } - end: - return righttoleft; -} -/*! \internal - */ -void QString::updateProperties() const +/*! \fn bool QString::isSimpleText() const + + \internal +*/ +bool QString::isSimpleText() const { - ushort *p = d->data; - ushort *end = p + d->size; - d->simpletext = true; + const ushort *p = d->data(); + const ushort * const end = p + d->size; while (p < end) { ushort uc = *p; // sort out regions of complex text formatting if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) { - d->simpletext = false; + return false; } p++; } - d->righttoleft = isStringRightToLeft(d->data, d->data + d->size); - d->clean = true; -} - -bool QString::isRightToLeft() const -{ - return isStringRightToLeft(d->data, d->data + d->size); + return true; } -/*! \fn bool QString::isSimpleText() const - - \internal -*/ - /*! \fn bool QString::isRightToLeft() const Returns true if the string is read right to left. */ - +bool QString::isRightToLeft() const +{ + const ushort *p = d->data(); + const ushort * const end = p + d->size; + while (p < end) { + switch(QChar::direction(*p)) + { + case QChar::DirL: + return false; + case QChar::DirR: + case QChar::DirAL: + return true; + default: + break; + } + ++p; + } + return false; +} /*! \fn QChar *QString::data() @@ -7122,17 +7072,13 @@ bool QString::isRightToLeft() const QString QString::fromRawData(const QChar *unicode, int size) { Data *x = static_cast<Data *>(qMalloc(sizeof(Data))); + *x = (Data){ Q_REFCOUNT_INITIALIZER(1), size, 0, false, { 0 } }; Q_CHECK_PTR(x); if (unicode) { - x->data = (ushort *)unicode; + x->offset = (const ushort *)unicode - (x->d + sizeof(qptrdiff)/sizeof(ushort)); } else { - x->data = x->array; size = 0; } - x->ref = 1; - x->alloc = x->size = size; - *x->array = '\0'; - x->clean = x->simpletext = x->righttoleft = x->capacity = 0; return QString(x, 0); } @@ -7152,18 +7098,16 @@ QString QString::fromRawData(const QChar *unicode, int size) */ QString &QString::setRawData(const QChar *unicode, int size) { - if (d->ref != 1 || (d->data == d->array && d->alloc)) { + if (d->ref != 1 || d->alloc) { *this = fromRawData(unicode, size); } else { if (unicode) { - d->data = (ushort *)unicode; + d->size = size; + d->offset = (const ushort *)unicode - (d->d + sizeof(qptrdiff)/sizeof(ushort)); } else { - d->data = d->array; - size = 0; + d->offset = 0; + d->size = 0; } - d->alloc = d->size = size; - *d->array = '\0'; - d->clean = d->simpletext = d->righttoleft = d->capacity = 0; } return *this; } @@ -7212,7 +7156,7 @@ QString &QString::setRawData(const QChar *unicode, int size) \snippet doc/src/snippets/code/src_corelib_tools_qstring.cpp 6 - \sa QString, QLatin1Char + \sa QString, QLatin1Char, QStringLiteral */ /*! \fn QLatin1String::QLatin1String(const char *str) @@ -7526,7 +7470,7 @@ QDataStream &operator>>(QDataStream &in, QString &str) } } } else { - str = QLatin1String(""); + str = QString(QLatin1String("")); } } return in; @@ -8345,7 +8289,7 @@ QStringRef QString::rightRef(int n) const QStringRef QString::midRef(int position, int n) const { - if (d == &shared_null || position >= d->size) + if (d == &shared_null.str || position >= d->size) return QStringRef(); if (n < 0) n = d->size - position; @@ -8498,7 +8442,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); @@ -8851,7 +8795,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]; @@ -8892,7 +8836,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); @@ -8943,7 +8887,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; @@ -9071,4 +9015,21 @@ QVector<uint> QStringRef::toUcs4() const return v; } +/*! + \macro QStringLiteral(str) + \relates QString + + The macro generates the data for a QString out of \a str at compile time if the compiler supports it. + Creating a QString from it is free in this case, and the generated string data is stored in + the read-only segment of the compiled object file. + + Using QStringLiteral instead of a double quoted ascii literal can significantly speed up creation + of QString's from data known at compile time. + + If the compiler is c++0x enabled the string \a str can actually contain unicode data. + + For compilers not supporting the creation of compile time strings, QStringLiteral will fall back to + QLatin1String. +*/ + QT_END_NAMESPACE diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 154012d132..27948e04ea 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,86 @@ 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; } +}; + +template<int N> struct QConstStringData; +template<int N> struct QConstStringDataPtr +{ + const QConstStringData<N> *ptr; +}; + +#if defined(Q_COMPILER_UNICODE_STRINGS) +template<int n> struct QConstStringData +{ + const QStringData str; + const char16_t data[n]; +}; +#define QT_QSTRING_UNICODE_MARKER u"" + +#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) +// wchar_t is 2 bytes +template<int n> struct QConstStringData +{ + const QStringData str; + const wchar_t data[n]; +}; +#define QT_QSTRING_UNICODE_MARKER L"" + +#else +template<int n> struct QConstStringData +{ + const QStringData str; + const ushort data[n]; +}; +#endif + +#if defined(QT_QSTRING_UNICODE_MARKER) +# if defined(Q_COMPILER_LAMBDA) +# define QStringLiteral(str) ([]() { \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + static const QConstStringData<Size> qstring_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + QConstStringDataPtr<Size> holder = { &qstring_literal }; \ + return holder; }()) + +# elif defined(Q_CC_GNU) +// We need to create a QStringData in the .rodata section of memory +// and the only way to do that is to create a "static const" variable. +// To do that, we need the __extension__ {( )} trick which only GCC supports + +# define QStringLiteral(str) \ + __extension__ ({ \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + static const QConstStringData<Size> qstring_literal = \ + { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + QConstStringDataPtr<Size> holder = { &qstring_literal }; \ + holder; }) +# endif +#endif + +#ifndef QStringLiteral +// no lambdas, not GCC, or GCC in C++98 mode with 4-byte wchar_t +// fallback, uses QLatin1String as next best options + +# define QStringLiteral(str) QLatin1String(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 +185,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 +339,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 +568,19 @@ 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)) {} + template <int N> + Q_DECL_CONSTEXPR inline QString(QConstStringDataPtr<N> dd) : d(const_cast<QStringData *>(&dd.ptr->str)) {} private: #if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) @@ -511,22 +592,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 @@ -563,11 +633,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; } @@ -595,9 +665,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())) @@ -605,23 +678,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 +776,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 @@ -756,15 +829,9 @@ public: inline void setCell(uchar cell); inline void setRow(uchar row); -#ifdef Q_COMPILER_MANGLES_RETURN_TYPE - const char toAscii() const { return QChar(*this).toAscii(); } - const char toLatin1() const { return QChar(*this).toLatin1(); } - const ushort unicode() const { return QChar(*this).unicode(); } -#else char toAscii() const { return QChar(*this).toAscii(); } char toLatin1() const { return QChar(*this).toLatin1(); } ushort unicode() const { return QChar(*this).unicode(); } -#endif ushort& unicode() { return s.data()[i].unicode(); } }; @@ -773,9 +840,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 +850,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 +1091,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 +1221,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 diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 1cc7e5d2c3..4c6848498b 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -45,47 +45,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 \reentrant @@ -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 diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 594ab2f183..6d998b62aa 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -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++; @@ -283,6 +249,23 @@ template <> struct QConcatenable<QString> : private QAbstractConcatenable #endif }; +template <int N> struct QConcatenable<QConstStringDataPtr<N> > : private QAbstractConcatenable +{ + typedef QConstStringDataPtr<N> type; + typedef QString ConvertTo; + enum { ExactSize = true }; + static int size(const type &) { return N; } + static inline void appendTo(const type &a, QChar *&out) + { + memcpy(out, reinterpret_cast<const char*>(a.ptr->data), sizeof(QChar) * N); + out += N; + } +#ifndef QT_NO_CAST_TO_ASCII + static inline QT_ASCII_CAST_WARN void appendTo(const type &a, char *&out) + { convertToAscii(a.ptr->data, N, out); } +#endif +}; + template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable { typedef QStringRef type; diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index efb7f46c9b..bded94399d 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -68,7 +68,7 @@ public: inline QStringList(const QStringList &l) : QList<QString>(l) { } inline QStringList(const QList<QString> &l) : QList<QString>(l) { } #ifdef Q_COMPILER_INITIALIZER_LISTS - inline QStringList(std::initializer_list<QString> args) : QList(args) { } + inline QStringList(std::initializer_list<QString> args) : QList<QString>(args) { } #endif inline void sort(); diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 42cab84cc0..f5b38eb1c0 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -30,6 +30,7 @@ HEADERS += \ tools/qrect.h \ tools/qregexp.h \ tools/qringbuffer_p.h \ + tools/qrefcount.h \ tools/qscopedpointer.h \ tools/qscopedpointer_p.h \ tools/qscopedvaluerollback.h \ @@ -72,6 +73,7 @@ SOURCES += \ tools/qcontiguouscache.cpp \ tools/qrect.cpp \ tools/qregexp.cpp \ + tools/qrefcount.cpp \ tools/qshareddata.cpp \ tools/qsharedpointer.cpp \ tools/qsimd.cpp \ |