summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qarraydataops.h58
-rw-r--r--src/corelib/tools/qcontiguouscache.h10
-rw-r--r--src/corelib/tools/qcryptographichash.cpp100
-rw-r--r--src/corelib/tools/qcryptographichash.h2
-rw-r--r--src/corelib/tools/qvector.h64
-rw-r--r--src/corelib/tools/qvector.qdoc53
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)