summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qproperty.cpp
Commit message (Collapse)AuthorAgeFilesLines
* QProperty: Fix notification logic for eager propertiesFabian Kosmale2020-11-031-2/+5
| | | | | | | | | | | | | This ensurse that we do not do dobule notifications in setValue. Moerover we avoid needless notifications in markDirtyAndNotifyObservers when the value did not change. Lastly, if the value did actually change, we pass that information along to notify, so that we do not evaluate the eager property twice. Fixes a test-case which errorneously relied on the old behavior, and adds a new test which verifies that the fix works. Change-Id: I8ec6fa2fe8611565dfc603ceab3ba5f92999b26c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Remove std::function from QProperty interfaceFabian Kosmale2020-11-031-21/+44
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Doc: Fix various documentation issues for Qt CoreTopi Reinio2020-10-311-2/+2
| | | | | | | Task-number: QTBUG-86295 Change-Id: I3bf7d4b1533d4fc81114d353b19beaf4ea9b93b2 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Paul Wicking <paul.wicking@qt.io>
* Doc: Fix documentation warnings for QProperty and related classesTopi Reinio2020-10-231-128/+43
| | | | | | Task-number: QTBUG-86295 Change-Id: I547f4cf34d9721f56ba1cd665218f66597ffbb5c Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Remove nodiscard in QPropertyObserverNodeProtector ctorAndrei Golubev2020-10-131-1/+1
| | | | | | | | | Produced error in my GCC 7.5 on Ubuntu 18: error: ‘nodiscard’ attribute applied to ‘QPropertyObserverNodeProtector<<anonymous> >::QPropertyObserverNodeProtector(QPropertyObserver*&)’ with void return type [-Werror=attributes] Q_REQUIRED_RESULT QPropertyObserverNodeProtector(QPropertyObserver *&observer) Change-Id: Ic1f6c4f502bb4d5c764686d5521b92f655592bb2 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Mark the class QPropertyObserverNodeProtector as [[nodiscard]]Lars Knoll2020-10-131-1/+1
| | | | | | | And not its constructor, as GCC at least doesn't like that. Change-Id: I4aada7ca7135dd9c599980640588e7c98d398171 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QPropertyObserver: mark as noexcecptFabian Kosmale2020-10-121-2/+2
| | | | | Change-Id: I2df75b35e42fa923c6cbf71a15569dc37140ee55 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QUntypedPropertyBinding::QUntypedPropertyBinding: use member initializer listFabian Kosmale2020-10-121-1/+1
| | | | | | | No need to default initialize the std::function and source location. Change-Id: I7d840376b16e7257386a4787dd06b7956fe37576 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Handle notifier list modification during iterationFabian Kosmale2020-10-121-22/+120
| | | | | | | | | | | | | | As propertyobservers can execute arbitrarily complex code, they can also modify the obsever list in multiple ways. To protect against list corruption resulting from this, we introduce a protection scheme which makes the list resilient against modification. A detailed description of the scheme can be found as a comment in QPropertyObserverPointer::notify. Task-number: QTBUG-87153 Change-Id: I9bb49e457165ddc1e4c8bbdf3d3c9fbf5ff27e94 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Fix ChangeHandler notification for eager propertiesFabian Kosmale2020-09-301-4/+16
| | | | | | | | | | | | | | ChangeHandler's evaluated the binding to detect if the value actually changed. This is a valid strategy for lazy bindings, but eager bindings were already evaluated at that point, and thus the change would not be detected. Change the binding loop test, so that there isn't a fixpoint in the binding loop, and we can still detect it. Changing the binding loop detection code to deal with this case is left as an exercise for the future. Change-Id: Ia5d9ce2cd98a5780e69c993b5824024eb186c154 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Disable moving of QPropertyLars Knoll2020-09-291-40/+7
| | | | | | | | | The semantics are not very intuitive, and it opens a can of worms with regards to what should happen with observers that observe that property. Change-Id: I6fb00b7693904b968224cc87d098bbd0ea776ba3 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QProperty: fix QBindingStoragePrivate::reallocate related codeFabian Kosmale2020-09-291-1/+2
| | | | | | | | | | 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>
* Prevent endless markDirtyAndNotifyObservers <-> notify loopFabian Kosmale2020-09-281-0/+8
| | | | | | | | | | | | Before we had the option of eager evaluation, we were able to use the dirty flag to detect whether we are recursing. However, eager properties will lead to a evaluateIfDirtyAndReturnTrueIfValueChanged call, and that in turn will clear the dirty flag. Introduce a new member to detect that situation, and set the bindings error state to BindingLoop if we detect that kind of loop. Change-Id: If40b93221848bd9e9422502318d992fad95b0b74 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Add QObjectCompatPropertyLars Knoll2020-09-021-13/+25
| | | | | | | | | | | | Add a compatibility property class that makes porting to the new property system as simple as possible. Binding evaluation for those compat properties is eager, as we do not control possible side effects of the code in the existing setters. Change-Id: Ic56347abb49e40631ec73e88c6d40d4bdb05ca29 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Pass a pointer to the property data into the method evaluating a bindingLars Knoll2020-09-021-6/+11
| | | | | | | | | Make it possible to evaluate the binding but write the result into a different memory location. This will help support compat properties, where the setter does a lot of additional work. Change-Id: Ib60220eb629e3dcb5c0d7004b693e92290dfabe5 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Add support for bindable properties to QObjectLars Knoll2020-09-021-0/+237
| | | | | | | | | | | | | | | | Add Q_OBJECT_BINDABLE_PROPERTY() macro that can be used to define a bindable property inside QObject. The macro and the class behind it creates storage for a property that is bindable inside a QObject or QObjectPrivate. The property only uses as much space as the data contained, ie. it has no storage overhead, as long as no bindings are being used. Bindings are being stored and looked up in the QBindingStorage associated with the owning object. Change-Id: I1dadd7bddbad6fbf10cfa791d6461574b9db82dd Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
* Cleanup QBindingPrivateLars Knoll2020-09-021-5/+6
| | | | | | | | | | | | Simplify the data structure. We only need one pointer for either the static callback or a bindingWrapper, so don't share it with the dependency observer array. Also ensure we reset the propertyDataPtr and clear the observers when the binding gets removed from a property. Change-Id: I4c1e7ec7823c3ef12c63d6f758b757e7bac60cae Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Add a QBindingStorage classLars Knoll2020-09-021-4/+163
| | | | | | | | | | | | | | | | | | | QBindingStorage is a class that can store a set of binding objects for the properties of a QObject. This will get used to reduce the memory overhead of the property system when adding bindable properties to QObject based classes. The binding storage has a pointer to the TLS entry containing the currently evaluating binding. Like that we avoid repeated TLS lookups and reduce the overhead of the property system to one pointer lookup and one compare for the case that properties aren't being used. Each QObject now owns one binding storage object, that can be used to store binding data for properties that members of the QObject. Change-Id: I27427c03c2ba281f072e074be96147bdbcaac246 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Move QPropertyObserver further up in the header fileLars Knoll2020-09-021-0/+2
| | | | | | | | | | Reorder source code to make the follow-up work easier. Also clean up retrieving the pointer to the aliased property. Make setSource(QPropertyBindingData) public, it'll be needed later on. Change-Id: I784fdceac8722c7df756b2d7c35e08c7ab3a2074 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Introduce a common base class for all QProperty typesLars Knoll2020-09-021-16/+60
| | | | | | | | | | | | | | | | | | Add an empty QUntypedPropertyData class. This allows making a couple of places where the system is currently using a void * more type safe. Also add a QPropertyData<T> as an intermediate class between QUntypedPropertyData and QProperty. This class will get used in a future commit to simplify storing property data separately from the possible binding data. Also simplify the static observer handling a bit by always passing it a pointer to the QUntypedPropertyData instead of some other void * that could point to anything. Change-Id: I1f8144ea717815b1bc6f034d1ac883c13af5aaf8 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Remove QNotifiedProperty and Q_PRIVATE_QPROPERTYLars Knoll2020-09-021-230/+0
| | | | | | | | | | | | | And all related functionality. This is being replaced by Q_BINDABLE_PROPERTY and Q_OBJECT_BINDABLE_PROPERTY in the next few commits. The new infrastructure coming will play nicer along with the existing property system. Commented out some autotests, that will get reimplemented with the updated infrastructure. Change-Id: I50c30bd4d5c6c6b6471f8eb93870e27d86f5a009 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Cleanups: Rename some classesLars Knoll2020-09-021-27/+27
| | | | | | | | | | Rename QPropertyBase to QPropertyBindingData, as it contains the data related to bindings. The new name fits better, as the data can now also live somewhere else than the data strored in the property. Change-Id: I489efb86ad2e0bad2740c9d1aa74506fe103d343 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Remove the special handling of QProperty<bool>Lars Knoll2020-09-021-27/+4
| | | | | | | | | Since we will be storing property data differently in most cases, having this special case would create too many additional complications. Change-Id: I27042b0730559bb375d8e3c07324398403a9885d Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Generalize some methods taking a QProperty<>Lars Knoll2020-09-021-0/+12
| | | | | | | | | | | | | | Generalize some methods taking a QProperty<T>, so that they can work with other types that implement the QProperty interface as well. This removes some duplication between QProperty and QNotifiedProperty. It also makes it possible to create private property classes that store their data in a different place. Change-Id: I4b1ae8589cb9a76be59e63206044dcf2244163c2 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Add const to some methodsLars Knoll2020-08-281-4/+4
| | | | | Change-Id: I60e93e0c9b57468ef4188bdb60a32fb9ac9046e1 Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
* Pass QMetaType by valueLars Knoll2020-08-241-1/+1
| | | | | | | | Now that QMetaType is not refcounted anymore, we can and should pass it by value. Change-Id: I848db65070713762f548ca949097c27783aacad4 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
* QNotifiedProperty: avoid crashFabian Kosmale2020-08-041-1/+1
| | | | | | | | | | | | We can end up in a situation where a (soon to be destroyed) observer is owned by a binding which is about to be deleted. If in that situation the binding is destroyed first, we end up with a dangling pointer and ensuing memory corruption. Instead, we now first transfer the ownership of the observer and only destroy the binding afterwards. Fixes: QTBUG-85824 Change-Id: I721c0319281ada981ae7896bd2e02e9a0cc901b8 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* Move all the QProperty related code into one compilation unitLars Knoll2020-07-101-48/+160
| | | | | | | | | | | | | And mark some methods as inline. Performance is critical for our new property system. Compiling it in one unit makes it possible for the compiler to do a much better job at inlining and generating optimized code. Improves performance of binding evaluations by another 20%. Change-Id: I5a2aa93c74d2b68418b0a9d2e34d8199bb71e3ad Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Significantly improve performance of binding evaluationLars Knoll2020-07-101-2/+2
| | | | | | | | | | | | | | Avoid any QVariant or type dependent code in the cpp files. Instead, let the binding wrapper determine if the value has changed and return true/false accordingly. This required also some reworking of the guard mechanism for notified properties, where the guard function wrapper now calls first the binding evaluation function and then passes the result to the guard. Change-Id: I350d07a508ccc0c5db7054a0efa4f270b6a78ec3 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Separate the error case when evaluating bindingsLars Knoll2020-07-101-0/+5
| | | | | | | | | | | | | | | | | | | | | There's no point in returning a usually empty error when evaluating bindings, adding overhead to the regular code path. Instead, the error can be set on the currently evaluating binding if required. This streamlines the functor used to wrap the binding and should thus expand to less code and execute faster in the regular case. To achieve this, expose a pointer to the currently evaluating binding in the private API (as QtQml needs it to be able to report errors). The error case now requires one additional TLS lookup, but we don't really care about performance in that case anyway. Change-Id: Iecb450e765244930a41d813fcf8eb4013957a6a3 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Cleanup QPropertyBindingErrorLars Knoll2020-07-101-15/+6
| | | | | | | | | | | | Remove location(). The method would always return an empty value. If you need the location, the binding itself has it. Remove setDescription() and require that the description gets passed in the constructor. Never create a d pointer if type is NoError, so we can quickly check for it inline. Change-Id: I7eb8a94786281069d6ea2d82567c09aa50c52ef6 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Get rid of one call into the TLS when evaluating bindingsLars Knoll2020-07-081-3/+6
| | | | | | | | | Store a pointer to the TLS in the BingingEvaluationState. Like this, we can save us one TLS lookup in the destructor. Shaves off a couple of percent during binding evaluation. Change-Id: Idc9dc5b0ea202aaeb68cdc063700b8e4968753dc Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Improve performance of property binding evaluationLars Knoll2020-07-071-2/+0
| | | | | | | | | Improves performance of binding evaluation by ~20% for simple C++ bindings by simplifying and inlining the code that clears the array of property observers. Change-Id: I829ac1895f1673367d737944d950360015a5b435 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QNotifiedProperty: Add guard callbackFabian Kosmale2020-06-251-2/+3
| | | | | | | | | | | | | | | A guard callback is a predicate which takes the new value set by setValue or computed as the result of a binding expression. If it returns false, the value is discarded and the old value is kept. Note that due to lazyness, when setting a binding, we still notify everyone as the binding is only evaluated on demand, and the guard can thus only run when someone actually queries the value. Note further that a guard is allowed to modify the value that is passed to it (e.g. to clamp it to a certain range). Task-number: QTBUG-85032 Change-Id: I3551e4357fe5780fb75da80bf8be208ec152dc2a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* QNotifiedProperty: pass old value to callback if requestedFabian Kosmale2020-06-251-1/+1
| | | | | | | | | Check at compile time whether the static callback takes an argument (which has to be of the same time as the type of the property). If so, retrieve the old value and pass it to the callback. Change-Id: Ib1c4c9e05b826b6be492b03f66fa72ad015963ee Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Implement support for QProperty<T> with a static observerSimon Hausmann2020-05-281-1/+229
| | | | | | | | | | | | | | | | | | | | | | | A common pattern in Qt Quick will be QProperty members that are connected to a callback that needs to perform something when the value changes, for example emitting a compatibility signal or marking scene graph node data dirty. To make such a pattern more efficient, a new QNotifiedProperty type is introduced that offers the same API as QProperty<T>, with two changes: (1) The template instantiation not only takes the property type as parameter but also a callback pointer-to-member. (2) Since that member itself cannot be called without an instance and to avoid storing an instance pointer permanently, the API for setBinding and setValue are adjusted to also take the instance pointer. For the former it gets stored in the binding, for the latter it is used to invoke the callback after setting the new value. Change-Id: I85cc1d1d1c0472164c4ae87808cfdc0d0b1475e1 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
* Add a QPropertyAliasUlf Hermann2020-05-271-3/+246
| | | | | | | | | | | | A property alias is the equivalent of the "alias" keyword in QML. It provides the same API as QProperty, but redirects any access to the QProperty it was initialized with. When the original property is destroyed the binding becomes invalid and ignores any further acccess. Task-number: QTBUG-84370 Change-Id: I0aef8d50e73a2aa9e7703d51194d4c5480573578 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
* QProperty: Support multiple observersUlf Hermann2020-05-271-15/+22
| | | | | | | | | Previously, only the first observer would get notified. Also, make sure that the notifiers are always retained when switching between bindings and values. Change-Id: I9c25c0f2e288dac3a335b68e618f7ddeb44be25a Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QProperty: Apply coding style and avoid warningsUlf Hermann2020-05-271-1/+1
| | | | | Change-Id: I14efdb293a4be39b3849b34bd8013fdab016ce7e Reviewed-by: Simon Hausmann <hausmann@gmail.com>
* Make it possible to take bindings from properties without private headersSimon Hausmann2020-04-171-5/+5
| | | | | | | | | | | Passing the QExplicitlySharedDataPointer by reference may lead compilers to wanting to have visibility to the destructor of the contained type (QPropertyBindingPrivate), which is not public. Fortunately QExplicitlySharedDataPointer is safe to use with raw pointers and those can be safely forward declared. Change-Id: I131ab6363eaee10b6dce196fb2c769e09a5c9557 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* QProperty: Add support for member function change handlersSimon Hausmann2020-04-061-6/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | When a class has multiple QProperty members to implement functionality, it is common to have functions in the class that react to changes. For example to emit a compatibility signal, in case of Qt Quick to mark the scene graph as dirty, etc. etc. To faciliate this use-case, this patch adds an internal QPropertyMemberChangeHandler template that allows connecting a QProperty field to a member function callback. At the moment that callback is still 3 * sizeof(pointer). This could in theory be reduced to 2 by eliminating the back-pointer (prev) as the observer lives as long as the property. That however belongs into maybe a future patch. In order to get a pointer back to the surrounding object that holds the QProperty as well as provides the callback function, the property system was changed to pass through the address of the QProperty member at run-time, and at compile time the delta from the QProperty member to the beginning of the surrounding class is calculated. Through subtraction we obtain the pointer to the owning object. Change-Id: Ia2976357053f474ff44d0d6f60527c3b8e1f613a Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Make QPropertyBindingPrivate accessible to QtQmlSimon Hausmann2020-03-271-15/+9
| | | | | | | | | | | | | | | | | | QtQml needs the private just for one detail which nobody else should need it for: Tracking additional dependencies and marking the binding as dirty. Exporting the private requires hiding some variables and providing accessors, to compile with MSVC - including the removal of QVarLengthArray usage. Upside: The binding structure shrinks by 8 bytes and the encapsulation makes it a little easier to change things without breaking declarative, ... in the unlikely event ;-) Also remove setDirty() from the public API as it's not needed by QtQml and using it is dangerous, because it means that there's a risk of somebody keeping a reference (count) to the untyped binding from within the binding closure, which introduces a memory leak. Change-Id: I43bd56f4bdf218efb54fa23e2d627ad3acfafeb5 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Change QTaggedPointer API to be more similar to other smart pointers in QtSimon Hausmann2020-03-191-2/+2
| | | | | | | * Rename pointer() to data() Change-Id: I8ef3e552d45c9990fee4b7efa98e2d878ed2cf98 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
* Use QTaggedPointer in QPropertyObserverSimon Hausmann2020-03-191-22/+37
| | | | | | | | | | This replaces the private tagged pointer and the use of enums for the tag makes the observer handling code more readable. The pointer-to-tagged-pointer class remains in qpropertyprivate.h due to its exoticness. Change-Id: Icc88799136c6839426d994b42368526463265e66 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Enable generic property bindings to QProperty<T>Simon Hausmann2020-03-191-0/+13
| | | | | | | | | | A generic binding allows implementing the binding function in a way that enables the QML engine to run binding scripts and convert the V4::Value into a QVariant and then assign the value to the property with the help of QMetaType::construct. Change-Id: Id4807be92eee7e3501908e6c5e4c861cfcb7772a Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
* Initial import of the Qt C++ property binding systemSimon Hausmann2020-03-161-0/+671
This implements the core value based property binding system with automatic dependency tracking. More features are to be added later, and the documentation will need further improvements as well. Change-Id: I77ec9163ba4dace6c4451f5933962ebe1b3b4b14 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>