summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qproperty.cpp
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-10-16 18:03:28 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2020-11-03 13:06:14 +0100
commitc1c991c3190ec3e9ba5fae9c5ae40385686d289d (patch)
tree466ef8af8fe0ef6f6336b1cf503f67d6ede6f633 /src/corelib/kernel/qproperty.cpp
parenta95ddcf97bcb3c5a6727fcaf6b3b74c05051ac4f (diff)
Remove std::function from QProperty interface
std::function as a type is rather unfortunate for us, as its SSO buffer makes it rather large, and we can ensure that the function is never empty. Considering that we do need to allocate memory for QPropertyBindingPrivate anyway, we can get rid of the SSO buffer and instead coalesce the allocations (similar to how std::make_shared works). The memory looks then like [--QPropertyBindingPrivate--][Functor] and QPropertyBindingPrivate can get a pointer to the functor via reinterpret_cast<std::byte>(this)+sizeof(QPropertyBindingPrivate). To actually do anything with the functor, we do however need a "vtable" which describes how we can call, destroy and move the functor. This is done by creating a constexpr struct of function pointers, and storing a pointer to it in QPropertyBindingPrivate. As a consequence of those changes, we cannot use QESDP anymore, as we now have to carefully deallocate the buffer we used for both the QPropertyBindingPrivate and the functor. We introduce a custom refcounting pointer for that. While we're at it, we make the refcount non-atomic, as bindings do not work across threads to begin with. Moreover, we can now make the class non-virtual, as that was only needed to hack around limitations of QESDP in the context of exported symbols. Change-Id: Idc5507e4c120e28df5bd5aea717fe69f15e540dc Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/kernel/qproperty.cpp')
-rw-r--r--src/corelib/kernel/qproperty.cpp65
1 files changed, 44 insertions, 21 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index b55069d1ae..103c3d8482 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -47,6 +47,24 @@ QT_BEGIN_NAMESPACE
using namespace QtPrivate;
+QPropertyBindingPrivatePtr::~QPropertyBindingPrivatePtr()
+{
+ if (d && (--d->ref == 0))
+ QPropertyBindingPrivate::destroyAndFreeMemory(static_cast<QPropertyBindingPrivate *>(d));
+}
+
+void QPropertyBindingPrivatePtr::reset(QtPrivate::RefCounted *ptr) noexcept
+{
+ if (ptr != d) {
+ if (ptr)
+ ptr->ref++;
+ auto *old = qExchange(d, ptr);
+ if (old && (--old->ref == 0))
+ QPropertyBindingPrivate::destroyAndFreeMemory(static_cast<QPropertyBindingPrivate *>(d));
+ }
+}
+
+
void QPropertyBindingDataPointer::addObserver(QPropertyObserver *observer)
{
if (auto *binding = bindingPtr()) {
@@ -69,13 +87,15 @@ QPropertyBindingPrivate::~QPropertyBindingPrivate()
{
if (firstObserver)
firstObserver.unlink();
+ if (vtable->size)
+ vtable->destroy(reinterpret_cast<std::byte *>(this) + sizeof(QPropertyBindingPrivate));
}
void QPropertyBindingPrivate::unlinkAndDeref()
{
propertyDataPtr = nullptr;
- if (!ref.deref())
- delete this;
+ if (--ref == 0)
+ destroyAndFreeMemory(this);
}
void QPropertyBindingPrivate::markDirtyAndNotifyObservers()
@@ -129,9 +149,9 @@ bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged(const Q
QUntypedPropertyData *mutable_data = const_cast<QUntypedPropertyData *>(data);
if (hasBindingWrapper) {
- changed = staticBindingWrapper(metaType, mutable_data, evaluationFunction);
+ changed = staticBindingWrapper(metaType, mutable_data, {vtable, reinterpret_cast<std::byte *>(this)+QPropertyBindingPrivate::getSizeEnsuringAlignment()});
} else {
- changed = evaluationFunction(metaType, mutable_data);
+ changed = vtable->call(metaType, mutable_data, reinterpret_cast<std::byte *>(this)+ QPropertyBindingPrivate::getSizeEnsuringAlignment());
}
dirty = false;
@@ -140,10 +160,12 @@ bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged(const Q
QUntypedPropertyBinding::QUntypedPropertyBinding() = default;
-QUntypedPropertyBinding::QUntypedPropertyBinding(QMetaType metaType, QUntypedPropertyBinding::BindingEvaluationFunction function,
+QUntypedPropertyBinding::QUntypedPropertyBinding(QMetaType metaType, const BindingFunctionVTable *vtable, void *function,
const QPropertyBindingSourceLocation &location)
- : d(new QPropertyBindingPrivate(metaType, std::move(function), std::move(location)))
{
+ std::byte *mem = new std::byte[QPropertyBindingPrivate::getSizeEnsuringAlignment() + vtable->size]();
+ d = new(mem) QPropertyBindingPrivate(metaType, vtable, std::move(location));
+ vtable->moveConstruct(mem+sizeof(QPropertyBindingPrivate), function);
}
QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other)
@@ -186,14 +208,14 @@ QPropertyBindingError QUntypedPropertyBinding::error() const
{
if (!d)
return QPropertyBindingError();
- return d->bindingError();
+ return static_cast<QPropertyBindingPrivate *>(d.get())->bindingError();
}
QMetaType QUntypedPropertyBinding::valueMetaType() const
{
if (!d)
return QMetaType();
- return d->valueMetaType();
+ return static_cast<QPropertyBindingPrivate *>(d.get())->valueMetaType();
}
QPropertyBindingData::~QPropertyBindingData()
@@ -221,28 +243,29 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB
if (auto *existingBinding = d.bindingPtr()) {
if (existingBinding == newBinding.data())
- return QUntypedPropertyBinding(oldBinding.data());
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
oldBinding = QPropertyBindingPrivatePtr(existingBinding);
- observer = oldBinding->takeObservers();
- oldBinding->unlinkAndDeref();
+ observer = static_cast<QPropertyBindingPrivate *>(oldBinding.data())->takeObservers();
+ static_cast<QPropertyBindingPrivate *>(oldBinding.data())->unlinkAndDeref();
d_ptr &= FlagMask;
} else {
observer = d.firstObserver();
}
if (newBinding) {
- newBinding.data()->ref.ref();
+ newBinding.data()->addRef();
d_ptr = (d_ptr & FlagMask) | reinterpret_cast<quintptr>(newBinding.data());
d_ptr |= BindingBit;
- newBinding->setDirty(true);
- newBinding->setProperty(propertyDataPtr);
+ auto newBindingRaw = static_cast<QPropertyBindingPrivate *>(newBinding.data());
+ newBindingRaw->setDirty(true);
+ newBindingRaw->setProperty(propertyDataPtr);
if (observer)
- newBinding->prependObserver(observer);
- newBinding->setStaticObserver(staticObserverCallback, guardCallback);
- if (newBinding->requiresEagerEvaluation()) {
- auto changed = newBinding->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
+ newBindingRaw->prependObserver(observer);
+ newBindingRaw->setStaticObserver(staticObserverCallback, guardCallback);
+ if (newBindingRaw->requiresEagerEvaluation()) {
+ auto changed = newBindingRaw->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
if (changed)
- observer.notify(newBinding.data(), propertyDataPtr, /*alreadyKnownToHaveChanged=*/true);
+ observer.notify(newBindingRaw, propertyDataPtr, /*alreadyKnownToHaveChanged=*/true);
}
} else if (observer) {
d.setObservers(observer.ptr);
@@ -251,9 +274,9 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB
}
if (oldBinding)
- oldBinding->detachFromProperty();
+ static_cast<QPropertyBindingPrivate *>(oldBinding.data())->detachFromProperty();
- return QUntypedPropertyBinding(oldBinding.data());
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
}
QPropertyBindingData::QPropertyBindingData(QPropertyBindingData &&other) : d_ptr(std::exchange(other.d_ptr, 0))