5#ifndef QQMLPROPERTYBINDING_P_H
6#define QQMLPROPERTYBINDING_P_H
19#include <private/qqmljavascriptexpression_p.h>
20#include <private/qqmlpropertydata_p.h>
21#include <private/qv4alloca_p.h>
22#include <private/qqmltranslation_p.h>
24#include <QtCore/qproperty.h>
34class QQmlPropertyBinding;
35class QQmlScriptString;
39 bool mustCaptureBindableProperty()
const final {
return false;}
41 friend class QQmlPropertyBinding;
42 void expressionChanged() override;
43 QQmlPropertyBinding *asBinding()
45 return const_cast<QQmlPropertyBinding *>(
static_cast<
const QQmlPropertyBindingJS *>(
this)->asBinding());
48 inline QQmlPropertyBinding
const *asBinding()
const;
54 QV4::ReturnedValue evaluate(
bool *isUndefined);
55 QV4::PersistentValue m_boundFunction;
61 friend class QQmlPropertyBindingJS;
63 static constexpr std::size_t jsExpressionOffsetLength() {
64 struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
65 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
66 return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
72 QQmlPropertyBindingJS *jsExpression()
74 return const_cast<QQmlPropertyBindingJS *>(
static_cast<
const QQmlPropertyBinding *>(
this)->jsExpression());
77 QQmlPropertyBindingJS
const *jsExpression()
const
79 return std::launder(
reinterpret_cast<QQmlPropertyBindingJS
const *>(
80 reinterpret_cast<std::byte
const*>(
this)
81 + QPropertyBindingPrivate::getSizeEnsuringAlignment()
82 + jsExpressionOffsetLength()));
85 static QUntypedPropertyBinding create(
const QQmlPropertyData *pd, QV4::Function *function,
86 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
87 QV4::ExecutionContext *scope, QObject *target,
88 QQmlPropertyIndex targetIndex);
89 static QUntypedPropertyBinding create(QMetaType propertyType, QV4::Function *function,
90 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
91 QV4::ExecutionContext *scope, QObject *target,
92 QQmlPropertyIndex targetIndex);
93 static QUntypedPropertyBinding createFromCodeString(
const QQmlPropertyData *property,
94 const QString &str, QObject *obj,
95 const QQmlRefPointer<QQmlContextData> &ctxt,
96 const QString &url, quint16 lineNumber,
97 QObject *target, QQmlPropertyIndex targetIndex);
98 static QUntypedPropertyBinding createFromScriptString(
const QQmlPropertyData *property,
99 const QQmlScriptString& script, QObject *obj,
100 QQmlContext *ctxt, QObject *target,
101 QQmlPropertyIndex targetIndex);
103 static QUntypedPropertyBinding createFromBoundFunction(
const QQmlPropertyData *pd, QV4::BoundFunction *function,
104 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
105 QV4::ExecutionContext *scope, QObject *target,
106 QQmlPropertyIndex targetIndex);
108 static bool isUndefined(
const QUntypedPropertyBinding &binding)
110 return isUndefined(QPropertyBindingPrivate::get(binding));
113 static bool isUndefined(
const QPropertyBindingPrivate *binding)
115 if (!(binding && binding->hasCustomVTable()))
117 return static_cast<
const QQmlPropertyBinding *>(binding)->isUndefined();
120 template<QMetaType::Type type>
121 static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr,
void *f) {
122 auto address =
static_cast<std::byte*>(f);
123 address -= QPropertyBindingPrivate::getSizeEnsuringAlignment();
125 return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
128 bool hasDependencies()
130 return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
134 template <QMetaType::Type type>
135 bool evaluate(QMetaType metaType,
void *dataPtr);
137 Q_NEVER_INLINE
void handleUndefinedAssignment(QQmlEnginePrivate *ep,
void *dataPtr);
139 QString createBindingLoopErrorDescription();
142 enum BoundFunction :
bool {
143 WithoutBoundFunction =
false,
144 HasBoundFunction =
true,
146 TargetData(QObject *target, QQmlPropertyIndex index, BoundFunction state)
147 : target(target), targetIndex(index), hasBoundFunction(state)
150 QQmlPropertyIndex targetIndex;
151 bool hasBoundFunction;
152 bool isUndefined =
false;
154 QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction);
158 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->target;
161 QQmlPropertyIndex targetIndex()
163 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->targetIndex;
166 bool hasBoundFunction()
168 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->hasBoundFunction;
171 bool isUndefined()
const
173 return std::launder(
reinterpret_cast<TargetData
const *>(&declarativeExtraData))->isUndefined;
176 void setIsUndefined(
bool isUndefined)
178 std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->isUndefined = isUndefined;
181 static void bindingErrorCallback(QPropertyBindingPrivate *);
198 [](
void *,
void *){},
205#define FOR_TYPE(TYPE)
206 case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
214 if (type.flags() & QMetaType::PointerToQObject)
215 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
216 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
227 static QUntypedPropertyBinding Q_QML_EXPORT
233inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding()
const
235 return std::launder(
reinterpret_cast<QQmlPropertyBinding
const *>(
236 reinterpret_cast<std::byte
const*>(
this)
237 - QPropertyBindingPrivate::getSizeEnsuringAlignment()
238 - QQmlPropertyBinding::jsExpressionOffsetLength()));
241static_assert(
sizeof(QQmlPropertyBinding) ==
sizeof(QPropertyBindingPrivate));
245 if (*
static_cast<
const T *>(result) == *
static_cast<
const T *>(dataPtr))
247 *
static_cast<T *>(dataPtr) = *
static_cast<
const T *>(result);
251template <QMetaType::Type type>
252bool QQmlPropertyBinding::evaluate(QMetaType metaType,
void *dataPtr)
255 const auto ctxt = jsExpression()->context();
256 QQmlEngine *engine = ctxt ? ctxt->engine() :
nullptr;
258 QPropertyBindingError error(QPropertyBindingError::EvaluationError);
259 if (
auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
260 currentBinding->setError(std::move(error));
263 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
264 ep->referenceScarceResources();
266 const auto handleErrorAndUndefined = [&](
bool evaluatedToUndefined) {
267 ep->dereferenceScarceResources();
268 if (jsExpression()->hasError()) {
269 QPropertyBindingError error(QPropertyBindingError::UnknownError,
270 jsExpression()->delayedError()->error().description());
271 QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
272 bindingErrorCallback(
this);
276 if (evaluatedToUndefined) {
277 handleUndefinedAssignment(ep, dataPtr);
281 }
else if (isUndefined()) {
282 setIsUndefined(
false);
288 if (!hasBoundFunction()) {
289 Q_ASSERT(metaType.sizeOf() > 0);
291 using Tuple = std::tuple<qsizetype,
bool,
bool>;
292 const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
294 case QMetaType::QObjectStar:
return Tuple(
sizeof(QObject *),
false,
false);
295 case QMetaType::Bool:
return Tuple(
sizeof(
bool),
false,
false);
296 case QMetaType::Int:
return Tuple(
sizeof(
int),
false,
false);
297 case QMetaType::Double:
return Tuple(
sizeof(
double),
false,
false);
298 case QMetaType::Float:
return Tuple(
sizeof(
float),
false,
false);
299 case QMetaType::QString:
return Tuple(
sizeof(QString),
true,
true);
301 const auto flags = metaType.flags();
304 flags & QMetaType::NeedsConstruction,
305 flags & QMetaType::NeedsDestruction);
309 Q_ALLOCA_VAR(
void, result, size);
310 if (needsConstruction)
311 metaType.construct(result);
313 const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
314 if (!handleErrorAndUndefined(evaluatedToUndefined))
318 case QMetaType::QObjectStar:
319 return compareAndAssign<QObject *>(dataPtr, result);
320 case QMetaType::Bool:
321 return compareAndAssign<
bool>(dataPtr, result);
323 return compareAndAssign<
int>(dataPtr, result);
324 case QMetaType::Double:
325 return compareAndAssign<
double>(dataPtr, result);
326 case QMetaType::Float:
327 return compareAndAssign<
float>(dataPtr, result);
328 case QMetaType::QString: {
329 const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
330 static_cast<QString *>(result)->~QString();
337 const bool hasChanged = !metaType.equals(result, dataPtr);
339 if (needsDestruction)
340 metaType.destruct(dataPtr);
341 metaType.construct(dataPtr, result);
343 if (needsDestruction)
344 metaType.destruct(result);
348 bool evaluatedToUndefined =
false;
349 QV4::Scope scope(engine->handle());
350 QV4::ScopedValue result(scope,
static_cast<QQmlPropertyBindingJSForBoundFunction *>(
351 jsExpression())->evaluate(&evaluatedToUndefined));
353 if (!handleErrorAndUndefined(evaluatedToUndefined))
357 case QMetaType::Bool: {
359 if (result->isBoolean())
360 b = result->booleanValue();
362 b = result->toBoolean();
363 if (b == *
static_cast<
bool *>(dataPtr))
365 *
static_cast<
bool *>(dataPtr) = b;
368 case QMetaType::Int: {
370 if (result->isInteger())
371 i = result->integerValue();
372 else if (result->isNumber()) {
373 i = QV4::StaticValue::toInteger(result->doubleValue());
377 if (i == *
static_cast<
int *>(dataPtr))
379 *
static_cast<
int *>(dataPtr) = i;
382 case QMetaType::Double:
383 if (result->isNumber()) {
384 double d = result->asDouble();
385 if (d == *
static_cast<
double *>(dataPtr))
387 *
static_cast<
double *>(dataPtr) = d;
391 case QMetaType::Float:
392 if (result->isNumber()) {
393 float d =
float(result->asDouble());
394 if (d == *
static_cast<
float *>(dataPtr))
396 *
static_cast<
float *>(dataPtr) = d;
400 case QMetaType::QString:
401 if (result->isString()) {
402 QString s = result->toQStringNoThrow();
403 if (s == *
static_cast<QString *>(dataPtr))
405 *
static_cast<QString *>(dataPtr) = s;
413 QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
414 resultVariant.convert(metaType);
415 const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
416 metaType.destruct(dataPtr);
417 metaType.construct(dataPtr, resultVariant.constData());
Combined button and popup list for selecting options.
constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static QtPrivate::QPropertyBindingData * bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
auto qQmlTranslationPropertyBindingCreateBinding(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, TranslateWithUnit &&translateWithUnit)
const QtPrivate::BindingFunctionVTable * bindingFunctionVTableForQQmlPropertyBinding(QMetaType type)
bool compareAndAssign(void *dataPtr, const void *result)