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 default:
359 break;
360 }
362 default:
363 break;
364 }
365
366 return std::fmod(lhs.toDouble(), rhs.toDouble());
367 }
368
370 {
371 // ++a is modeled as a -= (-1) to avoid the potential string concatenation
372 return (*this = operate<SubOperators>(*this, -1));
373 }
374
376 {
377 // a++ is modeled as a -= (-1) to avoid the potential string concatenation
378 QJSPrimitiveValue other = operate<SubOperators>(*this, -1);
379 std::swap(other, *this);
380 return +other; // We still need to coerce the original value.
381 }
382
384 {
385 return (*this = operate<SubOperators>(*this, 1));
386 }
387
389 {
390 QJSPrimitiveValue other = operate<SubOperators>(*this, 1);
391 std::swap(other, *this);
392 return +other; // We still need to coerce the original value.
393 }
394
396 {
397 // +a is modeled as a -= 0. That should force it to number.
398 return (*this = operate<SubOperators>(*this, 0));
399 }
400
402 {
403 return (*this = operate<MulOperators>(*this, -1));
404 }
405
406 constexpr bool strictlyEquals(const QJSPrimitiveValue &other) const
407 {
408 const Type myType = type();
409 const Type otherType = other.type();
410
411 if (myType != otherType) {
412 // int -> double promotion is OK in strict mode
413 if (myType == Double && otherType == Integer)
414 return strictlyEquals(double(other.asInteger()));
415 if (myType == Integer && otherType == Double)
416 return QJSPrimitiveValue(double(asInteger())).strictlyEquals(other);
417 return false;
418 }
419
420 switch (myType) {
421 case Undefined:
422 case Null:
423 return true;
424 case Boolean:
425 return asBoolean() == other.asBoolean();
426 case Integer:
427 return asInteger() == other.asInteger();
428 case Double: {
429 const double l = asDouble();
430 const double r = other.asDouble();
431 if (std::isnan(l) || std::isnan(r))
432 return false;
433 if (qIsNull(l) && qIsNull(r))
434 return true;
435 return QJSNumberCoercion::equals(l, r);
436 }
437 case String:
438 return asString() == other.asString();
439 }
440
441 return false;
442 }
443
444 // Loose operator==, in contrast to strict ===
445 constexpr bool equals(const QJSPrimitiveValue &other) const
446 {
447 const Type myType = type();
448 const Type otherType = other.type();
449
450 if (myType == otherType)
451 return strictlyEquals(other);
452
453 switch (myType) {
454 case Undefined:
455 return otherType == Null;
456 case Null:
457 return otherType == Undefined;
458 case Boolean:
459 return QJSPrimitiveValue(int(asBoolean())).equals(other);
460 case Integer:
461 // prefer rhs bool -> int promotion over promoting both to double
462 return otherType == Boolean
463 ? QJSPrimitiveValue(asInteger()).equals(int(other.asBoolean()))
464 : QJSPrimitiveValue(double(asInteger())).equals(other);
465 case Double:
466 // Promote the other side to double (or recognize lhs as undefined/null)
467 return other.equals(*this);
468 case String:
469 return fromString(asString()).parsedEquals(other);
470 }
471
472 return false;
473 }
474
475 friend constexpr inline bool operator==(const QJSPrimitiveValue &lhs, const
477 {
478 return lhs.strictlyEquals(rhs);
479 }
480
481 friend constexpr inline bool operator!=(const QJSPrimitiveValue &lhs,
482 const QJSPrimitiveValue &rhs)
483 {
484 return !lhs.strictlyEquals(rhs);
485 }
486
487 friend constexpr inline bool operator<(const QJSPrimitiveValue &lhs,
488 const QJSPrimitiveValue &rhs)
489 {
490 switch (lhs.type()) {
491 case Undefined:
492 return false;
493 case Null: {
494 switch (rhs.type()) {
495 case Undefined: return false;
496 case Null: return false;
497 case Boolean: return 0 < int(rhs.asBoolean());
498 case Integer: return 0 < rhs.asInteger();
499 case Double: return double(0) < rhs.asDouble();
500 case String: return double(0) < rhs.toDouble();
501 }
502 break;
503 }
504 case Boolean: {
505 switch (rhs.type()) {
506 case Undefined: return false;
507 case Null: return int(lhs.asBoolean()) < 0;
508 case Boolean: return lhs.asBoolean() < rhs.asBoolean();
509 case Integer: return int(lhs.asBoolean()) < rhs.asInteger();
510 case Double: return double(lhs.asBoolean()) < rhs.asDouble();
511 case String: return double(lhs.asBoolean()) < rhs.toDouble();
512 }
513 break;
514 }
515 case Integer: {
516 switch (rhs.type()) {
517 case Undefined: return false;
518 case Null: return lhs.asInteger() < 0;
519 case Boolean: return lhs.asInteger() < int(rhs.asBoolean());
520 case Integer: return lhs.asInteger() < rhs.asInteger();
521 case Double: return double(lhs.asInteger()) < rhs.asDouble();
522 case String: return double(lhs.asInteger()) < rhs.toDouble();
523 }
524 break;
525 }
526 case Double: {
527 switch (rhs.type()) {
528 case Undefined: return false;
529 case Null: return lhs.asDouble() < double(0);
530 case Boolean: return lhs.asDouble() < double(rhs.asBoolean());
531 case Integer: return lhs.asDouble() < double(rhs.asInteger());
532 case Double: return lhs.asDouble() < rhs.asDouble();
533 case String: return lhs.asDouble() < rhs.toDouble();
534 }
535 break;
536 }
537 case String: {
538 switch (rhs.type()) {
539 case Undefined: return false;
540 case Null: return lhs.toDouble() < double(0);
541 case Boolean: return lhs.toDouble() < double(rhs.asBoolean());
542 case Integer: return lhs.toDouble() < double(rhs.asInteger());
543 case Double: return lhs.toDouble() < rhs.asDouble();
544 case String: return lhs.asString() < rhs.asString();
545 }
546 break;
547 }
548 }
549
550 return false;
551 }
552
553 friend constexpr inline bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
554 {
555 return rhs < lhs;
556 }
557
558 friend constexpr inline bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
559 {
560 if (lhs.type() == String) {
561 if (rhs.type() == String)
562 return lhs.asString() <= rhs.asString();
563 else
564 return fromString(lhs.asString()) <= rhs;
565 }
566 if (rhs.type() == String)
567 return lhs <= fromString(rhs.asString());
568
569 if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
570 return false;
571 return !(lhs > rhs);
572 }
573
574 friend constexpr inline bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
575 {
576 if (lhs.type() == String) {
577 if (rhs.type() == String)
578 return lhs.asString() >= rhs.asString();
579 else
580 return fromString(lhs.asString()) >= rhs;
581 }
582 if (rhs.type() == String)
583 return lhs >= fromString(rhs.asString());
584
585 if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
586 return false;
587 return !(lhs < rhs);
588 }
589
590private:
591 friend class QJSManagedValue;
592 friend class QJSValue;
593 friend struct QV4::ExecutionEngine;
594
595 constexpr bool asBoolean() const { return d.getBool(); }
596 constexpr int asInteger() const { return d.getInt(); }
597 constexpr double asDouble() const { return d.getDouble(); }
598 QString asString() const { return d.getString(); }
599
600 constexpr bool parsedEquals(const QJSPrimitiveValue &other) const
601 {
602 return type() != Undefined && equals(other);
603 }
604
605 static QJSPrimitiveValue fromString(const QString &string)
606 {
607 bool ok;
608 const int intValue = string.toInt(&ok);
609 if (ok)
610 return intValue;
611
612 const double doubleValue = string.toDouble(&ok);
613 if (ok)
614 return doubleValue;
615 if (string == QStringLiteral("Infinity"))
616 return std::numeric_limits<double>::infinity();
617 if (string == QStringLiteral("-Infinity"))
618 return -std::numeric_limits<double>::infinity();
619 if (string == QStringLiteral("NaN"))
620 return std::numeric_limits<double>::quiet_NaN();
621 return QJSPrimitiveUndefined();
622 }
623
624 static Q_QML_EXPORT QString toString(double d);
625
626 template<typename Operators, typename Lhs, typename Rhs>
627 static QJSPrimitiveValue operateOnIntegers(const QJSPrimitiveValue &lhs,
628 const QJSPrimitiveValue &rhs)
629 {
630 int result;
631 if (Operators::opOverflow(lhs.d.get<Lhs>(), rhs.d.get<Rhs>(), &result))
632 return Operators::op(lhs.d.get<Lhs>(), rhs.d.get<Rhs>());
633 return result;
634 }
635
636 template<typename Operators>
637 static QJSPrimitiveValue operate(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
638 {
639 switch (lhs.type()) {
640 case Undefined:
641 switch (rhs.type()) {
642 case Undefined: return std::numeric_limits<double>::quiet_NaN();
643 case Null: return std::numeric_limits<double>::quiet_NaN();
644 case Boolean: return std::numeric_limits<double>::quiet_NaN();
645 case Integer: return std::numeric_limits<double>::quiet_NaN();
646 case Double: return std::numeric_limits<double>::quiet_NaN();
647 case String: return Operators::op(QJSPrimitiveUndefined(), rhs.asString());
648 }
649 break;
650 case Null:
651 switch (rhs.type()) {
652 case Undefined: return std::numeric_limits<double>::quiet_NaN();
653 case Null: return operateOnIntegers<Operators, int, int>(0, 0);
654 case Boolean: return operateOnIntegers<Operators, int, bool>(0, rhs);
655 case Integer: return operateOnIntegers<Operators, int, int>(0, rhs);
656 case Double: return Operators::op(0, rhs.asDouble());
657 case String: return Operators::op(QJSPrimitiveNull(), rhs.asString());
658 }
659 break;
660 case Boolean:
661 switch (rhs.type()) {
662 case Undefined: return std::numeric_limits<double>::quiet_NaN();
663 case Null: return operateOnIntegers<Operators, bool, int>(lhs, 0);
664 case Boolean: return operateOnIntegers<Operators, bool, bool>(lhs, rhs);
665 case Integer: return operateOnIntegers<Operators, bool, int>(lhs, rhs);
666 case Double: return Operators::op(lhs.asBoolean(), rhs.asDouble());
667 case String: return Operators::op(lhs.asBoolean(), rhs.asString());
668 }
669 break;
670 case Integer:
671 switch (rhs.type()) {
672 case Undefined: return std::numeric_limits<double>::quiet_NaN();
673 case Null: return operateOnIntegers<Operators, int, int>(lhs, 0);
674 case Boolean: return operateOnIntegers<Operators, int, bool>(lhs, rhs);
675 case Integer: return operateOnIntegers<Operators, int, int>(lhs, rhs);
676 case Double: return Operators::op(lhs.asInteger(), rhs.asDouble());
677 case String: return Operators::op(lhs.asInteger(), rhs.asString());
678 }
679 break;
680 case Double:
681 switch (rhs.type()) {
682 case Undefined: return std::numeric_limits<double>::quiet_NaN();
683 case Null: return Operators::op(lhs.asDouble(), 0);
684 case Boolean: return Operators::op(lhs.asDouble(), rhs.asBoolean());
685 case Integer: return Operators::op(lhs.asDouble(), rhs.asInteger());
686 case Double: return Operators::op(lhs.asDouble(), rhs.asDouble());
687 case String: return Operators::op(lhs.asDouble(), rhs.asString());
688 }
689 break;
690 case String:
691 switch (rhs.type()) {
692 case Undefined: return Operators::op(lhs.asString(), QJSPrimitiveUndefined());
693 case Null: return Operators::op(lhs.asString(), QJSPrimitiveNull());
694 case Boolean: return Operators::op(lhs.asString(), rhs.asBoolean());
695 case Integer: return Operators::op(lhs.asString(), rhs.asInteger());
696 case Double: return Operators::op(lhs.asString(), rhs.asDouble());
697 case String: return Operators::op(lhs.asString(), rhs.asString());
698 }
699 break;
700 }
701
702 Q_UNREACHABLE_RETURN(QJSPrimitiveUndefined());
703 }
704
705 constexpr bool isNanOrUndefined() const
706 {
707 switch (type()) {
708 case Undefined: return true;
709 case Double: return std::isnan(asDouble());
710 default: return false;
711 }
712 }
713
714 struct QJSPrimitiveValuePrivate
715 {
716 // Can't be default because QString has a non-trivial ctor.
717 constexpr QJSPrimitiveValuePrivate() noexcept {}
718
719 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveUndefined) noexcept {}
720 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveNull) noexcept
721 : m_type(Null) {}
722 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(bool b) noexcept
723 : m_bool(b), m_type(Boolean) {}
724 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(int i) noexcept
725 : m_int(i), m_type(Integer) {}
726 Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(double d) noexcept
727 : m_double(d), m_type(Double) {}
728 Q_IMPLICIT QJSPrimitiveValuePrivate(QString s) noexcept
729 : m_string(std::move(s)), m_type(String) {}
730
731 constexpr QJSPrimitiveValuePrivate(const QJSPrimitiveValuePrivate &other) noexcept
732 : m_type(other.m_type)
733 {
734 // Not copy-and-swap since swap() would be much more complicated.
735 if (!assignSimple(other))
736 new (&m_string) QString(other.m_string);
737 }
738
739 constexpr QJSPrimitiveValuePrivate(QJSPrimitiveValuePrivate &&other) noexcept
740 : m_type(other.m_type)
741 {
742 // Not move-and-swap since swap() would be much more complicated.
743 if (!assignSimple(other))
744 new (&m_string) QString(std::move(other.m_string));
745 }
746
747 constexpr QJSPrimitiveValuePrivate &operator=(const QJSPrimitiveValuePrivate &other) noexcept
748 {
749 if (this == &other)
750 return *this;
751
752 if (m_type == String) {
753 if (other.m_type == String) {
754 m_type = other.m_type;
755 m_string = other.m_string;
756 return *this;
757 }
758 m_string.~QString();
759 }
760
761 m_type = other.m_type;
762 if (!assignSimple(other))
763 new (&m_string) QString(other.m_string);
764 return *this;
765 }
766
767 constexpr QJSPrimitiveValuePrivate &operator=(QJSPrimitiveValuePrivate &&other) noexcept
768 {
769 if (this == &other)
770 return *this;
771
772 if (m_type == String) {
773 if (other.m_type == String) {
774 m_type = other.m_type;
775 m_string = std::move(other.m_string);
776 return *this;
777 }
778 m_string.~QString();
779 }
780
781 m_type = other.m_type;
782 if (!assignSimple(other))
783 new (&m_string) QString(std::move(other.m_string));
784 return *this;
785 }
786
787 ~QJSPrimitiveValuePrivate()
788 {
789 if (m_type == String)
790 m_string.~QString();
791 }
792
793 constexpr Type type() const noexcept { return m_type; }
794 constexpr bool getBool() const noexcept { return m_bool; }
795 constexpr int getInt() const noexcept { return m_int; }
796 constexpr double getDouble() const noexcept { return m_double; }
797 QString getString() const noexcept { return m_string; }
798
799 template<typename T>
800 constexpr T get() const noexcept {
801 if constexpr (std::is_same_v<T, QJSPrimitiveUndefined>)
802 return QJSPrimitiveUndefined();
803 else if constexpr (std::is_same_v<T, QJSPrimitiveNull>)
804 return QJSPrimitiveNull();
805 else if constexpr (std::is_same_v<T, bool>)
806 return getBool();
807 else if constexpr (std::is_same_v<T, int>)
808 return getInt();
809 else if constexpr (std::is_same_v<T, double>)
810 return getDouble();
811 else if constexpr (std::is_same_v<T, QString>)
812 return getString();
813
814 // GCC 8.x does not treat __builtin_unreachable() as constexpr
815 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
816 Q_UNREACHABLE_RETURN(T());
817 #else
818 return T();
819 #endif
820 }
821
822 constexpr QMetaType metaType() const noexcept {
823 switch (m_type) {
824 case Undefined:
825 return QMetaType();
826 case Null:
827 return QMetaType::fromType<std::nullptr_t>();
828 case Boolean:
829 return QMetaType::fromType<bool>();
830 case Integer:
831 return QMetaType::fromType<int>();
832 case Double:
833 return QMetaType::fromType<double>();
834 case String:
835 return QMetaType::fromType<QString>();
836 }
837
838 // GCC 8.x does not treat __builtin_unreachable() as constexpr
839 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
840 Q_UNREACHABLE_RETURN(QMetaType());
841 #else
842 return QMetaType();
843 #endif
844 }
845
846 constexpr void *data() noexcept {
847 switch (m_type) {
848 case Undefined:
849 case Null:
850 return nullptr;
851 case Boolean:
852 return &m_bool;
853 case Integer:
854 return &m_int;
855 case Double:
856 return &m_double;
857 case String:
858 return &m_string;
859 }
860
861 // GCC 8.x does not treat __builtin_unreachable() as constexpr
862 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
863 Q_UNREACHABLE_RETURN(nullptr);
864 #else
865 return nullptr;
866 #endif
867 }
868
869 constexpr const void *data() const noexcept {
870 switch (m_type) {
871 case Undefined:
872 case Null:
873 return nullptr;
874 case Boolean:
875 return &m_bool;
876 case Integer:
877 return &m_int;
878 case Double:
879 return &m_double;
880 case String:
881 return &m_string;
882 }
883
884 // GCC 8.x does not treat __builtin_unreachable() as constexpr
885 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
886 Q_UNREACHABLE_RETURN(nullptr);
887 #else
888 return nullptr;
889 #endif
890 }
891
892 private:
893 constexpr bool assignSimple(const QJSPrimitiveValuePrivate &other) noexcept
894 {
895 switch (other.m_type) {
896 case Undefined:
897 case Null:
898 return true;
899 case Boolean:
900 m_bool = other.m_bool;
901 return true;
902 case Integer:
903 m_int = other.m_int;
904 return true;
905 case Double:
906 m_double = other.m_double;
907 return true;
908 case String:
909 return false;
910 }
911
912 // GCC 8.x does not treat __builtin_unreachable() as constexpr
913 #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
914 Q_UNREACHABLE_RETURN(false);
915 #else
916 return false;
917 #endif
918 }
919
920 union {
921 bool m_bool = false;
922 int m_int;
923 double m_double;
924 QString m_string;
925 };
926
927 Type m_type = Undefined;
928 };
929
930 QJSPrimitiveValuePrivate d;
931};
932
933namespace QQmlPrivate {
934 // TODO: Make this constexpr once std::isnan is constexpr.
935 inline double jsExponentiate(double base, double exponent)
936 {
937 constexpr double qNaN = std::numeric_limits<double>::quiet_NaN();
938 constexpr double inf = std::numeric_limits<double>::infinity();
939
940 if (qIsNull(exponent))
941 return 1.0;
942
943 if (std::isnan(exponent))
944 return qNaN;
945
947 return std::isinf(exponent) ? qNaN : std::pow(base, exponent);
948
949 if (!qIsNull(base))
950 return std::pow(base, exponent);
951
952 if (std::copysign(1.0, base) > 0.0)
953 return exponent < 0.0 ? inf : std::pow(base, exponent);
954
955 if (exponent < 0.0)
956 return QJSNumberCoercion::equals(std::fmod(-exponent, 2.0), 1.0) ? -inf : inf;
957
958 return QJSNumberCoercion::equals(std::fmod(exponent, 2.0), 1.0)
959 ? std::copysign(0, -1.0)
960 : 0.0;
961 }
962}
963
965
966#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