7#include <qscopedvaluerollback.h>
9#include <QtCore/qalloc.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtCore/private/qthread_p.h>
12#include <QtCore/qmetaobject.h>
13#include <QtCore/qmutex.h>
19Q_STATIC_LOGGING_CATEGORY(lcQPropertyBinding,
"qt.qproperty.binding");
23void QPropertyBindingPrivatePtr::destroyAndFreeMemory()
25 QPropertyBindingPrivate::destroyAndFreeMemory(
static_cast<QPropertyBindingPrivate *>(d));
28void QPropertyBindingPrivatePtr::reset(QtPrivate::RefCounted *ptr)
noexcept
33 auto *old = std::exchange(d, ptr);
34 if (old && !old->deref())
35 QPropertyBindingPrivate::destroyAndFreeMemory(
static_cast<QPropertyBindingPrivate *>(d));
42 if (
auto *b = binding()) {
43 observer->prev = &b->firstObserver.ptr;
44 observer->next = b->firstObserver.ptr;
46 observer->next->prev = &observer->next;
47 b->firstObserver.ptr = observer;
49 auto &d = ptr->d_ref();
50 Q_ASSERT(!(d & QPropertyBindingData::BindingBit));
51 auto firstObserver =
reinterpret_cast<QPropertyObserver*>(d);
52 observer->prev =
reinterpret_cast<QPropertyObserver**>(&d);
53 observer->next = firstObserver;
55 observer->next->prev = &observer->next;
56 d =
reinterpret_cast<quintptr>(observer);
61
62
63
64
65
66
67
68
83
84
85
86
87
88
89
90
91 void addProperty(
const QPropertyBindingData *bindingData, QUntypedPropertyData *propertyData) {
92 if (bindingData->isNotificationDelayed())
95 while (data->used == size) {
101 auto *delayed = data->delayedProperties + data->used;
102 *delayed = QPropertyProxyBindingData { bindingData->d_ptr, bindingData, propertyData };
105 quintptr bindingBit = bindingData->d_ptr & QPropertyBindingData::BindingBit;
106 bindingData->d_ptr =
reinterpret_cast<quintptr>(delayed) | QPropertyBindingData::DelayedNotificationBit | bindingBit;
107 Q_ASSERT(bindingData->d_ptr > 3);
109 if (
auto observer =
reinterpret_cast<QPropertyObserver *>(delayed->d_ptr))
110 observer->prev =
reinterpret_cast<QPropertyObserver **>(&delayed->d_ptr);
115
116
117
118
119
120
121
122
123
124
125
126 void evaluateBindings(PendingBindingObserverList &bindingObservers, qsizetype index, QBindingStatus *status) {
127 auto *delayed = delayedProperties + index;
128 auto *bindingData = delayed->originalBindingData;
132 bindingData->d_ptr = delayed->d_ptr;
133 Q_ASSERT(!(bindingData->d_ptr & QPropertyBindingData::DelayedNotificationBit));
134 if (!bindingData->hasBinding()) {
135 if (
auto observer =
reinterpret_cast<QPropertyObserver *>(bindingData->d_ptr))
136 observer->prev =
reinterpret_cast<QPropertyObserver **>(&bindingData->d_ptr);
142 observer.evaluateBindings(bindingObservers, status);
146
147
148
149
150
151
152
153
155 auto *delayed = delayedProperties + index;
156 if (delayed->d_ptr & QPropertyBindingData::BindingBit)
158 if (!delayed->originalBindingData)
160 delayed->originalBindingData =
nullptr;
162 QPropertyObserverPointer observer {
reinterpret_cast<QPropertyObserver *>(delayed->d_ptr & ~QPropertyBindingData::DelayedNotificationBit) };
166 observer.notify(delayed->propertyData);
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
194Q_CONSTINIT
thread_local QBindingStatus *tl_status =
nullptr;
198 auto status =
new QBindingStatus {};
200
201
202
205 QThread *currentThread = threadData->thread;
207 QThreadPrivate *threadPriv =
static_cast<QThreadPrivate *>(QObjectPrivate::get(currentThread));
208 QMutexLocker lock(&threadPriv->mutex);
209 threadData->m_statusOrPendingObjects.setStatusAndClearList(status);
213 threadData->m_statusOrPendingObjects.setStatusAndClearList(status);
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
247 if (!groupUpdateData)
249 ++groupUpdateData
->ref;
253
254
255
256
257
258
259
260
261
262
263
266 auto status = &bindingStatus();
268 auto *data = groupUpdateData;
272 groupUpdateData =
nullptr;
274 PendingBindingObserverList bindingObservers;
278 for (qsizetype i = 0; i < data->used; ++i)
279 data->evaluateBindings(bindingObservers, i, status);
283 for (
const auto &bindingPtr: bindingObservers) {
284 auto *binding =
static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
285 binding->notifyNonRecursive();
290 for (qsizetype i = 0; i < data->used; ++i)
292 delete std::exchange(data, data->next);
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
319
320
321
322
325
326
327
328
333static_assert(std::is_trivially_destructible_v<QPropertyBindingSourceLocation>);
336QPropertyBindingPrivate::~QPropertyBindingPrivate()
339 firstObserver.unlink();
341 vtable->destroy(
reinterpret_cast<std::byte *>(
this)
342 + QPropertyBindingPrivate::getSizeEnsuringAlignment());
345void QPropertyBindingPrivate::clearDependencyObservers() {
346 for (size_t i = 0; i < qMin(dependencyObserverCount, inlineDependencyObservers.size()); ++i) {
347 QPropertyObserverPointer p{&inlineDependencyObservers[i]};
351 heapObservers->clear();
352 dependencyObserverCount = 0;
355QPropertyObserverPointer QPropertyBindingPrivate::allocateDependencyObserver_slow()
357 ++dependencyObserverCount;
359 heapObservers.reset(
new std::vector<QPropertyObserver>());
360 return {&heapObservers->emplace_back()};
363void QPropertyBindingPrivate::unlinkAndDeref()
365 clearDependencyObservers();
366 propertyDataPtr =
nullptr;
368 destroyAndFreeMemory(
this);
371bool QPropertyBindingPrivate::evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
374 status = &bindingStatus();
375 return evaluateRecursive_inline(bindingObservers, status);
378void QPropertyBindingPrivate::notifyNonRecursive(
const PendingBindingObserverList &bindingObservers)
380 notifyNonRecursive();
381 for (
auto &&bindingPtr: bindingObservers) {
382 auto *binding =
static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
383 binding->notifyNonRecursive();
387QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRecursive()
391 pendingNotify =
false;
395 firstObserver.noSelfDependencies(
this);
396 firstObserver.notify(propertyDataPtr);
398 if (hasStaticObserver)
399 staticObserverCallback(propertyDataPtr);
405
406
407
408
409
410
411
412
415
416
417
418
419QUntypedPropertyBinding::QUntypedPropertyBinding() =
default;
422
423
424
425
426
429
430
431
432
433
434
435QUntypedPropertyBinding::QUntypedPropertyBinding(QMetaType metaType,
const BindingFunctionVTable *vtable,
void *function,
436 const QPropertyBindingSourceLocation &location)
438 std::byte *mem =
new std::byte[QPropertyBindingPrivate::getSizeEnsuringAlignment() + vtable->size]();
439 d =
new(mem) QPropertyBindingPrivate(metaType, vtable, std::move(location));
440 vtable->moveConstruct(mem + QPropertyBindingPrivate::getSizeEnsuringAlignment(), function);
444
445
446
447
448
449QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other)
450 : d(std::move(other.d))
455
456
457QUntypedPropertyBinding::QUntypedPropertyBinding(
const QUntypedPropertyBinding &other)
462
463
464QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(
const QUntypedPropertyBinding &other)
471
472
473
474
475
476QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(QUntypedPropertyBinding &&other)
478 d = std::move(other.d);
483
484
485QUntypedPropertyBinding::QUntypedPropertyBinding(QPropertyBindingPrivate *priv)
491
492
493QUntypedPropertyBinding::~QUntypedPropertyBinding()
498
499
500
501
502
503bool QUntypedPropertyBinding::isNull()
const
509
510
511
512
513QPropertyBindingError QUntypedPropertyBinding::error()
const
516 return QPropertyBindingError();
517 return static_cast<QPropertyBindingPrivate *>(d.get())->bindingError();
521
522
523
524QMetaType QUntypedPropertyBinding::valueMetaType()
const
528 return static_cast<QPropertyBindingPrivate *>(d.get())->valueMetaType();
531QPropertyBindingData::~QPropertyBindingData()
533 QPropertyBindingDataPointer d{
this};
534 if (isNotificationDelayed())
535 proxyData()->originalBindingData =
nullptr;
536 for (
auto observer = d.firstObserver(); observer;) {
537 auto next = observer.nextObserver();
541 if (
auto binding = d.binding())
542 binding->unlinkAndDeref();
545QUntypedPropertyBinding QPropertyBindingData::setBinding(
const QUntypedPropertyBinding &binding,
546 QUntypedPropertyData *propertyDataPtr,
547 QPropertyObserverCallback staticObserverCallback,
548 QtPrivate::QPropertyBindingWrapper guardCallback)
550 QPropertyBindingPrivatePtr oldBinding;
551 QPropertyBindingPrivatePtr newBinding = binding.d;
553 QPropertyBindingDataPointer d{
this};
554 QPropertyObserverPointer observer;
556 auto &data = d_ref();
557 if (
auto *existingBinding = d.binding()) {
558 if (existingBinding == newBinding.data())
559 return QUntypedPropertyBinding(
static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
560 if (existingBinding->isUpdating()) {
561 existingBinding->setError({QPropertyBindingError::BindingLoop, QStringLiteral(
"Binding set during binding evaluation!")});
562 return QUntypedPropertyBinding(
static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
564 oldBinding = QPropertyBindingPrivatePtr(existingBinding);
565 observer =
static_cast<QPropertyBindingPrivate *>(oldBinding.data())->takeObservers();
566 static_cast<QPropertyBindingPrivate *>(oldBinding.data())->unlinkAndDeref();
569 observer = d.firstObserver();
573 newBinding.data()->addRef();
574 data =
reinterpret_cast<quintptr>(newBinding.data());
576 auto newBindingRaw =
static_cast<QPropertyBindingPrivate *>(newBinding.data());
577 newBindingRaw->setProperty(propertyDataPtr);
579 newBindingRaw->prependObserver(observer);
580 newBindingRaw->setStaticObserver(staticObserverCallback, guardCallback);
582 PendingBindingObserverList bindingObservers;
583 newBindingRaw->evaluateRecursive(bindingObservers);
584 newBindingRaw->notifyNonRecursive(bindingObservers);
585 }
else if (observer) {
586 d.setObservers(observer.ptr);
592 static_cast<QPropertyBindingPrivate *>(oldBinding.data())->detachFromProperty();
594 return QUntypedPropertyBinding(
static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
597QPropertyBindingData::QPropertyBindingData(QPropertyBindingData &&other) : d_ptr(std::exchange(other.d_ptr, 0))
599 QPropertyBindingDataPointer::fixupAfterMove(
this);
606 QBindingStatus *s = status;
609 currentState = &s->currentlyEvaluatingBinding;
612 binding->clearDependencyObservers();
624 currentlyEvaluatingBindingList = &bindingStatus().currentlyEvaluatingBinding;
629QPropertyBindingPrivate *QPropertyBindingPrivate::currentlyEvaluatingBinding()
631 auto currentState = bindingStatus().currentlyEvaluatingBinding ;
632 return currentState ? currentState->binding :
nullptr;
636void QPropertyBindingData::evaluateIfDirty(
const QUntypedPropertyData *)
const
640void QPropertyBindingData::removeBinding_helper()
642 QPropertyBindingDataPointer d{
this};
644 auto *existingBinding = d.binding();
645 Q_ASSERT(existingBinding);
646 if (existingBinding->isSticky()) {
650 auto observer = existingBinding->takeObservers();
653 d.setObservers(observer.ptr);
654 existingBinding->unlinkAndDeref();
657void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding()
const
659 auto currentState = bindingStatus().currentlyEvaluatingBinding;
662 registerWithCurrentlyEvaluatingBinding_helper(currentState);
666void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentState)
const
668 QPropertyBindingDataPointer d{
this};
670 if (currentState->alreadyCaptureProperties.contains(
this))
673 currentState->alreadyCaptureProperties.push_back(
this);
675 QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
676 Q_ASSERT(QPropertyObserver::ObserverNotifiesBinding == 0);
677 dependencyObserver.setBindingToNotify_unsafe(currentState->binding);
678 d.addObserver(dependencyObserver.ptr);
681void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr)
const
683 notifyObservers(propertyDataPtr,
nullptr);
686void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage)
const
688 if (isNotificationDelayed())
690 QPropertyBindingDataPointer d{
this};
692 PendingBindingObserverList bindingObservers;
693 if (QPropertyObserverPointer observer = d.firstObserver()) {
694 if (notifyObserver_helper(propertyDataPtr, storage, observer, bindingObservers) == Evaluated) {
696
697
698
699
700
701
703 d = QPropertyBindingDataPointer {storage->bindingData(propertyDataPtr)};
704 if (QPropertyObserverPointer observer = d.firstObserver())
705 observer.notify(propertyDataPtr);
706 for (
auto &&bindingPtr: bindingObservers) {
707 auto *binding =
static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
708 binding->notifyNonRecursive();
714QPropertyBindingData::NotificationResult QPropertyBindingData::notifyObserver_helper
716 QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
717 QPropertyObserverPointer observer,
718 PendingBindingObserverList &bindingObservers)
const
720#ifdef QT_HAS_FAST_CURRENT_THREAD_ID
721 QBindingStatus *status = storage ? storage->bindingStatus :
nullptr;
722 if (!status || status->threadId != QThread::currentThreadId())
723 status = &bindingStatus();
726 QBindingStatus *status = &bindingStatus();
728 if (QPropertyDelayedNotifications *delay = status->groupUpdateData) {
729 delay->addProperty(
this, propertyDataPtr);
733 observer.evaluateBindings(bindingObservers, status);
738QPropertyObserver::QPropertyObserver(ChangeHandler changeHandler)
740 QPropertyObserverPointer d{
this};
741 d.setChangeHandler(changeHandler);
744#if QT_DEPRECATED_SINCE(6
, 6
)
745QPropertyObserver::QPropertyObserver(QUntypedPropertyData *data)
747 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
749 next.setTag(ObserverIsAlias);
755
756void QPropertyObserver::setSource(
const QPropertyBindingData &property)
758 QPropertyObserverPointer d{
this};
759 QPropertyBindingDataPointer propPrivate{&property};
760 d.observeProperty(propPrivate);
763QPropertyObserver::~QPropertyObserver()
765 QPropertyObserverPointer d{
this};
769QPropertyObserver::QPropertyObserver(QPropertyObserver &&other)
noexcept
771 binding = std::exchange(other.binding, {});
772 next = std::exchange(other.next, {});
773 prev = std::exchange(other.prev, {});
777 prev.setPointer(
this);
780QPropertyObserver &QPropertyObserver::operator=(QPropertyObserver &&other)
noexcept
785 QPropertyObserverPointer d{
this};
789 binding = std::exchange(other.binding, {});
790 next = std::exchange(other.next, {});
791 prev = std::exchange(other.prev, {});
795 prev.setPointer(
this);
801
802
803
804
808
809
810
811
812
813
817 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
818 ptr->changeHandler = changeHandler;
819 ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
823
824
825
828 Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
829 ptr->binding = binding;
833
834
835
836
837
840
841
842
843
848 auto observer =
const_cast<QPropertyObserver*>(ptr);
851 if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding)
852 if (observer->binding == binding) {
853 qCritical(
"Property depends on itself!");
857 observer = observer->next.data();
866 auto observer =
const_cast<QPropertyObserver*>(ptr);
869 QPropertyObserver *next = observer->next.data();
871 if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) {
872 auto bindingToEvaluate = observer->binding;
873 QPropertyObserverNodeProtector protector(observer);
875 QPropertyBindingPrivatePtr currentBinding(observer->binding);
876 const bool evalStatus = bindingToEvaluate->evaluateRecursive_inline(bindingObservers, status);
878 bindingObservers.push_back(std::move(currentBinding));
879 next = protector.next();
890 property.addObserver(
ptr);
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
936
937
938
939
940QPropertyBindingError::QPropertyBindingError()
945
946
947
948QPropertyBindingError::QPropertyBindingError(Type type,
const QString &description)
950 if (type != NoError) {
951 d =
new QPropertyBindingErrorPrivate;
953 d->description = description;
958
959
960QPropertyBindingError::QPropertyBindingError(
const QPropertyBindingError &other)
966
967
968QPropertyBindingError &QPropertyBindingError::operator=(
const QPropertyBindingError &other)
975
976
977
978QPropertyBindingError::QPropertyBindingError(QPropertyBindingError &&other)
979 : d(std::move(other.d))
984
985
986
987QPropertyBindingError &QPropertyBindingError::operator=(QPropertyBindingError &&other)
989 d = std::move(other.d);
994
995
996QPropertyBindingError::~QPropertyBindingError()
1001
1002
1003
1004
1005QPropertyBindingError::Type QPropertyBindingError::type()
const
1008 return QPropertyBindingError::NoError;
1013
1014
1015
1016QString QPropertyBindingError::description()
const
1020 return d->description;
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1046
1047
1048
1049
1050
1051
1052
1055
1056
1057
1058
1059
1062
1063
1064
1065
1066
1067
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1086
1087
1088
1089
1090
1093
1094
1095
1096
1097
1098
1099
1100
1103
1104
1105
1106
1107
1110
1111
1112
1113
1114
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1129
1130
1131
1132
1135
1136
1137
1138
1139
1142
1143
1144
1145
1146
1147
1148
1149
1152
1153
1154
1155
1156
1157
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1172
1173
1174
1175
1176
1177
1178
1181
1182
1183
1184
1185
1186
1187
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1202
1203
1204
1205
1208
1209
1210
1211
1212
1213
1214
1215
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1273
1274
1275
1276
1277
1280
1281
1282
1283
1284
1287
1288
1289
1290
1291
1292
1293
1294
1297
1298
1299
1300
1301
1302
1303
1304
1308
1309
1310
1311
1312
1313
1314
1315
1318
1319
1320
1321
1322
1325
1326
1327
1328
1329
1330
1331
1334
1335
1336
1337
1338
1339
1340
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1375
1376
1377
1378
1381
1382
1383
1384
1387
1388
1389
1390
1393
1394
1395
1396
1397
1400
1401
1402
1403
1404
1405
1406
1409
1410
1411
1412
1413
1414
1415
1418
1419
1420
1421
1424
1425
1426
1427
1428
1431
1432
1433
1434
1435
1436
1439
1440
1441
1442
1443
1446
1447
1448
1449
1450
1451
1452
1453
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1484
1485
1486
1487
1488
1489
1492
1493
1494
1495
1496
1497
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1554
1555
1556
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1634
1635
1636
1637
1638
1639
1640
1641
1642
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1732
1733
1734
1735
1736
1737
1738
1739
1740
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1796
1797
1798
1799
1800
1801
1802
1803
1804
1808
1809
1810
1813
1814
1815
1816
1819
1820
1821
1822
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1849
1850
1851
1852
1853
1854
1855
1856
1859
1860
1861
1862
1865
1866
1867
1868
1869
1872
1873
1874
1875
1876
1877
1878
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1939
1940
1941
1942
1946
1947
1948
1949
1950
1951
1954
1955
1956
1957
1958
1959
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2013
2014
2015
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2096
2097
2098
2099
2102
2103
2104
2105
2108
2109
2110
2111
2112
2115
2116
2117
2118
2119
2122
2123
2124
2125
2126
2129
2130
2131
2132
2133
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2180
2181
2182
2183
2184
2187
2188
2189
2190
2191
2192
2195
2196
2197
2198
2199
2200
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2254
2255
2256
2257
2258
2259
2278 static_assert(
alignof(
Pair) ==
alignof(
void *));
2279 static_assert(
alignof(
size_t) ==
alignof(
void *));
2286 return reinterpret_cast<
Pair *>(dd + 1);
2290 Q_ASSERT(!
d || newSize >
d->size);
2292 void *nd = calloc(1, allocSize);
2294 newData->size = newSize;
2299 newData->used =
d->used;
2301 for (size_t i = 0; i <
d->size; ++i, ++p) {
2304 Q_ASSERT(newData->size && (newData->size & (newData->size - 1)) == 0);
2305 size_t index = qHash(p->data) & (newData->size - 1);
2306 while (pp[index].data) {
2308 if (index == newData->size)
2311 new (pp + index)
Pair{p->data, QPropertyBindingData(
std::move(p->bindingData))};
2316 QtPrivate::sizedFree(d, oldAllocSize);
2325 Q_ASSERT(
d->size && (
d->size & (
d->size - 1)) == 0);
2326 size_t index = qHash(data) & (
d->size - 1);
2328 while (p[index].data) {
2329 if (p[index].data == data)
2330 return &p[index].bindingData;
2332 if (index ==
d->size)
2344 else if (d->used*2 >= d->size)
2345 reallocate(d->size*2);
2346 Q_ASSERT(
d->size && (
d->size & (
d->size - 1)) == 0);
2347 size_t index = qHash(data) & (
d->size - 1);
2349 while (p[index].data) {
2350 if (p[index].data == data)
2351 return &p[index].bindingData;
2353 if (index ==
d->size)
2359 new (p + index)
Pair{data, QPropertyBindingData()};
2360 return &p[index].bindingData;
2368 for (size_t i = 0; i <
d->size; ++i) {
2374 QtPrivate::sizedFree(d, allocSize);
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2390QBindingStorage::QBindingStorage()
2392 bindingStatus = &QT_PREPEND_NAMESPACE(bindingStatus)();
2393 Q_ASSERT(bindingStatus);
2396QBindingStorage::~QBindingStorage()
2398 QBindingStoragePrivate(d).destroy();
2401void QBindingStorage::reinitAfterThreadMove()
2403 bindingStatus = &QT_PREPEND_NAMESPACE(bindingStatus)();
2404 Q_ASSERT(bindingStatus);
2407void QBindingStorage::clear()
2409 QBindingStoragePrivate(d).destroy();
2411 bindingStatus =
nullptr;
2414void QBindingStorage::registerDependency_helper(
const QUntypedPropertyData *data)
const
2416 Q_ASSERT(bindingStatus);
2419 QtPrivate::BindingEvaluationState *currentBinding;
2420#ifdef QT_HAS_FAST_CURRENT_THREAD_ID
2421 const bool threadMatches = (QThread::currentThreadId() == bindingStatus->threadId);
2422 if (Q_LIKELY(threadMatches))
2423 currentBinding = bindingStatus->currentlyEvaluatingBinding;
2425 currentBinding = QT_PREPEND_NAMESPACE(bindingStatus)().currentlyEvaluatingBinding;
2427 currentBinding = QT_PREPEND_NAMESPACE(bindingStatus)().currentlyEvaluatingBinding;
2429 QUntypedPropertyData *dd =
const_cast<QUntypedPropertyData *>(data);
2430 if (!currentBinding)
2432 auto storage = QBindingStoragePrivate(d).get(dd,
true);
2435 storage->registerWithCurrentlyEvaluatingBinding(currentBinding);
2439QPropertyBindingData *QBindingStorage::bindingData_helper(
const QUntypedPropertyData *data)
const
2441 return QBindingStoragePrivate(d).get(data);
2444const QBindingStatus *QBindingStorage::status(QtPrivate::QBindingStatusAccessToken)
const
2446 return bindingStatus;
2449QPropertyBindingData *QBindingStorage::bindingData_helper(QUntypedPropertyData *data,
bool create)
2451 return QBindingStoragePrivate(d).get(data, create);
2458void initBindingStatusThreadId()
2460 bindingStatus().threadId = QThread::currentThreadId();
2465 auto ret = bindingStatus().currentlyEvaluatingBinding;
2476
2477
2478
2479
2480
2481
2482
2485 return bindingStatus().currentlyEvaluatingBinding !=
nullptr;
2491 if (
const auto current = bindingStatus().currentCompatProperty)
2492 return current->property == property;
2502 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2503 <<
"The QBindable does not allow interaction with the binding.";
2506 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2507 <<
"The QBindable is read-only.";
2511 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2512 <<
"The QBindable is invalid.";
2519 qCWarning(lcQPropertyBinding) <<
"setBinding: Could not set binding as the property expects it to be of type"
2521 <<
"but got" << expected.name() <<
"instead.";
2527
2528
2529
2542void getter(
const QUntypedPropertyData *d,
void *value)
2545 adaptor->bindingData().registerWithCurrentlyEvaluatingBinding();
2546 auto mt = adaptor->metaProperty().metaType();
2548 mt.construct(value, adaptor->metaProperty().read(adaptor->object()).data());
2551void setter(QUntypedPropertyData *d,
const void *value)
2554 adaptor->bindingData().removeBinding();
2555 adaptor->metaProperty().write(adaptor->object(),
2556 QVariant(adaptor->metaProperty().metaType(), value));
2562 return QUntypedPropertyBinding(adaptor->bindingData().binding());
2566 QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp,
2570 type.destruct(value);
2571 type.construct(value, adaptor->metaProperty().read(adaptor->object()).data());
2572 if (binding.vtable->call(type, temp, binding.functor)) {
2573 adaptor->metaProperty().write(adaptor->object(), QVariant(type, value));
2580 QPropertyBindingWrapper wrapper)
2583 return adaptor->bindingData().setBinding(binding, d,
nullptr, wrapper);
2586void setObserver(
const QUntypedPropertyData *d, QPropertyObserver *observer)
2593 : QSlotObjectBase(&impl), obj(o), metaProperty_(p)
2597#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
2611 if (!self->bindingData_.hasBinding())
2612 self->bindingData_.notifyObservers(self);
2632 if (!metaProperty.isValid()) {
2633 qCWarning(lcQPropertyBinding) <<
"QUntypedBindable: Property is not valid";
2637 if (metaProperty.isBindable()) {
2638 *
this = metaProperty.bindable(obj);
2642 if (!metaProperty.hasNotifySignal()) {
2643 qCWarning(lcQPropertyBinding)
2644 <<
"QUntypedBindable: Property" << metaProperty.name() <<
"has no notify signal";
2648 auto metatype =
iface->metaType();
2649 if (metaProperty.metaType() != metatype) {
2650 qCWarning(lcQPropertyBinding) <<
"QUntypedBindable: Property" << metaProperty.name()
2651 <<
"of type" << metaProperty.metaType().name()
2652 <<
"does not match requested type" << metatype.name();
2657 if (obj->metaObject()->property(metaProperty.propertyIndex()).name() != metaProperty.name()) {
2658 qCWarning(lcQPropertyBinding) <<
"QUntypedBindable: Property" << metaProperty.name()
2659 <<
"does not belong to this object";
2664 auto adaptor = QObjectPrivate::get(obj)->getPropertyAdaptorSlotObject(metaProperty);
2669 auto c = QObjectPrivate::connect(obj, metaProperty.notifySignalIndex(), obj, adaptor,
2670 Qt::DirectConnection);
2681 [=]() -> QMetaProperty {
2684 auto propertyIndex = obj->metaObject()->indexOfProperty(property);
2685 if (propertyIndex < 0) {
2686 qCWarning(lcQPropertyBinding)
2687 <<
"QUntypedBindable: No property named" << property;
2690 return obj->metaObject()->property(propertyIndex);
const QtPrivate::QBindableInterface * iface
friend class QT_PREPEND_NAMESPACE(QUntypedBindable)
Combined button and popup list for selecting options.
void printMetaTypeMismatch(QMetaType actual, QMetaType expected)
void printUnsuitableBindableWarning(QAnyStringView prefix, BindableWarnings::Reason reason)
void setter(QUntypedPropertyData *d, const void *value)
void getter(const QUntypedPropertyData *d, void *value)
bool bindingWrapper(QMetaType type, QUntypedPropertyData *d, QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp, void *value)
QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d)
QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding, QPropertyBindingWrapper wrapper)
void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer)
Q_CORE_EXPORT bool isAnyBindingEvaluating()
void setBindingStatus(QBindingStatus *status, QBindingStatusAccessToken)
Q_CORE_EXPORT void restoreBindingStatus(BindingEvaluationState *status)
QBindingStatus * getBindingStatus(QtPrivate::QBindingStatusAccessToken)
Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
Q_CORE_EXPORT void beginPropertyUpdateGroup()
Q_CORE_EXPORT void endPropertyUpdateGroup()
static QBindingStatus & bindingStatus()
static Q_NEVER_INLINE void initBindingStatus()
QPropertyBindingData bindingData
QUntypedPropertyData * data
static Pair * pairs(QBindingStorageData *dd)
QBindingStoragePrivate(QBindingStorageData *&_d)
void reallocate(size_t newSize)
QPropertyBindingData * get(QUntypedPropertyData *data, bool create)
QPropertyBindingData * get(const QUntypedPropertyData *data)
Q_ALWAYS_INLINE void addObserver(QPropertyObserver *observer)
QPropertyObserverPointer firstObserver() const
QPropertyProxyBindingData delayedProperties[size]
void notify(qsizetype index)
static constexpr auto PageSize
void addProperty(const QPropertyBindingData *bindingData, QUntypedPropertyData *propertyData)
static constexpr qsizetype size
void evaluateBindings(PendingBindingObserverList &bindingObservers, qsizetype index, QBindingStatus *status)
QPropertyDelayedNotifications * next
void observeProperty(QPropertyBindingDataPointer property)
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler)
BindingEvaluationState(QPropertyBindingPrivate *binding, QBindingStatus *status)
BindingEvaluationState * previousState
BindingEvaluationState ** currentState
QtPrivate::BindingEvaluationState ** currentlyEvaluatingBindingList
CompatPropertySafePoint * previousState
CompatPropertySafePoint ** currentState
QtPrivate::BindingEvaluationState * bindingState