Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qjsprimitivevalue.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJSPRIMITIVEVALUE_H
5#define QJSPRIMITIVEVALUE_H
6
7#include <QtQml/qtqmlglobal.h>
8#include <QtQml/qjsnumbercoercion.h>
9
10#include <QtCore/qstring.h>
11#include <QtCore/qnumeric.h>
12#include <QtCore/qvariant.h>
13
14#include <variant>
15#include <cmath>
16
18
19namespace QV4 { struct ExecutionEngine; }
20
23
25{
26 template<typename Concrete>
27 struct StringNaNOperators
28 {
29 static constexpr double op(const QString &, QJSPrimitiveUndefined)
30 {
31 return std::numeric_limits<double>::quiet_NaN();
32 }
33
34 static constexpr double op(QJSPrimitiveUndefined, const QString &)
35 {
36 return std::numeric_limits<double>::quiet_NaN();
37 }
38
39 static double op(const QString &lhs, QJSPrimitiveNull) { return op(lhs, 0); }
40 static double op(QJSPrimitiveNull, const QString &rhs) { return op(0, rhs); }
41
42 template<typename T>
43 static double op(const QString &lhs, T rhs)
44 {
45 return Concrete::op(fromString(lhs).toDouble(), rhs);
46 }
47
48 template<typename T>
49 static double op(T lhs, const QString &rhs)
50 {
51 return Concrete::op(lhs, fromString(rhs).toDouble());
52 }
53
54 static double op(const QString &lhs, const QString &rhs)
55 {
56 return Concrete::op(fromString(lhs).toDouble(), fromString(rhs).toDouble());
57 }
58 };
59
60 struct AddOperators {
61 static constexpr double op(double lhs, double rhs) { return lhs + rhs; }
62 static bool opOverflow(int lhs, int rhs, int *result)
63 {
64 return qAddOverflow(lhs, rhs, result);
65 }
66
67 template<typename T>
68 static QString op(const QString &lhs, T rhs)
69 {
70 return lhs + QJSPrimitiveValue(rhs).toString();
71 }
72
73 template<typename T>
74 static QString op(T lhs, const QString &rhs)
75 {
76 return QJSPrimitiveValue(lhs).toString() + rhs;
77 }
78
79 static QString op(const QString &lhs, const QString &rhs) { return lhs + rhs; }
80 };
81
82 struct SubOperators : private StringNaNOperators<SubOperators> {
83 static constexpr double op(double lhs, double rhs) { return lhs - rhs; }
84 static bool opOverflow(int lhs, int rhs, int *result)
85 {
86 return qSubOverflow(lhs, rhs, result);
87 }
88
89 using StringNaNOperators::op;
90 };
91
92 struct MulOperators : private StringNaNOperators<MulOperators> {
93 static constexpr double op(double lhs, double rhs) { return lhs * rhs; }
94 static bool opOverflow(int lhs, int rhs, int *result)
95 {
96 // compare mul_int32 in qv4math_p.h
97 auto hadOverflow = qMulOverflow(lhs, rhs, result);
98 if (((lhs < 0) ^ (rhs < 0)) && (*result == 0))
99 return true; // result must be negative 0, does not fit into int
100 return hadOverflow;
101 }
102
103 using StringNaNOperators::op;
104 };
105
106 struct DivOperators : private StringNaNOperators<DivOperators> {
107 static constexpr double op(double lhs, double rhs) { return lhs / rhs; }
108 static constexpr bool opOverflow(int, int, int *)
109 {
110 return true;
111 }
112
113 using StringNaNOperators::op;
114 };
115
116public:
125
126 constexpr Type type() const { return Type(d.type()); }
127
128 // Prevent casting from Type to int
130
131 Q_IMPLICIT constexpr QJSPrimitiveValue() noexcept = default;
132 Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveUndefined undefined) noexcept : d(undefined) {}
133 Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveNull null) noexcept : d(null) {}
134 Q_IMPLICIT constexpr QJSPrimitiveValue(bool value) noexcept : d(value) {}
135 Q_IMPLICIT constexpr QJSPrimitiveValue(int value) noexcept : d(value) {}
136 Q_IMPLICIT constexpr QJSPrimitiveValue(double value) noexcept : d(value) {}
137 Q_IMPLICIT QJSPrimitiveValue(QString string) noexcept : d(std::move(string)) {}
138
139 explicit QJSPrimitiveValue(const QMetaType type, const void *value) noexcept
140 {
141 switch (type.id()) {
144 break;
145 case QMetaType::Nullptr:
146 d = QJSPrimitiveNull();
147 break;
148 case QMetaType::Bool:
149 d = *static_cast<const bool *>(value);
150 break;
151 case QMetaType::Int:
152 d = *static_cast<const int *>(value);
153 break;
154 case QMetaType::Double:
155 d = *static_cast<const double *>(value);
156 break;
157 case QMetaType::QString:
158 d = *static_cast<const QString *>(value);
159 break;
160 default:
161 // Unsupported. Remains undefined.
162 break;
163 }
164 }
165
167 {
168 switch (type.id()) {
171 break;
172 case QMetaType::Nullptr:
173 d = QJSPrimitiveNull();
174 break;
175 case QMetaType::Bool:
176 d = false;
177 break;
178 case QMetaType::Int:
179 d = 0;
180 break;
181 case QMetaType::Double:
182 d = 0.0;
183 break;
184 case QMetaType::QString:
185 d = QString();
186 break;
187 default:
188 // Unsupported. Remains undefined.
189 break;
190 }
191 }
192
193 explicit QJSPrimitiveValue(const QVariant &variant) noexcept
195 {
196 }
197
198 constexpr QMetaType metaType() const { return d.metaType(); }
199 constexpr void *data() { return d.data(); }
200 constexpr const void *data() const { return d.data(); }
201 constexpr const void *constData() const { return d.data(); }
202
203 template<Type type>
205 if constexpr (type == Undefined)
206 return QJSPrimitiveUndefined();
207 if constexpr (type == Null)
208 return QJSPrimitiveNull();
209 if constexpr (type == Boolean)
210 return toBoolean();
211 if constexpr (type == Integer)
212 return toInteger();
213 if constexpr (type == Double)
214 return toDouble();
215 if constexpr (type == String)
216 return toString();
217
218 Q_UNREACHABLE_RETURN(QJSPrimitiveUndefined());
219 }
220
221 constexpr bool toBoolean() const
222 {
223 switch (type()) {
224 case Undefined: return false;
225 case Null: return false;
226 case Boolean: return asBoolean();
227 case Integer: return asInteger() != 0;
228 case Double: {
229 const double v = asDouble();
230 return !QJSNumberCoercion::equals(v, 0) && !std::isnan(v);
231 }
232 case String: return !asString().isEmpty();
233 }
234
235 // GCC 8.x does not treat __builtin_unreachable() as constexpr
236 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
237 Q_UNREACHABLE_RETURN(false);
238 #else
239 return false;
240 #endif
241 }
242
243 constexpr int toInteger() const
244 {
245 switch (type()) {
246 case Undefined: return 0;
247 case Null: return 0;
248 case Boolean: return asBoolean();
249 case Integer: return asInteger();
250 case Double: return QJSNumberCoercion::toInteger(asDouble());
251 case String: return fromString(asString()).toInteger();
252 }
253
254 // GCC 8.x does not treat __builtin_unreachable() as constexpr
255 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
256 Q_UNREACHABLE_RETURN(0);
257 #else
258 return 0;
259 #endif
260 }
261
262 constexpr double toDouble() const
263 {
264 switch (type()) {
265 case Undefined: return std::numeric_limits<double>::quiet_NaN();
266 case Null: return 0;
267 case Boolean: return asBoolean();
268 case Integer: return asInteger();
269 case Double: return asDouble();
270 case String: return fromString(asString()).toDouble();
271 }
272
273 // GCC 8.x does not treat __builtin_unreachable() as constexpr
274 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
275 Q_UNREACHABLE_RETURN({});
276 #else
277 return {};
278 #endif
279 }
280
282 {
283 switch (type()) {
284 case Undefined: return QStringLiteral("undefined");
285 case Null: return QStringLiteral("null");
286 case Boolean: return asBoolean() ? QStringLiteral("true") : QStringLiteral("false");
287 case Integer: return QString::number(asInteger());
288 case Double: {
289 const double result = asDouble();
290 if (std::isnan(result))
291 return QStringLiteral("NaN");
292 if (std::isfinite(result))
293 return toString(result);
294 if (result > 0)
295 return QStringLiteral("Infinity");
296 return QStringLiteral("-Infinity");
297 }
298 case String: return asString();
299 }
300
301 Q_UNREACHABLE_RETURN(QString());
302 }
303
305 {
306 switch (type()) {
307 case Undefined: return QVariant();
308 case Null: return QVariant::fromValue<std::nullptr_t>(nullptr);
309 case Boolean: return QVariant(asBoolean());
310 case Integer: return QVariant(asInteger());
311 case Double: return QVariant(asDouble());
312 case String: return QVariant(asString());
313 }
314
315 Q_UNREACHABLE_RETURN(QVariant());
316 }
317
319 const QJSPrimitiveValue &rhs)
320 {
321 return operate<AddOperators>(lhs, rhs);
322 }
323
325 const QJSPrimitiveValue &rhs)
326 {
327 return operate<SubOperators>(lhs, rhs);
328 }
329
331 const QJSPrimitiveValue &rhs)
332 {
333 return operate<MulOperators>(lhs, rhs);
334 }
335
337 const QJSPrimitiveValue &rhs)
338 {
339 return operate<DivOperators>(lhs, rhs);
340 }
341
343 const QJSPrimitiveValue &rhs)
344 {
345 switch (lhs.type()) {
346 case Null:
347 case Boolean:
348 case Integer:
349 switch (rhs.type()) {
350 case Boolean:
351 case Integer: {
352 const int leftInt = lhs.toInteger();
353 const int rightInt = rhs.toInteger();
354 if (leftInt >= 0 && rightInt > 0)
355 return leftInt % rightInt;
357 }
358 case Undefined:
359 case Null:
360 case Double:
361 case String:
362 break;
363 }
365 case Undefined:
366 case Double:
367 case String:
368 break;
369 }
370
371 return std::fmod(lhs.toDouble(), rhs.toDouble());
372 }
373
375 {
376 // ++a is modeled as a -= (-1) to avoid the potential string concatenation
377 return (*this = operate<SubOperators>(*this, -1));
378 }
379
381 {
382 // a++ is modeled as a -= (-1) to avoid the potential string concatenation
383 QJSPrimitiveValue other = operate<SubOperators>(*this, -1);
384 std::swap(other, *this);
385 return +other; // We still need to coerce the original value.
386 }
387
389 {
390 return (*this = operate<SubOperators>(*this, 1));
391 }
392
394 {
395 QJSPrimitiveValue other = operate<SubOperators>(*this, 1);
396 std::swap(other, *this);
397 return +other; // We still need to coerce the original value.
398 }
399
401 {
402 // +a is modeled as a -= 0. That should force it to number.
403 return (*this = operate<SubOperators>(*this, 0));
404 }
405
407 {
408 return (*this = operate<MulOperators>(*this, -1));
409 }
410
411 constexpr bool strictlyEquals(const QJSPrimitiveValue &other) const
412 {
413 const Type myType = type();
414 const Type otherType = other.type();
415
416 if (myType != otherType) {
417 // int -> double promotion is OK in strict mode
418 if (myType == Double && otherType == Integer)
419 return strictlyEquals(double(other.asInteger()));
420 if (myType == Integer && otherType == Double)
421 return QJSPrimitiveValue(double(asInteger())).strictlyEquals(other);
422 return false;
423 }
424
425 switch (myType) {
426 case Undefined:
427 case Null:
428 return true;
429 case Boolean:
430 return asBoolean() == other.asBoolean();
431 case Integer:
432 return asInteger() == other.asInteger();
433 case Double: {
434 const double l = asDouble();
435 const double r = other.asDouble();
436 if (std::isnan(l) || std::isnan(r))
437 return false;
438 if (qIsNull(l) && qIsNull(r))
439 return true;
440 return QJSNumberCoercion::equals(l, r);
441 }
442 case String:
443 return asString() == other.asString();
444 }
445
446 return false;
447 }
448
449 // Loose operator==, in contrast to strict ===
450 constexpr bool equals(const QJSPrimitiveValue &other) const
451 {
452 const Type myType = type();
453 const Type otherType = other.type();
454
455 if (myType == otherType)
456 return strictlyEquals(other);
457
458 switch (myType) {
459 case Undefined:
460 return otherType == Null;
461 case Null:
462 return otherType == Undefined;
463 case Boolean:
464 return QJSPrimitiveValue(int(asBoolean())).equals(other);
465 case Integer:
466 // prefer rhs bool -> int promotion over promoting both to double
467 return otherType == Boolean
468 ? QJSPrimitiveValue(asInteger()).equals(int(other.asBoolean()))
469 : QJSPrimitiveValue(double(asInteger())).equals(other);
470 case Double:
471 // Promote the other side to double (or recognize lhs as undefined/null)
472 return other.equals(*this);
473 case String:
474 return fromString(asString()).parsedEquals(other);
475 }
476
477 return false;
478 }
479
480 friend constexpr inline bool operator==(const QJSPrimitiveValue &lhs, const
482 {
483 return lhs.strictlyEquals(rhs);
484 }
485
486 friend constexpr inline bool operator!=(const QJSPrimitiveValue &lhs,
487 const QJSPrimitiveValue &rhs)
488 {
489 return !lhs.strictlyEquals(rhs);
490 }
491
492 friend constexpr inline bool operator<(const QJSPrimitiveValue &lhs,
493 const QJSPrimitiveValue &rhs)
494 {
495 switch (lhs.type()) {
496 case Undefined:
497 return false;
498 case Null: {
499 switch (rhs.type()) {
500 case Undefined: return false;
501 case Null: return false;
502 case Boolean: return 0 < int(rhs.asBoolean());
503 case Integer: return 0 < rhs.asInteger();
504 case Double: return double(0) < rhs.asDouble();
505 case String: return double(0) < rhs.toDouble();
506 }
507 break;
508 }
509 case Boolean: {
510 switch (rhs.type()) {
511 case Undefined: return false;
512 case Null: return int(lhs.asBoolean()) < 0;
513 case Boolean: return lhs.asBoolean() < rhs.asBoolean();
514 case Integer: return int(lhs.asBoolean()) < rhs.asInteger();
515 case Double: return double(lhs.asBoolean()) < rhs.asDouble();
516 case String: return double(lhs.asBoolean()) < rhs.toDouble();
517 }
518 break;
519 }
520 case Integer: {
521 switch (rhs.type()) {
522 case Undefined: return false;
523 case Null: return lhs.asInteger() < 0;
524 case Boolean: return lhs.asInteger() < int(rhs.asBoolean());
525 case Integer: return lhs.asInteger() < rhs.asInteger();
526 case Double: return double(lhs.asInteger()) < rhs.asDouble();
527 case String: return double(lhs.asInteger()) < rhs.toDouble();
528 }
529 break;
530 }
531 case Double: {
532 switch (rhs.type()) {
533 case Undefined: return false;
534 case Null: return lhs.asDouble() < double(0);
535 case Boolean: return lhs.asDouble() < double(rhs.asBoolean());
536 case Integer: return lhs.asDouble() < double(rhs.asInteger());
537 case Double: return lhs.asDouble() < rhs.asDouble();
538 case String: return lhs.asDouble() < rhs.toDouble();
539 }
540 break;
541 }
542 case String: {
543 switch (rhs.type()) {
544 case Undefined: return false;
545 case Null: return lhs.toDouble() < double(0);
546 case Boolean: return lhs.toDouble() < double(rhs.asBoolean());
547 case Integer: return lhs.toDouble() < double(rhs.asInteger());
548 case Double: return lhs.toDouble() < rhs.asDouble();
549 case String: return lhs.asString() < rhs.asString();
550 }
551 break;
552 }
553 }
554
555 return false;
556 }
557
558 friend constexpr inline bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
559 {
560 return rhs < lhs;
561 }
562
563 friend constexpr inline bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
564 {
565 if (lhs.type() == String) {
566 if (rhs.type() == String)
567 return lhs.asString() <= rhs.asString();
568 else
569 return fromString(lhs.asString()) <= rhs;
570 }
571 if (rhs.type() == String)
572 return lhs <= fromString(rhs.asString());
573
574 if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
575 return false;
576 return !(lhs > rhs);
577 }
578
579 friend constexpr inline bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
580 {
581 if (lhs.type() == String) {
582 if (rhs.type() == String)
583 return lhs.asString() >= rhs.asString();
584 else
585 return fromString(lhs.asString()) >= rhs;
586 }
587 if (rhs.type() == String)
588 return lhs >= fromString(rhs.asString());
589
590 if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
591 return false;
592 return !(lhs < rhs);
593 }
594
595private:
596 friend class QJSManagedValue;
597 friend class QJSValue;
598 friend struct QV4::ExecutionEngine;
599
600 constexpr bool asBoolean() const { return d.getBool(); }
601 constexpr int asInteger() const { return d.getInt(); }
602 constexpr double asDouble() const { return d.getDouble(); }
603 QString asString() const { return d.getString(); }
604
605 constexpr bool parsedEquals(const QJSPrimitiveValue &other) const
606 {
607 return type() != Undefined && equals(other);
608 }
609
610 static QJSPrimitiveValue fromString(const QString &string)
611 {
612 bool ok;
613 const int intValue = string.toInt(&ok);
614 if (ok)
615 return intValue;
616
617 const double doubleValue = string.toDouble(&ok);
618 if (ok)
619 return doubleValue;
620 if (string == QStringLiteral("Infinity"))
621 return std::numeric_limits<double>::infinity();
622 if (string == QStringLiteral("-Infinity"))
623 return -std::numeric_limits<double>::infinity();
624 if (string == QStringLiteral("NaN"))
625 return std::numeric_limits<double>::quiet_NaN();
626 return QJSPrimitiveUndefined();
627 }
628
629 static Q_QML_EXPORT QString toString(double d);
630
631 template<typename Operators, typename Lhs, typename Rhs>
632 static QJSPrimitiveValue operateOnIntegers(const QJSPrimitiveValue &lhs,
633 const QJSPrimitiveValue &rhs)
634 {
635 int result;
636 if (Operators::opOverflow(lhs.d.get<Lhs>(), rhs.d.get<Rhs>(), &result))
637 return Operators::op(lhs.d.get<Lhs>(), rhs.d.get<Rhs>());
638 return result;
639 }
640
641 template<typename Operators>
642 static QJSPrimitiveValue operate(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
643 {
644 switch (lhs.type()) {
645 case Undefined:
646 switch (rhs.type()) {
647 case Undefined: return std::numeric_limits<double>::quiet_NaN();
648 case Null: return std::numeric_limits<double>::quiet_NaN();
649 case Boolean: return std::numeric_limits<double>::quiet_NaN();
650 case Integer: return std::numeric_limits<double>::quiet_NaN();
651 case Double: return std::numeric_limits<double>::quiet_NaN();
652 case String: return Operators::op(QJSPrimitiveUndefined(), rhs.asString());
653 }
654 break;
655 case Null:
656 switch (rhs.type()) {
657 case Undefined: return std::numeric_limits<double>::quiet_NaN();
658 case Null: return operateOnIntegers<Operators, int, int>(0, 0);
659 case Boolean: return operateOnIntegers<Operators, int, bool>(0, rhs);
660 case Integer: return operateOnIntegers<Operators, int, int>(0, rhs);
661 case Double: return Operators::op(0, rhs.asDouble());
662 case String: return Operators::op(QJSPrimitiveNull(), rhs.asString());
663 }
664 break;
665 case Boolean:
666 switch (rhs.type()) {
667 case Undefined: return std::numeric_limits<double>::quiet_NaN();
668 case Null: return operateOnIntegers<Operators, bool, int>(lhs, 0);
669 case Boolean: return operateOnIntegers<Operators, bool, bool>(lhs, rhs);
670 case Integer: return operateOnIntegers<Operators, bool, int>(lhs, rhs);
671 case Double: return Operators::op(lhs.asBoolean(), rhs.asDouble());
672 case String: return Operators::op(lhs.asBoolean(), rhs.asString());
673 }
674 break;
675 case Integer:
676 switch (rhs.type()) {
677 case Undefined: return std::numeric_limits<double>::quiet_NaN();
678 case Null: return operateOnIntegers<Operators, int, int>(lhs, 0);
679 case Boolean: return operateOnIntegers<Operators, int, bool>(lhs, rhs);
680 case Integer: return operateOnIntegers<Operators, int, int>(lhs, rhs);
681 case Double: return Operators::op(lhs.asInteger(), rhs.asDouble());
682 case String: return Operators::op(lhs.asInteger(), rhs.asString());
683 }
684 break;
685 case Double:
686 switch (rhs.type()) {
687 case Undefined: return std::numeric_limits<double>::quiet_NaN();
688 case Null: return Operators::op(lhs.asDouble(), 0);
689 case Boolean: return Operators::op(lhs.asDouble(), rhs.asBoolean());
690 case Integer: return Operators::op(lhs.asDouble(), rhs.asInteger());
691 case Double: return Operators::op(lhs.asDouble(), rhs.asDouble());
692 case String: return Operators::op(lhs.asDouble(), rhs.asString());
693 }
694 break;
695 case String:
696 switch (rhs.type()) {
697 case Undefined: return Operators::op(lhs.asString(), QJSPrimitiveUndefined());
698 case Null: return Operators::op(lhs.asString(), QJSPrimitiveNull());
699 case Boolean: return Operators::op(lhs.asString(), rhs.asBoolean());
700 case Integer: return Operators::op(lhs.asString(), rhs.asInteger());
701 case Double: return Operators::op(lhs.asString(), rhs.asDouble());
702 case String: return Operators::op(lhs.asString(), rhs.asString());
703 }
704 break;
705 }
706
707 Q_UNREACHABLE_RETURN(QJSPrimitiveUndefined());
708 }
709
710 constexpr bool isNanOrUndefined() const
711 {
712 switch (type()) {
713 case Undefined: return true;
714 case Null: return false;
715 case Boolean: return false;
716 case Integer: return false;
717 case Double: return std::isnan(asDouble());
718 case String: return false;
719 }
720 // GCC 8.x does not treat __builtin_unreachable() as constexpr
721 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
722 Q_UNREACHABLE_RETURN(false);
723 #else
724 return false;
725 #endif
726 }
727
728 struct QJSPrimitiveValuePrivate
729 {
730 // Can't be default because QString has a non-trivial ctor.
731 constexpr QJSPrimitiveValuePrivate() noexcept {}
732
733 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveUndefined) noexcept {}
734 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveNull) noexcept
735 : m_type(Null) {}
736 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(bool b) noexcept
737 : m_bool(b), m_type(Boolean) {}
738 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(int i) noexcept
739 : m_int(i), m_type(Integer) {}
740 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(double d) noexcept
741 : m_double(d), m_type(Double) {}
742 Q_IMPLICIT QJSPrimitiveValuePrivate(QString s) noexcept
743 : m_string(std::move(s)), m_type(String) {}
744
745 constexpr QJSPrimitiveValuePrivate(const QJSPrimitiveValuePrivate &other) noexcept
746 : m_type(other.m_type)
747 {
748 // Not copy-and-swap since swap() would be much more complicated.
749 if (!assignSimple(other))
750 new (&m_string) QString(other.m_string);
751 }
752
753 constexpr QJSPrimitiveValuePrivate(QJSPrimitiveValuePrivate &&other) noexcept
754 : m_type(other.m_type)
755 {
756 // Not move-and-swap since swap() would be much more complicated.
757 if (!assignSimple(other))
758 new (&m_string) QString(std::move(other.m_string));
759 }
760
761 constexpr QJSPrimitiveValuePrivate &operator=(const QJSPrimitiveValuePrivate &other) noexcept
762 {
763 if (this == &other)
764 return *this;
765
766 if (m_type == String) {
767 if (other.m_type == String) {
768 m_type = other.m_type;
769 m_string = other.m_string;
770 return *this;
771 }
772 m_string.~QString();
773 }
774
775 m_type = other.m_type;
776 if (!assignSimple(other))
777 new (&m_string) QString(other.m_string);
778 return *this;
779 }
780
781 constexpr QJSPrimitiveValuePrivate &operator=(QJSPrimitiveValuePrivate &&other) noexcept
782 {
783 if (this == &other)
784 return *this;
785
786 if (m_type == String) {
787 if (other.m_type == String) {
788 m_type = other.m_type;
789 m_string = std::move(other.m_string);
790 return *this;
791 }
792 m_string.~QString();
793 }
794
795 m_type = other.m_type;
796 if (!assignSimple(other))
797 new (&m_string) QString(std::move(other.m_string));
798 return *this;
799 }
800
801 ~QJSPrimitiveValuePrivate()
802 {
803 if (m_type == String)
804 m_string.~QString();
805 }
806
807 constexpr Type type() const noexcept { return m_type; }
808 constexpr bool getBool() const noexcept { return m_bool; }
809 constexpr int getInt() const noexcept { return m_int; }
810 constexpr double getDouble() const noexcept { return m_double; }
811 QString getString() const noexcept { return m_string; }
812
813 template<typename T>
814 constexpr T get() const noexcept {
815 if constexpr (std::is_same_v<T, QJSPrimitiveUndefined>)
816 return QJSPrimitiveUndefined();
817 else if constexpr (std::is_same_v<T, QJSPrimitiveNull>)
818 return QJSPrimitiveNull();
819 else if constexpr (std::is_same_v<T, bool>)
820 return getBool();
821 else if constexpr (std::is_same_v<T, int>)
822 return getInt();
823 else if constexpr (std::is_same_v<T, double>)
824 return getDouble();
825 else if constexpr (std::is_same_v<T, QString>)
826 return getString();
827
828 // GCC 8.x does not treat __builtin_unreachable() as constexpr
829 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
830 Q_UNREACHABLE_RETURN(T());
831 #else
832 return T();
833 #endif
834 }
835
836 constexpr QMetaType metaType() const noexcept {
837 switch (m_type) {
838 case Undefined:
839 return QMetaType();
840 case Null:
841 return QMetaType::fromType<std::nullptr_t>();
842 case Boolean:
843 return QMetaType::fromType<bool>();
844 case Integer:
845 return QMetaType::fromType<int>();
846 case Double:
847 return QMetaType::fromType<double>();
848 case String:
849 return QMetaType::fromType<QString>();
850 }
851
852 // GCC 8.x does not treat __builtin_unreachable() as constexpr
853 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
854 Q_UNREACHABLE_RETURN(QMetaType());
855 #else
856 return QMetaType();
857 #endif
858 }
859
860 constexpr void *data() noexcept {
861 switch (m_type) {
862 case Undefined:
863 case Null:
864 return nullptr;
865 case Boolean:
866 return &m_bool;
867 case Integer:
868 return &m_int;
869 case Double:
870 return &m_double;
871 case String:
872 return &m_string;
873 }
874
875 // GCC 8.x does not treat __builtin_unreachable() as constexpr
876 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
877 Q_UNREACHABLE_RETURN(nullptr);
878 #else
879 return nullptr;
880 #endif
881 }
882
883 constexpr const void *data() const noexcept {
884 switch (m_type) {
885 case Undefined:
886 case Null:
887 return nullptr;
888 case Boolean:
889 return &m_bool;
890 case Integer:
891 return &m_int;
892 case Double:
893 return &m_double;
894 case String:
895 return &m_string;
896 }
897
898 // GCC 8.x does not treat __builtin_unreachable() as constexpr
899 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
900 Q_UNREACHABLE_RETURN(nullptr);
901 #else
902 return nullptr;
903 #endif
904 }
905
906 private:
907 constexpr bool assignSimple(const QJSPrimitiveValuePrivate &other) noexcept
908 {
909 switch (other.m_type) {
910 case Undefined:
911 case Null:
912 return true;
913 case Boolean:
914 m_bool = other.m_bool;
915 return true;
916 case Integer:
917 m_int = other.m_int;
918 return true;
919 case Double:
920 m_double = other.m_double;
921 return true;
922 case String:
923 return false;
924 }
925
926 // GCC 8.x does not treat __builtin_unreachable() as constexpr
927 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
928 Q_UNREACHABLE_RETURN(false);
929 #else
930 return false;
931 #endif
932 }
933
934 union {
935 bool m_bool = false;
936 int m_int;
937 double m_double;
938 QString m_string;
939 };
940
941 Type m_type = Undefined;
942 };
943
944 QJSPrimitiveValuePrivate d;
945};
946
947namespace QQmlPrivate {
948 // TODO: Make this constexpr once std::isnan is constexpr.
949 inline double jsExponentiate(double base, double exponent)
950 {
951 constexpr double qNaN = std::numeric_limits<double>::quiet_NaN();
952 constexpr double inf = std::numeric_limits<double>::infinity();
953
954 if (qIsNull(exponent))
955 return 1.0;
956
957 if (std::isnan(exponent))
958 return qNaN;
959
961 return std::isinf(exponent) ? qNaN : std::pow(base, exponent);
962
963 if (!qIsNull(base))
964 return std::pow(base, exponent);
965
966 if (std::copysign(1.0, base) > 0.0)
967 return exponent < 0.0 ? inf : std::pow(base, exponent);
968
969 if (exponent < 0.0)
970 return QJSNumberCoercion::equals(std::fmod(-exponent, 2.0), 1.0) ? -inf : inf;
971
972 return QJSNumberCoercion::equals(std::fmod(exponent, 2.0), 1.0)
973 ? std::copysign(0, -1.0)
974 : 0.0;
975 }
976}
977
979
980#endif // QJSPRIMITIVEVALUE_H
\inmodule QtQml
static constexpr bool equals(double lhs, double rhs)
The QJSPrimitiveValue class operates on primitive types in JavaScript semantics.
friend QJSPrimitiveValue operator+(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
friend QJSPrimitiveValue operator*(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
constexpr void * data()
QJSPrimitiveValue(Type)=delete
constexpr QMetaType metaType() const
friend constexpr bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
Q_IMPLICIT constexpr QJSPrimitiveValue(bool value) noexcept
Creates a QJSPrimitiveValue of value value and type Boolean.
friend constexpr bool operator!=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
QJSPrimitiveValue(QMetaType type) noexcept
Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveNull null) noexcept
Creates a QJSPrimitiveValue of value null and type Null.
constexpr const void * data() const
friend constexpr bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
QJSPrimitiveValue operator++(int)
QJSPrimitiveValue operator+()
QVariant toVariant() const
friend QJSPrimitiveValue operator-(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
QJSPrimitiveValue(const QVariant &variant) noexcept
Creates a QJSPrimitiveValue from the contents of value if those contents can be stored in QJSPrimtive...
QJSPrimitiveValue operator--(int)
Q_IMPLICIT constexpr QJSPrimitiveValue(int value) noexcept
Creates a QJSPrimitiveValue of value value and type Integer.
friend constexpr bool operator<(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
constexpr const void * constData() const
constexpr double toDouble() const
Returns the value coerced to a JavaScript Number by JavaScript rules.
QJSPrimitiveValue to() const
constexpr Type type() const
Returns the type of the QJSPrimitiveValue.
Type
This enum speicifies the types a QJSPrimitiveValue might contain.
QJSPrimitiveValue & operator--()
QJSPrimitiveValue(const QMetaType type, const void *value) noexcept
friend QJSPrimitiveValue operator/(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
constexpr int toInteger() const
Returns the value coerced to an integral 32bit number by the rules JavaScript would apply when prepar...
QString toString() const
Returns the value coerced to a JavaScript String by JavaScript rules.
QJSPrimitiveValue & operator++()
constexpr bool toBoolean() const
Returns the value coerced a boolean by JavaScript rules.
QJSPrimitiveValue operator-()
constexpr bool strictlyEquals(const QJSPrimitiveValue &other) const
Performs the JavaScript '===' operation on this QJSPrimitiveValue and other, and returns the result.
constexpr bool equals(const QJSPrimitiveValue &other) const
Performs the JavaScript '==' operation on this QJSPrimitiveValue and other, and returns the result.
Q_IMPLICIT constexpr QJSPrimitiveValue(double value) noexcept
Creates a QJSPrimitiveValue of value value and type Double.
friend QJSPrimitiveValue operator%(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
friend constexpr bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
friend constexpr bool operator==(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
Q_IMPLICIT QJSPrimitiveValue(QString string) noexcept
Creates a QJSPrimitiveValue of value value and type String.
Q_IMPLICIT constexpr QJSPrimitiveValue() noexcept=default
Creates a QJSPrimitiveValue of type Undefined.
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
\inmodule QtCore
Definition qmetatype.h:341
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
~QString()
Destroys the string.
Definition qstring.h:1323
\inmodule QtCore
Definition qvariant.h:65
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QMetaType metaType() const
double jsExponentiate(double base, double exponent)
Combined button and popup list for selecting options.
#define Q_FALLTHROUGH()
#define Q_IMPLICIT
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qIsNull(qfloat16 f) noexcept
Definition qfloat16.h:354
std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
Definition qnumeric.h:113
std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
Definition qnumeric.h:153
std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
Definition qnumeric.h:182
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLdouble s
[6]
Definition qopenglext.h:235
GLint * exponent
GLuint64EXT * result
[6]
static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
static QT_BEGIN_NAMESPACE const char * asString(QSSGRenderGraphObject::Type type)
#define QStringLiteral(str)
unsigned char quint8
Definition qtypes.h:46
static const uint base
Definition qurlidna.cpp:20
QVariant variant
[1]
QSharedPointer< T > other(t)
[5]
An empty marker type to signify the JavaScript null value. \inmodule QtQml.
An empty marker type to signify the JavaScript Undefined type and its single value....
Definition moc.h:23