From f75160774abfcdfc2fb17f382fe2a6b28ba181a5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 5 Feb 2020 14:47:26 +0100 Subject: Cleanup code in QContiguousCache Remove the union being used to hold the d-pointer, as accessing both members of the union on the same data is technically undefined behavior. Change-Id: Ia5a063d97538222575a47e9462c0675acdf32aef Reviewed-by: Sona Kurazyan Reviewed-by: Thiago Macieira --- src/corelib/tools/qcontiguouscache.h | 168 +++++++++++++++-------------------- 1 file changed, 74 insertions(+), 94 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 451ba3e8de..fb487b60a1 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -57,11 +57,6 @@ struct Q_CORE_EXPORT QContiguousCacheData int start; int offset; - // total is 24 bytes (HP-UX aCC: 40 bytes) - // the next entry is already aligned to 8 bytes - // there will be an 8 byte gap here if T requires 16-byte alignment - // (such as long double on 64-bit platforms, __int128, __float128) - static QContiguousCacheData *allocateData(int size, int alignment); static void freeData(QContiguousCacheData *data); @@ -71,18 +66,15 @@ struct Q_CORE_EXPORT QContiguousCacheData }; template -struct QContiguousCacheTypedData: private QContiguousCacheData +struct QContiguousCacheTypedData : public QContiguousCacheData { - // private inheritance to avoid aliasing warningss T array[1]; - - static inline void freeData(QContiguousCacheTypedData *data) { QContiguousCacheData::freeData(data); } }; template class QContiguousCache { typedef QContiguousCacheTypedData Data; - union { QContiguousCacheData *d; QContiguousCacheTypedData *p; }; + Data *d; public: // STL compatibility typedef T value_type; @@ -96,7 +88,7 @@ public: explicit QContiguousCache(int capacity = 0); QContiguousCache(const QContiguousCache &v) : d(v.d) { d->ref.ref(); } - inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(p); } + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) freeData(d); } inline void detach() { if (d->ref.loadRelaxed() != 1) detach_helper(); } inline bool isDetached() const { return d->ref.loadRelaxed() == 1; } @@ -131,10 +123,10 @@ public: inline int firstIndex() const { return d->offset; } inline int lastIndex() const { return d->offset + d->count - 1; } - inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; } - inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; } - inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; } - inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; } + inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; } void removeFirst(); T takeFirst(); @@ -147,39 +139,28 @@ public: inline void normalizeIndexes() { d->offset = d->start; } #ifdef QT_QCONTIGUOUSCACHE_DEBUG - void dump() const { p->dump(); } + void dump() const { d->dump(); } #endif private: void detach_helper(); - QContiguousCacheData *allocateData(int aalloc); + Data *allocateData(int aalloc); void freeData(Data *x); - int sizeOfTypedData() { - // this is more or less the same as sizeof(Data), except that it doesn't - // count the padding at the end - return reinterpret_cast(&(reinterpret_cast(this))->array[1]) - reinterpret_cast(this); - } - int alignOfTypedData() const - { - return qMax(sizeof(void*), alignof(Data)); - } }; template void QContiguousCache::detach_helper() { - union { QContiguousCacheData *d; QContiguousCacheTypedData *p; } x; - - x.d = allocateData(d->alloc); - x.d->ref.storeRelaxed(1); - x.d->count = d->count; - x.d->start = d->start; - x.d->offset = d->offset; - x.d->alloc = d->alloc; - - T *dest = x.p->array + x.d->start; - T *src = p->array + d->start; - int oldcount = x.d->count; + Data *x = allocateData(d->alloc); + x->ref.storeRelaxed(1); + x->count = d->count; + x->start = d->start; + x->offset = d->offset; + x->alloc = d->alloc; + + T *dest = x->array + x->start; + T *src = d->array + d->start; + int oldcount = x->count; while (oldcount--) { if (QTypeInfo::isComplex) { new (dest) T(*src); @@ -187,16 +168,16 @@ void QContiguousCache::detach_helper() *dest = *src; } dest++; - if (dest == x.p->array + x.d->alloc) - dest = x.p->array; + if (dest == x->array + x->alloc) + dest = x->array; src++; - if (src == p->array + d->alloc) - src = p->array; + if (src == d->array + d->alloc) + src = d->array; } if (!d->ref.deref()) - freeData(p); - d = x.d; + freeData(d); + d = x; } template @@ -206,39 +187,38 @@ void QContiguousCache::setCapacity(int asize) if (asize == d->alloc) return; detach(); - union { QContiguousCacheData *d; QContiguousCacheTypedData *p; } x; - x.d = allocateData(asize); - x.d->ref.storeRelaxed(1); - x.d->alloc = asize; - x.d->count = qMin(d->count, asize); - x.d->offset = d->offset + d->count - x.d->count; + Data *x = allocateData(asize); + x->ref.storeRelaxed(1); + x->alloc = asize; + x->count = qMin(d->count, asize); + x->offset = d->offset + d->count - x->count; if(asize) - x.d->start = x.d->offset % x.d->alloc; + x->start = x->offset % x->alloc; else - x.d->start = 0; + x->start = 0; - int oldcount = x.d->count; + int oldcount = x->count; if(oldcount) { - T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc; - T *src = p->array + (d->start + d->count-1) % d->alloc; + T *dest = x->array + (x->start + x->count-1) % x->alloc; + T *src = d->array + (d->start + d->count-1) % d->alloc; while (oldcount--) { if (QTypeInfo::isComplex) { new (dest) T(*src); } else { *dest = *src; } - if (dest == x.p->array) - dest = x.p->array + x.d->alloc; + if (dest == x->array) + dest = x->array + x->alloc; dest--; - if (src == p->array) - src = p->array + d->alloc; + if (src == d->array) + src = d->array + d->alloc; src--; } } /* free old */ - freeData(p); - d = x.d; + freeData(d); + d = x; } template @@ -247,31 +227,31 @@ void QContiguousCache::clear() if (d->ref.loadRelaxed() == 1) { if (QTypeInfo::isComplex) { int oldcount = d->count; - T * i = p->array + d->start; - T * e = p->array + d->alloc; + T * i = d->array + d->start; + T * e = d->array + d->alloc; while (oldcount--) { i->~T(); i++; if (i == e) - i = p->array; + i = d->array; } } d->count = d->start = d->offset = 0; } else { - union { QContiguousCacheData *d; QContiguousCacheTypedData *p; } x; - x.d = allocateData(d->alloc); - x.d->ref.storeRelaxed(1); - x.d->alloc = d->alloc; - x.d->count = x.d->start = x.d->offset = 0; - if (!d->ref.deref()) freeData(p); - d = x.d; + Data *x = allocateData(d->alloc); + x->ref.storeRelaxed(1); + x->alloc = d->alloc; + x->count = x->start = x->offset = 0; + if (!d->ref.deref()) + freeData(d); + d = x; } } template -inline QContiguousCacheData *QContiguousCache::allocateData(int aalloc) +inline typename QContiguousCache::Data *QContiguousCache::allocateData(int aalloc) { - return QContiguousCacheData::allocateData(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); + return static_cast(QContiguousCacheData::allocateData(sizeof(Data) + (aalloc - 1) * sizeof(T), alignof(Data))); } template @@ -289,7 +269,7 @@ QContiguousCache &QContiguousCache::operator=(const QContiguousCache &o { other.d->ref.ref(); if (!d->ref.deref()) - freeData(p); + freeData(d); d = other.d; return *this; } @@ -315,16 +295,16 @@ void QContiguousCache::freeData(Data *x) { if (QTypeInfo::isComplex) { int oldcount = d->count; - T * i = p->array + d->start; - T * e = p->array + d->alloc; + T * i = d->array + d->start; + T * e = d->array + d->alloc; while (oldcount--) { i->~T(); i++; if (i == e) - i = p->array; + i = d->array; } } - x->freeData(x); + Data::freeData(x); } template void QContiguousCache::append(const T &value) @@ -334,10 +314,10 @@ void QContiguousCache::append(const T &value) detach(); if (QTypeInfo::isComplex) { if (d->count == d->alloc) - (p->array + (d->start+d->count) % d->alloc)->~T(); - new (p->array + (d->start+d->count) % d->alloc) T(value); + (d->array + (d->start+d->count) % d->alloc)->~T(); + new (d->array + (d->start+d->count) % d->alloc) T(value); } else { - p->array[(d->start+d->count) % d->alloc] = value; + d->array[(d->start+d->count) % d->alloc] = value; } if (d->count == d->alloc) { @@ -365,12 +345,12 @@ void QContiguousCache::prepend(const T &value) d->count++; else if (d->count == d->alloc) - (p->array + d->start)->~T(); + (d->array + d->start)->~T(); if (QTypeInfo::isComplex) - new (p->array + d->start) T(value); + new (d->array + d->start) T(value); else - p->array[d->start] = value; + d->array[d->start] = value; } template @@ -382,10 +362,10 @@ void QContiguousCache::insert(int pos, const T &value) detach(); if (containsIndex(pos)) { if (QTypeInfo::isComplex) { - (p->array + pos % d->alloc)->~T(); - new (p->array + pos % d->alloc) T(value); + (d->array + pos % d->alloc)->~T(); + new (d->array + pos % d->alloc) T(value); } else { - p->array[pos % d->alloc] = value; + d->array[pos % d->alloc] = value; } } else if (pos == d->offset-1) prepend(value); @@ -398,18 +378,18 @@ void QContiguousCache::insert(int pos, const T &value) d->start = pos % d->alloc; d->count = 1; if (QTypeInfo::isComplex) - new (p->array + d->start) T(value); + new (d->array + d->start) T(value); else - p->array[d->start] = value; + d->array[d->start] = value; } } template inline const T &QContiguousCache::at(int pos) const -{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache::at", "index out of range"); return p->array[pos % d->alloc]; } +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache::at", "index out of range"); return d->array[pos % d->alloc]; } template inline const T &QContiguousCache::operator[](int pos) const -{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache::at", "index out of range"); return p->array[pos % d->alloc]; } +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache::at", "index out of range"); return d->array[pos % d->alloc]; } template inline T &QContiguousCache::operator[](int pos) @@ -417,7 +397,7 @@ inline T &QContiguousCache::operator[](int pos) detach(); if (!containsIndex(pos)) insert(pos, T()); - return p->array[pos % d->alloc]; + return d->array[pos % d->alloc]; } template @@ -427,7 +407,7 @@ inline void QContiguousCache::removeFirst() detach(); d->count--; if (QTypeInfo::isComplex) - (p->array + d->start)->~T(); + (d->array + d->start)->~T(); d->start = (d->start + 1) % d->alloc; d->offset++; } @@ -439,7 +419,7 @@ inline void QContiguousCache::removeLast() detach(); d->count--; if (QTypeInfo::isComplex) - (p->array + (d->start + d->count) % d->alloc)->~T(); + (d->array + (d->start + d->count) % d->alloc)->~T(); } template -- cgit v1.2.3