Remove QHashDummyNode and avoid undifined behavior
A lot of code in QHash is doing casting to QHashNode while the pointer may be of type QHashDummyNode. This is a lot of undefined behavior. Remove QHashDummyNode and specialize QHashNode for QHashDummyValue instead. QHashDummyValue is the only type for which QTypeInfo::isDummy is true. Q_DUMMY and QTypeInfo::isDummy are internal API, so is QHashDummyNode, so we can remove them. Task-number: QTBUG-40029 Change-Id: I60c2ff0933075b9202bde89a9992746052f75133 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
84e189502a
commit
813af5f065
@ -64,7 +64,7 @@ public:
|
||||
isComplex = true,
|
||||
isStatic = true,
|
||||
isLarge = (sizeof(T)>sizeof(void*)),
|
||||
isDummy = false,
|
||||
isDummy = false, //### Qt6: remove
|
||||
sizeOf = sizeof(T)
|
||||
};
|
||||
};
|
||||
|
@ -217,17 +217,23 @@ private:
|
||||
Q_DISABLE_COPY(QHashNode)
|
||||
};
|
||||
|
||||
template <class Key, class T>
|
||||
struct QHashDummyNode
|
||||
// Specialize for QHashDummyValue in order to save some memory
|
||||
template <class Key>
|
||||
struct QHashNode<Key, QHashDummyValue>
|
||||
{
|
||||
QHashNode<Key, T> *next;
|
||||
union {
|
||||
QHashNode *next;
|
||||
QHashDummyValue value;
|
||||
};
|
||||
const uint h;
|
||||
const Key key;
|
||||
|
||||
inline QHashDummyNode(const Key &key0, uint hash, QHashNode<Key, T> *n) : next(n), h(hash), key(key0) {}
|
||||
inline QHashNode(const Key &key0, const QHashDummyValue &, uint hash, QHashNode *n)
|
||||
: next(n), h(hash), key(key0) {}
|
||||
inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; }
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QHashDummyNode)
|
||||
Q_DISABLE_COPY(QHashNode)
|
||||
};
|
||||
|
||||
|
||||
@ -276,7 +282,6 @@ Q_HASH_DECLARE_INT_NODES(uint);
|
||||
template <class Key, class T>
|
||||
class QHash
|
||||
{
|
||||
typedef QHashDummyNode<Key, T> DummyNode;
|
||||
typedef QHashNode<Key, T> Node;
|
||||
|
||||
union {
|
||||
@ -289,7 +294,6 @@ class QHash
|
||||
}
|
||||
|
||||
static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
|
||||
static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); }
|
||||
|
||||
public:
|
||||
inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
|
||||
@ -554,25 +558,14 @@ template <class Key, class T>
|
||||
Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
|
||||
{
|
||||
Node *concreteNode = concrete(node);
|
||||
if (QTypeInfo<T>::isDummy) {
|
||||
(void) new (newNode) DummyNode(concreteNode->key, concreteNode->h, 0);
|
||||
} else {
|
||||
(void) new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, 0);
|
||||
}
|
||||
new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, 0);
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
|
||||
QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
|
||||
{
|
||||
Node *node;
|
||||
|
||||
if (QTypeInfo<T>::isDummy) {
|
||||
node = reinterpret_cast<Node *>(new (d->allocateNode(alignOfDummyNode())) DummyNode(akey, ah, *anextNode));
|
||||
} else {
|
||||
node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode);
|
||||
}
|
||||
|
||||
Node *node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode);
|
||||
*anextNode = node;
|
||||
++d->size;
|
||||
return node;
|
||||
@ -605,9 +598,7 @@ Q_INLINE_TEMPLATE void QHash<Key, T>::clear()
|
||||
template <class Key, class T>
|
||||
Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
|
||||
{
|
||||
QHashData *x = d->detach_helper(duplicateNode, deleteNode2,
|
||||
QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node),
|
||||
QTypeInfo<T>::isDummy ? alignOfDummyNode() : alignOfNode());
|
||||
QHashData *x = d->detach_helper(duplicateNode, deleteNode2, sizeof(Node), alignOfNode());
|
||||
if (!d->ref.deref())
|
||||
freeData(d);
|
||||
d = x;
|
||||
@ -789,7 +780,7 @@ Q_INLINE_TEMPLATE typename QHash<Key, T>::iterator QHash<Key, T>::insert(const K
|
||||
return iterator(createNode(h, akey, avalue, node));
|
||||
}
|
||||
|
||||
if (!QTypeInfo<T>::isDummy)
|
||||
if (!QtPrivate::is_same<T, QHashDummyValue>::value)
|
||||
(*node)->value = avalue;
|
||||
return iterator(*node);
|
||||
}
|
||||
@ -958,7 +949,7 @@ Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash<Key, T> &other)
|
||||
do {
|
||||
if (it2 == other.end() || !(it2.key() == akey))
|
||||
return false;
|
||||
if (!QTypeInfo<T>::isDummy && !(it.value() == it2.value()))
|
||||
if (!(it.value() == it2.value()))
|
||||
return false;
|
||||
++it;
|
||||
++it2;
|
||||
|
Loading…
Reference in New Issue
Block a user