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/qvector.h | 64 | ||||
-rw-r--r-- | src/corelib/tools/qvector.qdoc | 53 |
6 files changed, 183 insertions, 104 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/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) |