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)
254 const auto ctxt = jsExpression()->context();
255 QQmlEngine *engine = ctxt ? ctxt->engine() :
nullptr;
257 QPropertyBindingError error(QPropertyBindingError::EvaluationError);
258 if (
auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
259 currentBinding->setError(std::move(error));
262 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
263 ep->referenceScarceResources();
265 const auto handleErrorAndUndefined = [&](
bool evaluatedToUndefined) {
266 ep->dereferenceScarceResources();
267 if (jsExpression()->hasError()) {
268 QPropertyBindingError error(QPropertyBindingError::UnknownError,
269 jsExpression()->delayedError()->error().description());
270 QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
271 bindingErrorCallback(
this);
275 if (evaluatedToUndefined) {
276 handleUndefinedAssignment(ep, dataPtr);
280 }
else if (isUndefined()) {
281 setIsUndefined(
false);
287 if (!hasBoundFunction()) {
288 Q_ASSERT(metaType.sizeOf() > 0);
290 using Tuple = std::tuple<qsizetype,
bool,
bool>;
291 const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
293 case QMetaType::QObjectStar:
return Tuple(
sizeof(QObject *),
false,
false);
294 case QMetaType::Bool:
return Tuple(
sizeof(
bool),
false,
false);
295 case QMetaType::Int:
return Tuple(
sizeof(
int),
false,
false);
296 case QMetaType::Double:
return Tuple(
sizeof(
double),
false,
false);
297 case QMetaType::Float:
return Tuple(
sizeof(
float),
false,
false);
298 case QMetaType::QString:
return Tuple(
sizeof(QString),
true,
true);
300 const auto flags = metaType.flags();
303 flags & QMetaType::NeedsConstruction,
304 flags & QMetaType::NeedsDestruction);
308 Q_ALLOCA_VAR(
void, result, size);
309 if (needsConstruction)
310 metaType.construct(result);
312 const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
313 if (!handleErrorAndUndefined(evaluatedToUndefined))
317 case QMetaType::QObjectStar:
318 return compareAndAssign<QObject *>(dataPtr, result);
319 case QMetaType::Bool:
320 return compareAndAssign<
bool>(dataPtr, result);
322 return compareAndAssign<
int>(dataPtr, result);
323 case QMetaType::Double:
324 return compareAndAssign<
double>(dataPtr, result);
325 case QMetaType::Float:
326 return compareAndAssign<
float>(dataPtr, result);
327 case QMetaType::QString: {
328 const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
329 static_cast<QString *>(result)->~QString();
336 const bool hasChanged = !metaType.equals(result, dataPtr);
338 if (needsDestruction)
339 metaType.destruct(dataPtr);
340 metaType.construct(dataPtr, result);
342 if (needsDestruction)
343 metaType.destruct(result);
347 bool evaluatedToUndefined =
false;
348 QV4::Scope scope(engine->handle());
349 QV4::ScopedValue result(scope,
static_cast<QQmlPropertyBindingJSForBoundFunction *>(
350 jsExpression())->evaluate(&evaluatedToUndefined));
352 if (!handleErrorAndUndefined(evaluatedToUndefined))
356 case QMetaType::Bool: {
358 if (result->isBoolean())
359 b = result->booleanValue();
361 b = result->toBoolean();
362 if (b == *
static_cast<
bool *>(dataPtr))
364 *
static_cast<
bool *>(dataPtr) = b;
367 case QMetaType::Int: {
369 if (result->isInteger())
370 i = result->integerValue();
371 else if (result->isNumber()) {
372 i = QV4::StaticValue::toInteger(result->doubleValue());
376 if (i == *
static_cast<
int *>(dataPtr))
378 *
static_cast<
int *>(dataPtr) = i;
381 case QMetaType::Double:
382 if (result->isNumber()) {
383 double d = result->asDouble();
384 if (d == *
static_cast<
double *>(dataPtr))
386 *
static_cast<
double *>(dataPtr) = d;
390 case QMetaType::Float:
391 if (result->isNumber()) {
392 float d =
float(result->asDouble());
393 if (d == *
static_cast<
float *>(dataPtr))
395 *
static_cast<
float *>(dataPtr) = d;
399 case QMetaType::QString:
400 if (result->isString()) {
401 QString s = result->toQStringNoThrow();
402 if (s == *
static_cast<QString *>(dataPtr))
404 *
static_cast<QString *>(dataPtr) = s;
412 QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
413 resultVariant.convert(metaType);
414 const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
415 metaType.destruct(dataPtr);
416 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)