5#ifndef QQMLPROPERTYBINDING_P_H
6#define QQMLPROPERTYBINDING_P_H
19#include <private/qqmljavascriptexpression_p.h>
20#include <private/qqmlpropertybindingbase_p.h>
21#include <private/qqmlpropertydata_p.h>
22#include <private/qv4alloca_p.h>
23#include <private/qqmltranslation_p.h>
25#include <QtCore/qproperty.h>
35class QQmlPropertyBinding;
36class QQmlScriptString;
40 bool mustCaptureBindableProperty()
const final {
return false;}
42 friend class QQmlPropertyBinding;
43 void expressionChanged() override;
44 QQmlPropertyBinding *asBinding()
46 return const_cast<QQmlPropertyBinding *>(
static_cast<
const QQmlPropertyBindingJS *>(
this)->asBinding());
49 inline QQmlPropertyBinding
const *asBinding()
const;
55 QV4::ReturnedValue evaluate(
bool *isUndefined);
56 QV4::PersistentValue m_boundFunction;
62 friend class QQmlPropertyBindingJS;
64 static constexpr std::size_t jsExpressionOffsetLength() {
65 struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
66 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
67 return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
73 QQmlPropertyBindingJS *jsExpression()
75 return const_cast<QQmlPropertyBindingJS *>(
static_cast<
const QQmlPropertyBinding *>(
this)->jsExpression());
78 QQmlPropertyBindingJS
const *jsExpression()
const
80 return std::launder(
reinterpret_cast<QQmlPropertyBindingJS
const *>(
81 reinterpret_cast<std::byte
const*>(
this)
82 + QPropertyBindingPrivate::getSizeEnsuringAlignment()
83 + jsExpressionOffsetLength()));
86 static QUntypedPropertyBinding create(
const QQmlPropertyData *pd, QV4::Function *function,
87 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
88 QV4::ExecutionContext *scope, QObject *target,
89 QQmlPropertyIndex targetIndex);
90 static QUntypedPropertyBinding create(QMetaType propertyType, QV4::Function *function,
91 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
92 QV4::ExecutionContext *scope, QObject *target,
93 QQmlPropertyIndex targetIndex);
94 static QUntypedPropertyBinding createFromCodeString(
const QQmlPropertyData *property,
95 const QString &str, QObject *obj,
96 const QQmlRefPointer<QQmlContextData> &ctxt,
97 const QString &url, quint16 lineNumber,
98 QObject *target, QQmlPropertyIndex targetIndex);
99 static QUntypedPropertyBinding createFromScriptString(
const QQmlPropertyData *property,
100 const QQmlScriptString& script, QObject *obj,
101 QQmlContext *ctxt, QObject *target,
102 QQmlPropertyIndex targetIndex);
104 static QUntypedPropertyBinding createFromBoundFunction(
const QQmlPropertyData *pd, QV4::BoundFunction *function,
105 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
106 QV4::ExecutionContext *scope, QObject *target,
107 QQmlPropertyIndex targetIndex);
109 static bool isUndefined(
const QUntypedPropertyBinding &binding)
111 return isUndefined(QPropertyBindingPrivate::get(binding));
114 static bool isUndefined(
const QPropertyBindingPrivate *binding)
116 if (!binding || !binding->isQmlBinding())
118 return static_cast<
const QQmlPropertyBindingBase *>(binding)->isUndefined();
121 template<QMetaType::Type type>
122 static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr,
void *f) {
123 auto address =
static_cast<std::byte*>(f);
124 address -= QPropertyBindingPrivate::getSizeEnsuringAlignment();
126 return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
129 bool hasDependencies()
const
131 return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
135 template <QMetaType::Type type>
136 bool evaluate(QMetaType metaType,
void *dataPtr);
138 Q_NEVER_INLINE
void handleUndefinedAssignment(QQmlEnginePrivate *ep,
void *dataPtr);
140 QString createBindingLoopErrorDescription();
142 QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, HasBoundFunction hasBoundFunction);
144 static QUntypedPropertyBinding makeUntyped(QQmlPropertyBinding *binding)
146 return QPropertyBindingPrivate::makeUntyped(binding);
149 static void bindingErrorCallback(QPropertyBindingPrivate *);
166 [](
void *,
void *){},
173#define FOR_TYPE(TYPE)
174 case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
182 if (type.flags() & QMetaType::PointerToQObject)
183 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
184 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
195 static QUntypedPropertyBinding Q_QML_EXPORT
201inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding()
const
203 return std::launder(
reinterpret_cast<QQmlPropertyBinding
const *>(
204 reinterpret_cast<std::byte
const*>(
this)
205 - QPropertyBindingPrivate::getSizeEnsuringAlignment()
206 - QQmlPropertyBinding::jsExpressionOffsetLength()));
209static_assert(
sizeof(QQmlPropertyBinding) ==
sizeof(QPropertyBindingPrivate));
213 if (*
static_cast<
const T *>(result) == *
static_cast<
const T *>(dataPtr))
215 *
static_cast<T *>(dataPtr) = *
static_cast<
const T *>(result);
219template <QMetaType::Type type>
220bool QQmlPropertyBinding::evaluate(QMetaType metaType,
void *dataPtr)
223 const auto ctxt = jsExpression()->context();
224 QQmlEngine *engine = ctxt ? ctxt->engine() :
nullptr;
226 QPropertyBindingError error(QPropertyBindingError::EvaluationError);
227 if (
auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
228 currentBinding->setError(std::move(error));
231 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
232 ep->referenceScarceResources();
234 const auto handleErrorAndUndefined = [&](
bool evaluatedToUndefined) {
235 ep->dereferenceScarceResources();
236 if (jsExpression()->hasError()) {
237 QPropertyBindingError error(QPropertyBindingError::UnknownError,
238 jsExpression()->delayedError()->error().description());
239 QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
240 bindingErrorCallback(
this);
244 if (evaluatedToUndefined) {
245 handleUndefinedAssignment(ep, dataPtr);
249 }
else if (QQmlPropertyBindingBase::isUndefined()) {
250 setIsUndefined(
false);
256 if (!hasBoundFunction()) {
257 Q_ASSERT(metaType.sizeOf() > 0);
259 using Tuple = std::tuple<qsizetype,
bool,
bool>;
260 const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
262 case QMetaType::QObjectStar:
return Tuple(
sizeof(QObject *),
false,
false);
263 case QMetaType::Bool:
return Tuple(
sizeof(
bool),
false,
false);
264 case QMetaType::Int:
return Tuple(
sizeof(
int),
false,
false);
265 case QMetaType::Double:
return Tuple(
sizeof(
double),
false,
false);
266 case QMetaType::Float:
return Tuple(
sizeof(
float),
false,
false);
267 case QMetaType::QString:
return Tuple(
sizeof(QString),
true,
true);
269 const auto flags = metaType.flags();
272 flags & QMetaType::NeedsConstruction,
273 flags & QMetaType::NeedsDestruction);
277 Q_ALLOCA_VAR(
void, result, size);
278 if (needsConstruction)
279 metaType.construct(result);
281 const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
282 if (!handleErrorAndUndefined(evaluatedToUndefined))
286 case QMetaType::QObjectStar:
287 return compareAndAssign<QObject *>(dataPtr, result);
288 case QMetaType::Bool:
289 return compareAndAssign<
bool>(dataPtr, result);
291 return compareAndAssign<
int>(dataPtr, result);
292 case QMetaType::Double:
293 return compareAndAssign<
double>(dataPtr, result);
294 case QMetaType::Float:
295 return compareAndAssign<
float>(dataPtr, result);
296 case QMetaType::QString: {
297 const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
298 static_cast<QString *>(result)->~QString();
305 const bool hasChanged = !metaType.equals(result, dataPtr);
307 if (needsDestruction)
308 metaType.destruct(dataPtr);
309 metaType.construct(dataPtr, result);
311 if (needsDestruction)
312 metaType.destruct(result);
316 bool evaluatedToUndefined =
false;
317 QV4::Scope scope(engine->handle());
318 QV4::ScopedValue result(scope,
static_cast<QQmlPropertyBindingJSForBoundFunction *>(
319 jsExpression())->evaluate(&evaluatedToUndefined));
321 if (!handleErrorAndUndefined(evaluatedToUndefined))
325 case QMetaType::Bool: {
327 if (result->isBoolean())
328 b = result->booleanValue();
330 b = result->toBoolean();
331 if (b == *
static_cast<
bool *>(dataPtr))
333 *
static_cast<
bool *>(dataPtr) = b;
336 case QMetaType::Int: {
338 if (result->isInteger())
339 i = result->integerValue();
340 else if (result->isNumber()) {
341 i = QV4::StaticValue::toInteger(result->doubleValue());
345 if (i == *
static_cast<
int *>(dataPtr))
347 *
static_cast<
int *>(dataPtr) = i;
350 case QMetaType::Double:
351 if (result->isNumber()) {
352 double d = result->asDouble();
353 if (d == *
static_cast<
double *>(dataPtr))
355 *
static_cast<
double *>(dataPtr) = d;
359 case QMetaType::Float:
360 if (result->isNumber()) {
361 float d =
float(result->asDouble());
362 if (d == *
static_cast<
float *>(dataPtr))
364 *
static_cast<
float *>(dataPtr) = d;
368 case QMetaType::QString:
369 if (result->isString()) {
370 QString s = result->toQStringNoThrow();
371 if (s == *
static_cast<QString *>(dataPtr))
373 *
static_cast<QString *>(dataPtr) = s;
381 QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
382 resultVariant.convert(metaType);
383 const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
384 metaType.destruct(dataPtr);
385 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)