diff options
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qarraydataops.h | 58 | ||||
-rw-r--r-- | src/corelib/tools/qcontiguouscache.h | 10 | ||||
-rw-r--r-- | src/corelib/tools/qcryptographichash.cpp | 100 | ||||
-rw-r--r-- | src/corelib/tools/qcryptographichash.h | 2 | ||||
-rw-r--r-- | src/corelib/tools/qset.h | 56 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 64 | ||||
-rw-r--r-- | src/corelib/tools/qvector.qdoc | 53 | ||||
-rw-r--r-- | src/corelib/tools/qversionnumber.cpp | 196 | ||||
-rw-r--r-- | src/corelib/tools/qversionnumber.h | 151 |
9 files changed, 529 insertions, 161 deletions
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 0d2be5d51c..1d74f49993 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -117,6 +117,9 @@ struct QPodArrayOps this->size += int(n); } + template <typename ...Args> + void emplaceBack(Args&&... args) { this->emplace(this->end(), T(std::forward<Args>(args)...)); } + void truncate(size_t newSize) { Q_ASSERT(this->isMutable()); @@ -163,16 +166,28 @@ struct QPodArrayOps *where++ = t; } - void insert(T *where, T &&t) + template <typename ...Args> + void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); } + + template <typename ...Args> + void emplace(T *where, Args&&... args) { Q_ASSERT(!this->isShared()); Q_ASSERT(where >= this->begin() && where <= this->end()); Q_ASSERT(this->allocatedCapacity() - this->size >= 1); - ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where), - (static_cast<const T*>(this->end()) - where) * sizeof(T)); - this->size += 1; - new (where) T(std::move(t)); + if (where == this->end()) { + new (this->end()) T(std::forward<Args>(args)...); + } else { + // Preserve the value, because it might be a reference to some part of the moved chunk + T t(std::forward<Args>(args)...); + + ::memmove(static_cast<void *>(where + 1), static_cast<void *>(where), + (static_cast<const T*>(this->end()) - where) * sizeof(T)); + *where = t; + } + + ++this->size; } @@ -289,6 +304,12 @@ struct QGenericArrayOps } } + template <typename ...Args> + void emplaceBack(Args&&... args) + { + this->emplace(this->end(), std::forward<Args>(args)...); + } + void truncate(size_t newSize) { Q_ASSERT(this->isMutable()); @@ -444,31 +465,20 @@ struct QGenericArrayOps } } - void insert(T *where, T &&t) + template <typename ...Args> + void createInPlace(T *where, Args&&... args) { new (where) T(std::forward<Args>(args)...); } + + template <typename iterator, typename ...Args> + void emplace(iterator where, Args&&... args) { Q_ASSERT(!this->isShared()); Q_ASSERT(where >= this->begin() && where <= this->end()); Q_ASSERT(this->allocatedCapacity() - this->size >= 1); - // Array may be truncated at where in case of exceptions - T *const end = this->end(); - - if (where != end) { - // Move elements in array - T *readIter = end - 1; - T *writeIter = end; - new (writeIter) T(std::move(*readIter)); - while (readIter > where) { - --readIter; - --writeIter; - *writeIter = std::move(*readIter); - } - *where = std::move(t); - } else { - new (where) T(std::move(t)); - } - + createInPlace(this->end(), std::forward<Args>(args)...); ++this->size; + + std::rotate(where, this->end() - 1, this->end()); } void erase(T *b, T *e) diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 8cae7d1651..451ba3e8de 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -56,8 +56,6 @@ struct Q_CORE_EXPORT QContiguousCacheData int count; int start; int offset; - uint sharable : 1; - uint reserved : 31; // total is 24 bytes (HP-UX aCC: 40 bytes) // the next entry is already aligned to 8 bytes @@ -96,7 +94,7 @@ public: typedef int size_type; explicit QContiguousCache(int capacity = 0); - QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } + QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); } inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(p); } @@ -178,8 +176,6 @@ void QContiguousCache<T>::detach_helper() x.d->start = d->start; x.d->offset = d->offset; x.d->alloc = d->alloc; - x.d->sharable = true; - x.d->reserved = 0; T *dest = x.p->array + x.d->start; T *src = p->array + d->start; @@ -267,7 +263,6 @@ void QContiguousCache<T>::clear() x.d->ref.storeRelaxed(1); x.d->alloc = d->alloc; x.d->count = x.d->start = x.d->offset = 0; - x.d->sharable = true; if (!d->ref.deref()) freeData(p); d = x.d; } @@ -287,7 +282,6 @@ QContiguousCache<T>::QContiguousCache(int cap) d->ref.storeRelaxed(1); d->alloc = cap; d->count = d->start = d->offset = 0; - d->sharable = true; } template <typename T> @@ -297,8 +291,6 @@ QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &o if (!d->ref.deref()) freeData(p); d = other.d; - if (!d->sharable) - detach_helper(); return *this; } diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index fa8d21e07a..1d4afabedd 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -359,53 +359,67 @@ void QCryptographicHash::reset() Adds the first \a length chars of \a data to the cryptographic hash. */ -void QCryptographicHash::addData(const char *data, int length) +void QCryptographicHash::addData(const char *data, qsizetype length) { - switch (d->method) { - case Sha1: - sha1Update(&d->sha1Context, (const unsigned char *)data, length); - break; + Q_ASSERT(length >= 0); + +#if QT_POINTER_SIZE == 8 + // feed the data UINT_MAX bytes at a time, as some of the methods below + // take a uint (of course, feeding more than 4G of data into the hashing + // functions will be pretty slow anyway) + qsizetype remaining = length; + while (remaining) { + length = qMin(qsizetype(std::numeric_limits<uint>::max()), remaining); + remaining -= length; +#else + { +#endif + switch (d->method) { + case Sha1: + sha1Update(&d->sha1Context, (const unsigned char *)data, length); + break; #ifdef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 - default: - Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in"); - Q_UNREACHABLE(); - break; + default: + Q_ASSERT_X(false, "QCryptographicHash", "Method not compiled in"); + Q_UNREACHABLE(); + break; #else - case Md4: - md4_update(&d->md4Context, (const unsigned char *)data, length); - break; - case Md5: - MD5Update(&d->md5Context, (const unsigned char *)data, length); - break; - case Sha224: - SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length); - break; - case Sha256: - SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length); - break; - case Sha384: - SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length); - break; - case Sha512: - SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length); - break; - case RealSha3_224: - case Keccak_224: - sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); - break; - case RealSha3_256: - case Keccak_256: - sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); - break; - case RealSha3_384: - case Keccak_384: - sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); - break; - case RealSha3_512: - case Keccak_512: - sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); - break; + case Md4: + md4_update(&d->md4Context, (const unsigned char *)data, length); + break; + case Md5: + MD5Update(&d->md5Context, (const unsigned char *)data, length); + break; + case Sha224: + SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length); + break; + case Sha256: + SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length); + break; + case Sha384: + SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length); + break; + case Sha512: + SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length); + break; + case RealSha3_224: + case Keccak_224: + sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); + break; + case RealSha3_256: + case Keccak_256: + sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); + break; + case RealSha3_384: + case Keccak_384: + sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); + break; + case RealSha3_512: + case Keccak_512: + sha3Update(&d->sha3Context, reinterpret_cast<const BitSequence *>(data), quint64(length) * 8); + break; #endif + } } d->result.clear(); } diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h index ad1de7c756..f76fe2d013 100644 --- a/src/corelib/tools/qcryptographichash.h +++ b/src/corelib/tools/qcryptographichash.h @@ -94,7 +94,7 @@ public: void reset(); - void addData(const char *data, int length); + void addData(const char *data, qsizetype length); void addData(const QByteArray &data); bool addData(QIODevice* device); diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index f98bb051ec..ef363ed52d 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -105,11 +105,7 @@ public: friend class QSet<T>; public: -#if QT_DEPRECATED_SINCE(5, 15) - typedef std::bidirectional_iterator_tag iterator_category; -#else typedef std::forward_iterator_tag iterator_category; -#endif typedef qptrdiff difference_type; typedef T value_type; typedef const T *pointer; @@ -129,15 +125,6 @@ public: { return i != o.i; } inline iterator &operator++() { ++i; return *this; } inline iterator operator++(int) { iterator r = *this; ++i; return r; } -#if QT_DEPRECATED_SINCE(5, 15) - inline QT_DEPRECATED iterator &operator--() { --i; return *this; } - inline QT_DEPRECATED iterator operator--(int) { iterator r = *this; --i; return r; } - inline QT_DEPRECATED iterator operator+(int j) const { return i + j; } - inline QT_DEPRECATED iterator operator-(int j) const { return i - j; } - friend inline QT_DEPRECATED iterator operator+(int j, iterator k) { return k + j; } - inline QT_DEPRECATED iterator &operator+=(int j) { i += j; return *this; } - inline QT_DEPRECATED iterator &operator-=(int j) { i -= j; return *this; } -#endif }; class const_iterator @@ -148,11 +135,7 @@ public: friend class QSet<T>; public: -#if QT_DEPRECATED_SINCE(5, 15) - typedef std::bidirectional_iterator_tag iterator_category; -#else typedef std::forward_iterator_tag iterator_category; -#endif typedef qptrdiff difference_type; typedef T value_type; typedef const T *pointer; @@ -170,15 +153,6 @@ public: inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline const_iterator &operator++() { ++i; return *this; } inline const_iterator operator++(int) { const_iterator r = *this; ++i; return r; } -#if QT_DEPRECATED_SINCE(5, 15) - inline QT_DEPRECATED const_iterator &operator--() { --i; return *this; } - inline QT_DEPRECATED const_iterator operator--(int) { const_iterator r = *this; --i; return r; } - inline QT_DEPRECATED const_iterator operator+(int j) const { return i + j; } - inline QT_DEPRECATED const_iterator operator-(int j) const { return i - j; } - friend inline QT_DEPRECATED const_iterator operator+(int j, const_iterator k) { return k + j; } - inline QT_DEPRECATED const_iterator &operator+=(int j) { i += j; return *this; } - inline QT_DEPRECATED const_iterator &operator-=(int j) { i -= j; return *this; } -#endif }; // STL style @@ -191,23 +165,10 @@ public: inline const_iterator cend() const noexcept { return q_hash.end(); } inline const_iterator constEnd() const noexcept { return q_hash.constEnd(); } -#if QT_DEPRECATED_SINCE(5, 15) - typedef std::reverse_iterator<iterator> reverse_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - - reverse_iterator QT_DEPRECATED rbegin() { return reverse_iterator(end()); } - reverse_iterator QT_DEPRECATED rend() { return reverse_iterator(begin()); } - const_reverse_iterator QT_DEPRECATED rbegin() const noexcept { return const_reverse_iterator(end()); } - const_reverse_iterator QT_DEPRECATED rend() const noexcept { return const_reverse_iterator(begin()); } - const_reverse_iterator QT_DEPRECATED crbegin() const noexcept { return const_reverse_iterator(end()); } - const_reverse_iterator QT_DEPRECATED crend() const noexcept { return const_reverse_iterator(begin()); } -#endif - iterator erase(iterator i) { return erase(m2c(i)); } iterator erase(const_iterator i) { - Q_ASSERT_X(isValidIterator(i), "QSet::erase", "The specified const_iterator argument 'i' is invalid"); return q_hash.erase(reinterpret_cast<typename Hash::const_iterator &>(i)); } @@ -263,15 +224,6 @@ private: static const_iterator m2c(iterator it) noexcept { return const_iterator(typename Hash::const_iterator(it.i.i)); } - - bool isValidIterator(const iterator &i) const - { - return q_hash.isValidIterator(reinterpret_cast<const typename Hash::iterator&>(i)); - } - bool isValidIterator(const const_iterator &i) const noexcept - { - return q_hash.isValidIterator(reinterpret_cast<const typename Hash::const_iterator&>(i)); - } }; #if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606 @@ -415,14 +367,6 @@ public: inline const T &value() const { Q_ASSERT(item_exists()); return *n; } inline bool findNext(const T &t) { while (c->constEnd() != (n = i)) if (*i++ == t) return true; return false; } -#if QT_DEPRECATED_SINCE(5, 15) - inline QT_DEPRECATED bool hasPrevious() const { return c->constBegin() != i; } - inline QT_DEPRECATED const T &previous() { n = --i; return *n; } - inline QT_DEPRECATED const T &peekPrevious() const { iterator p = i; return *--p; } - inline QT_DEPRECATED bool findPrevious(const T &t) - { while (c->constBegin() != i) if (*(n = --i) == t) return true; - n = c->end(); return false; } -#endif }; #endif // QT_NO_JAVA_STYLE_ITERATORS diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 3e98de41f4..2cfcb2e5dc 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -242,10 +242,14 @@ public: void append(const_reference t) { append(const_iterator(std::addressof(t)), const_iterator(std::addressof(t)) + 1); } void append(const_iterator i1, const_iterator i2); - void append(value_type &&t); + void append(rvalue_ref t) { emplaceBack(std::move(t)); } void append(const QVector<T> &l) { append(l.constBegin(), l.constEnd()); } void prepend(rvalue_ref t); void prepend(const T &t); + + template <typename ...Args> + reference emplaceBack(Args&&... args) { return *emplace(count(), std::forward<Args>(args)...); } + iterator insert(int i, parameter_type t) { return insert(i, 1, t); } iterator insert(int i, int n, parameter_type t); @@ -264,7 +268,17 @@ public: Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid"); return insert(std::distance(constBegin(), before), std::move(t)); } - iterator insert(int i, rvalue_ref t); + iterator insert(int i, rvalue_ref t) { return emplace(i, std::move(t)); } + + template <typename ...Args> + iterator emplace(const_iterator before, Args&&... args) + { + Q_ASSERT_X(isValidIterator(before), "QVector::emplace", "The specified iterator argument 'before' is invalid"); + return emplace(std::distance(constBegin(), before), std::forward<Args>(args)...); + } + + template <typename ...Args> + iterator emplace(int i, Args&&... args); #if 0 template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); @@ -388,6 +402,10 @@ public: inline void push_front(const T &t) { prepend(t); } void pop_back() { removeLast(); } void pop_front() { removeFirst(); } + + template <typename ...Args> + reference emplace_back(Args&&... args) { return emplaceBack(std::forward<Args>(args)...); } + inline bool empty() const { return d->size == 0; } inline reference front() { return first(); } @@ -538,27 +556,6 @@ inline void QVector<T>::append(const_iterator i1, const_iterator i2) } template <typename T> -inline void QVector<T>::append(value_type &&t) -{ - const size_t newSize = size() + 1; - const bool isTooSmall = newSize > d->allocatedCapacity(); - const bool isOverlapping = std::addressof(*d->begin()) <= std::addressof(t) - && std::addressof(t) < std::addressof(*d->end()); - if (isTooSmall || d->needsDetach() || Q_UNLIKELY(isOverlapping)) { - typename Data::ArrayOptions flags = d->detachFlags(); - if (isTooSmall) - flags |= Data::GrowsForward; - DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags)); - detached->copyAppend(constBegin(), constEnd()); - detached->moveAppend(std::addressof(t), std::addressof(t) + 1); - d.swap(detached); - } else { - // we're detached and we can just move data around - d->moveAppend(std::addressof(t), std::addressof(t) + 1); - } -} - -template <typename T> inline typename QVector<T>::iterator QVector<T>::insert(int i, int n, parameter_type t) { @@ -592,10 +589,11 @@ QVector<T>::insert(int i, int n, parameter_type t) } template <typename T> +template <typename ...Args> typename QVector<T>::iterator -QVector<T>::insert(int i, rvalue_ref t) +QVector<T>::emplace(int i, Args&&... args) { - Q_ASSERT_X(size_t(i) <= size_t(d->size), "QVector<T>::insert", "index out of range"); + Q_ASSERT_X(i >= 0 && i <= d->size, "QVector<T>::insert", "index out of range"); const size_t newSize = size() + 1; if (d->needsDetach() || newSize > d->allocatedCapacity()) { @@ -605,12 +603,24 @@ QVector<T>::insert(int i, rvalue_ref t) DataPointer detached(Data::allocate(d->detachCapacity(newSize), flags)); const_iterator where = constBegin() + i; + + // First, create an element to handle cases, when a user moves + // the element from a container to the same container + detached->createInPlace(detached.begin() + i, std::forward<Args>(args)...); + + // Then, put the first part of the elements to the new location detached->copyAppend(constBegin(), where); - detached->moveAppend(std::addressof(t), std::addressof(t) + 1); + + // After that, increase the actual size, because we created + // one extra element + ++detached.size; + + // Finally, put the rest of the elements to the new location detached->copyAppend(where, constEnd()); + d.swap(detached); } else { - d->insert(d.begin() + i, std::move(t)); + d->emplace(d.begin() + i, std::forward<Args>(args)...); } return d.begin() + i; } diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc index 116d962411..a5ea4073f8 100644 --- a/src/corelib/tools/qvector.qdoc +++ b/src/corelib/tools/qvector.qdoc @@ -646,6 +646,28 @@ \sa append(), insert() */ +/*! + \fn template <typename T> template <typename ...Args> T &QVector<T>::emplaceBack(Args&&... args) + \fn template <typename T> template <typename ...Args> T &QVector<T>::emplace_back(Args&&... args) + + Adds a new element to the end for the container. This new element + is constructed in-place using \a args as the arguments for its + construction. + + Returns a reference to the new element. + + Example: + \snippet code/src_corelib_tools_qvector.cpp emplace-back + + It is also possible to access a newly created object by using + returned reference: + \snippet code/src_corelib_tools_qvector.cpp emplace-back-ref + + This is the same as vector.emplace(vector.size(), \a args). + + \sa emplace +*/ + /*! \fn template <typename T> void QVector<T>::insert(int i, const T &value) \fn template <typename T> void QVector<T>::insert(int i, T &&value) @@ -693,6 +715,26 @@ first of the inserted items. */ +/*! + \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(int i, Args&&... args) + + Extends the container by inserting a new element at position \a i. + This new element is constructed in-place using \a args as the + arguments for its construction. + + Returns an iterator to the new element. + + Example: + \snippet code/src_corelib_tools_qvector.cpp emplace + + \note It is garanteed that the element will be created in place + at the beginning, but after that it might be copied or + moved to the right position. + + \sa emplaceBack +*/ + + /*! \fn template <typename T> void QVector<T>::replace(int i, const T &value) Replaces the item at index position \a i with \a value. @@ -838,6 +880,17 @@ \sa takeFirst(), removeLast() */ +/*! + \fn template <typename T> template <typename ...Args> QVector<T>::iterator QVector<T>::emplace(QVector<T>::iterator before, Args&&... args) + + \overload + + Creates a new element in front of the item pointed to by the + iterator \a before. This new element is constructed in-place + using \a args as the arguments for its construction. + + Returns an iterator to the new element. +*/ /*! \fn template <typename T> QVector<T> &QVector<T>::fill(const T &value, int size = -1) diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp index 58e3c15560..0883896751 100644 --- a/src/corelib/tools/qversionnumber.cpp +++ b/src/corelib/tools/qversionnumber.cpp @@ -556,5 +556,199 @@ uint qHash(const QVersionNumber &key, uint seed) return seed; } -QT_END_NAMESPACE +/*! + \class QTypeRevision + \inmodule QtCore + \since 6.0 + \brief The QTypeRevision class contains a lightweight representation of + a version number with two 8-bit segments, major and minor, either + of which can be unknown. + + Use this class to describe revisions of a type. Compatible revisions can be + expressed as increments of the minor version. Breaking changes can be + expressed as increments of the major version. The return values of + \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to + \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions + specify in which Qt versions the properties and methods were added. + + \sa QMetaMethod::revision(), QMetaProperty::revision() +*/ + +/*! + \fn template<typename Integer> static bool QTypeRevision::isValidSegment(Integer segment) + + Returns true if the given number can be used as either major or minor + version in a QTypeRevision. Valid segments need to be \c {>= 0} and \c {< 255}. +*/ + +/*! + \fn QTypeRevision::QTypeRevision() + + Produces an invalid revision. + + \sa isValid() +*/ + +/*! + \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion) + + Produces a QTypeRevision from the given \a majorVersion and \a minorVersion, + both of which need to be a valid segments. + + \sa isValidSegment() +*/ + +/*! + \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion) + + Produces a QTypeRevision from the given \a majorVersion with an invalid minor + version. \a majorVersion needs to be a valid segment. + + \sa isValidSegment() +*/ + +/*! + \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion) + + Produces a QTypeRevision from the given \a minorVersion with an invalid major + version. \a minorVersion needs to be a valid segment. + + \sa isValidSegment() +*/ + +/*! + \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value) + + Produces a QTypeRevision from the given \a value. \a value encodes both the + minor and major versions in the least significant and second least + significant byte, respectively. + + \a value must not have any bits outside the least significant two bytes set. + \c Integer needs to be at least 16 bits wide, and must not have a sign bit + in the least significant 16 bits. + + \sa toEncodedVersion() +*/ + +/*! + \fn static QTypeRevision QTypeRevision::zero() + + Produces a QTypeRevision with major and minor version \c{0}. +*/ + +/*! + \fn bool QTypeRevision::hasMajorVersion() const + + Returns true if the major version is known, otherwise false. + + \sa majorVersion(), hasMinorVersion() +*/ + +/*! + \fn quint8 QTypeRevision::majorVersion() const + + Returns the major version encoded in the revision. + + \sa hasMajorVersion(), minorVersion() +*/ + +/*! + \fn bool QTypeRevision::hasMinorVersion() const + + Returns true if the minor version is known, otherwise false. + + \sa minorVersion(), hasMajorVersion() +*/ +/*! + \fn quint8 QTypeRevision::minorVersion() const + + Returns the minor version encoded in the revision. + + \sa hasMinorVersion(), majorVersion() +*/ + +/*! + \fn bool QTypeRevision::isValid() const + + Returns true if the major version or the minor version is known, + otherwise false. + + \sa hasMajorVersion(), hasMinorVersion() +*/ + +/*! + \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const + + Transforms the revision into an integer value, encoding the minor + version into the least significant byte, and the major version into + the second least significant byte. + + \c Integer needs to be at least 16 bits wide, and must not have a sign bit + in the least significant 16 bits. + + \sa fromEncodedVersion() +*/ + +#ifndef QT_NO_DATASTREAM +/*! + \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision) + \relates QTypeRevision + \since 6.0 + + Writes the revision \a revision to stream \a out. + */ +QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision) +{ + return out << revision.toEncodedVersion<quint16>(); +} + +/*! + \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision) + \relates QTypeRevision + \since 6.0 + + Reads a revision from stream \a in and stores it in \a revision. + */ +QDataStream& operator>>(QDataStream &in, QTypeRevision &revision) +{ + quint16 value; + in >> value; + revision = QTypeRevision::fromEncodedVersion(value); + return in; +} +#endif + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QTypeRevision &revision) +{ + QDebugStateSaver saver(debug); + if (revision.hasMajorVersion()) { + if (revision.hasMinorVersion()) + debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion(); + else + debug.nospace().noquote() << revision.majorVersion() << ".x"; + } else { + if (revision.hasMinorVersion()) + debug << revision.minorVersion(); + else + debug.noquote() << "invalid"; + } + return debug; +} +#endif + +/*! + \fn uint qHash(const QTypeRevision &key, uint seed) + \relates QHash + \since 6.0 + + Returns the hash value for the \a key, using \a seed to seed the + calculation. +*/ +uint qHash(const QTypeRevision &key, uint seed) +{ + return qHash(key.toEncodedVersion<quint16>(), seed); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h index d43b86ba51..03a27548b8 100644 --- a/src/corelib/tools/qversionnumber.h +++ b/src/corelib/tools/qversionnumber.h @@ -309,8 +309,159 @@ Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersi Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) noexcept { return QVersionNumber::compare(lhs, rhs) != 0; } +class QTypeRevision; +Q_CORE_EXPORT uint qHash(const QTypeRevision &key, uint seed = 0); + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision); +Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QTypeRevision &revision); +#endif + +class QTypeRevision +{ +public: + template<typename Integer> + using if_valid_segment_type = typename std::enable_if< + std::is_integral<Integer>::value, bool>::type; + + template<typename Integer> + using if_valid_value_type = typename std::enable_if< + std::is_integral<Integer>::value + && (sizeof(Integer) > sizeof(quint16) + || (sizeof(Integer) == sizeof(quint16) + && !std::is_signed<Integer>::value)), bool>::type; + + template<typename Integer, if_valid_segment_type<Integer> = true> + static constexpr bool isValidSegment(Integer segment) + { + return segment >= Integer(0) && segment < Integer(SegmentUnknown); + } + + static constexpr bool isValidSegment(qint8 segment) { return segment >= 0; } + + template<typename Major, typename Minor, + if_valid_segment_type<Major> = true, + if_valid_segment_type<Minor> = true> + static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion) + { + return Q_ASSERT(isValidSegment(majorVersion)), + Q_ASSERT(isValidSegment(minorVersion)), + QTypeRevision(quint8(majorVersion), quint8(minorVersion)); + } + + template<typename Major, if_valid_segment_type<Major> = true> + static constexpr QTypeRevision fromMajorVersion(Major majorVersion) + { + return Q_ASSERT(isValidSegment(majorVersion)), + QTypeRevision(quint8(majorVersion), SegmentUnknown); + } + + template<typename Minor, if_valid_segment_type<Minor> = true> + static constexpr QTypeRevision fromMinorVersion(Minor minorVersion) + { + return Q_ASSERT(isValidSegment(minorVersion)), + QTypeRevision(SegmentUnknown, quint8(minorVersion)); + } + + template<typename Integer, if_valid_value_type<Integer> = true> + static constexpr QTypeRevision fromEncodedVersion(Integer value) + { + return Q_ASSERT((value & ~Integer(0xffff)) == Integer(0)), + QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff)); + } + + static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); } + + constexpr QTypeRevision() = default; + + constexpr bool hasMajorVersion() const { return m_majorVersion != SegmentUnknown; } + constexpr quint8 majorVersion() const { return m_majorVersion; } + + constexpr bool hasMinorVersion() const { return m_minorVersion != SegmentUnknown; } + constexpr quint8 minorVersion() const { return m_minorVersion; } + + constexpr bool isValid() const { return hasMajorVersion() || hasMinorVersion(); } + + template<typename Integer, if_valid_value_type<Integer> = true> + constexpr Integer toEncodedVersion() const + { + return Integer(m_majorVersion << 8) | Integer(m_minorVersion); + } + +private: + enum { SegmentUnknown = quint8(~0U) }; + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + constexpr QTypeRevision(quint8 major, quint8 minor) + : m_minorVersion(minor), m_majorVersion(major) {} + + quint8 m_minorVersion = SegmentUnknown; + quint8 m_majorVersion = SegmentUnknown; +#else + constexpr QTypeRevision(quint8 major, quint8 minor) + : m_majorVersion(major), m_minorVersion(minor) {} + + quint8 m_majorVersion = SegmentUnknown; + quint8 m_minorVersion = SegmentUnknown; +#endif +}; + +inline constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs) +{ + return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>(); +} + +inline constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs) +{ + return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>(); +} + +inline constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs) +{ + return (!lhs.hasMajorVersion() && rhs.hasMajorVersion()) + // non-0 major > unspecified major > major 0 + ? rhs.majorVersion() != 0 + : ((lhs.hasMajorVersion() && !rhs.hasMajorVersion()) + // major 0 < unspecified major < non-0 major + ? lhs.majorVersion() == 0 + : (lhs.majorVersion() != rhs.majorVersion() + // both majors specified and non-0 + ? lhs.majorVersion() < rhs.majorVersion() + : ((!lhs.hasMinorVersion() && rhs.hasMinorVersion()) + // non-0 minor > unspecified minor > minor 0 + ? rhs.minorVersion() != 0 + : ((lhs.hasMinorVersion() && !rhs.hasMinorVersion()) + // minor 0 < unspecified minor < non-0 minor + ? lhs.minorVersion() == 0 + // both minors specified and non-0 + : lhs.minorVersion() < rhs.minorVersion())))); +} + +inline constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs) +{ + return lhs != rhs && !(lhs < rhs); +} + +inline constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs) +{ + return lhs == rhs || lhs < rhs; +} + +inline constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs) +{ + return lhs == rhs || !(lhs < rhs); +} + +Q_STATIC_ASSERT(sizeof(QTypeRevision) == 2); +Q_DECLARE_TYPEINFO(QTypeRevision, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision); +#endif + QT_END_NAMESPACE Q_DECLARE_METATYPE(QVersionNumber) +Q_DECLARE_METATYPE(QTypeRevision) #endif //QVERSIONNUMBER_H |