QProperty: fix QBindingStoragePrivate::reallocate related code
In the internal hash map implementation, we have to ensure that the index is in the interval [0, size - 1]. Moreover, in setBinding we have to refetch the binding storage in case a reallocation happened. Change-Id: I11c6264f16537699c8908b647e2355a39ce87648 Reviewed-by: Lars Knoll <lars.knoll@qt.io>bb10
parent
7a41b928d4
commit
6b4e0c5803
|
|
@ -1388,7 +1388,8 @@ struct QBindingStoragePrivate
|
|||
for (size_t i = 0; i < d->size; ++i, ++p) {
|
||||
if (p->data) {
|
||||
Pair *pp = pairs(newData);
|
||||
size_t index = qHash(p->data);
|
||||
Q_ASSERT(newData->size && (newData->size & (newData->size - 1)) == 0); // size is a power of two
|
||||
size_t index = qHash(p->data) & (newData->size - 1);
|
||||
while (pp[index].data) {
|
||||
++index;
|
||||
if (index == newData->size)
|
||||
|
|
|
|||
|
|
@ -397,6 +397,9 @@ public:
|
|||
{
|
||||
QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true);
|
||||
QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, nullptr, bindingWrapper));
|
||||
// refetch the binding data, as the eager evaluation in setBinding() above could cause a reallocation
|
||||
// in the binding storage
|
||||
bd = qGetBindingStorage(owner())->bindingData(this);
|
||||
notify(bd);
|
||||
return static_cast<QPropertyBinding<T> &>(oldBinding);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ private slots:
|
|||
void bindingSourceLocation();
|
||||
void bindingError();
|
||||
void bindingLoop();
|
||||
void realloc();
|
||||
void changePropertyFromWithinChangeHandler();
|
||||
void changePropertyFromWithinChangeHandlerThroughDependency();
|
||||
void changePropertyFromWithinChangeHandler2();
|
||||
|
|
@ -567,6 +568,41 @@ void tst_QProperty::bindingLoop()
|
|||
QCOMPARE(tester.bindableEagerProp2().binding().error().type(), QPropertyBindingError::BindingLoop);
|
||||
}
|
||||
|
||||
class ReallocTester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int prop1 READ prop1 WRITE setProp1 BINDABLE bindableProp1)
|
||||
Q_PROPERTY(int prop2 READ prop2 WRITE setProp2 BINDABLE bindableProp2)
|
||||
Q_PROPERTY(int prop3 READ prop3 WRITE setProp3 BINDABLE bindableProp3)
|
||||
Q_PROPERTY(int prop4 READ prop4 WRITE setProp4 BINDABLE bindableProp4)
|
||||
Q_PROPERTY(int prop5 READ prop5 WRITE setProp5 BINDABLE bindableProp5)
|
||||
public:
|
||||
ReallocTester(QObject *parent = nullptr) : QObject(parent) {}
|
||||
|
||||
|
||||
#define GEN(N) \
|
||||
int prop##N() {return propData##N.value();} \
|
||||
void setProp##N(int i) { propData##N = i; } \
|
||||
QBindable<int> bindableProp##N() {return QBindable<int>(&propData##N);} \
|
||||
Q_OBJECT_COMPAT_PROPERTY(ReallocTester, int, propData##N, &ReallocTester::setProp##N)
|
||||
GEN(1)
|
||||
GEN(2)
|
||||
GEN(3)
|
||||
GEN(4)
|
||||
GEN(5)
|
||||
#undef GEN
|
||||
};
|
||||
|
||||
void tst_QProperty::realloc()
|
||||
{
|
||||
ReallocTester tester;
|
||||
tester.bindableProp1().setBinding([&](){return tester.prop5();});
|
||||
tester.bindableProp2().setBinding([&](){return tester.prop5();});
|
||||
tester.bindableProp3().setBinding([&](){return tester.prop5();});
|
||||
tester.bindableProp4().setBinding([&](){return tester.prop5();});
|
||||
tester.bindableProp5().setBinding([&]() -> int{return 42;});
|
||||
};
|
||||
|
||||
void tst_QProperty::changePropertyFromWithinChangeHandler()
|
||||
{
|
||||
QProperty<int> property(100);
|
||||
|
|
|
|||
Loading…
Reference in New Issue