Replace std::variant with tagged union in QJSPrimitiveValue
Pick-to: 6.1 Fixes: QTBUG-91717 Change-Id: Id19e08589206253b96c76bc40a799ccd95b0e0bf Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
parent
5e280b8792
commit
9970ebb277
|
@ -144,7 +144,7 @@ class QJSPrimitiveValue
|
|||
};
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
enum Type : quint8 {
|
||||
Undefined,
|
||||
Null,
|
||||
Boolean,
|
||||
|
@ -153,16 +153,16 @@ public:
|
|||
String
|
||||
};
|
||||
|
||||
constexpr Type type() const { return Type(d.index()); }
|
||||
constexpr Type type() const { return Type(d.type()); }
|
||||
|
||||
constexpr QJSPrimitiveValue() = default;
|
||||
constexpr QJSPrimitiveValue(QJSPrimitiveUndefined undefined) : d(undefined) {}
|
||||
constexpr QJSPrimitiveValue(QJSPrimitiveNull null) : d(null) {}
|
||||
constexpr QJSPrimitiveValue(bool value) : d(value) {}
|
||||
constexpr QJSPrimitiveValue(int value) : d(value) {}
|
||||
constexpr QJSPrimitiveValue(double value) : d(value) {}
|
||||
QJSPrimitiveValue(QString string) : d(std::move(string)) {}
|
||||
QJSPrimitiveValue(const QVariant &variant)
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue() noexcept = default;
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveUndefined undefined) noexcept : d(undefined) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveNull null) noexcept : d(null) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue(bool value) noexcept : d(value) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue(int value) noexcept : d(value) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValue(double value) noexcept : d(value) {}
|
||||
Q_IMPLICIT QJSPrimitiveValue(QString string) noexcept : d(std::move(string)) {}
|
||||
explicit QJSPrimitiveValue(const QVariant &variant) noexcept
|
||||
{
|
||||
switch (variant.typeId()) {
|
||||
case QMetaType::UnknownType:
|
||||
|
@ -194,13 +194,14 @@ public:
|
|||
switch (type()) {
|
||||
case Undefined: return false;
|
||||
case Null: return false;
|
||||
case Boolean: return std::get<bool>(d);
|
||||
case Integer: return std::get<int>(d) != 0;
|
||||
case Boolean: return asBoolean();
|
||||
case Integer: return asInteger() != 0;
|
||||
case Double: {
|
||||
const double v = std::get<double>(d);
|
||||
const double v = asDouble();
|
||||
return !QJSNumberCoercion::equals(v, 0) && !std::isnan(v);
|
||||
}
|
||||
case String: return !std::get<QString>(d).isEmpty();
|
||||
case String: return !asString().isEmpty();
|
||||
default: Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -211,10 +212,11 @@ public:
|
|||
switch (type()) {
|
||||
case Undefined: return 0;
|
||||
case Null: return 0;
|
||||
case Boolean: return std::get<bool>(d);
|
||||
case Integer: return std::get<int>(d);
|
||||
case Double: return QJSNumberCoercion::toInteger(std::get<double>(d));
|
||||
case String: return fromString(std::get<String>(d)).toInteger();
|
||||
case Boolean: return asBoolean();
|
||||
case Integer: return asInteger();
|
||||
case Double: return QJSNumberCoercion::toInteger(asDouble());
|
||||
case String: return fromString(asString()).toInteger();
|
||||
default: Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -225,13 +227,14 @@ public:
|
|||
switch (type()) {
|
||||
case Undefined: return std::numeric_limits<double>::quiet_NaN();
|
||||
case Null: return 0;
|
||||
case Boolean: return std::get<bool>(d);
|
||||
case Integer: return std::get<int>(d);
|
||||
case Double: return std::get<double>(d);
|
||||
case String: return fromString(std::get<String>(d)).toDouble();
|
||||
case Boolean: return asBoolean();
|
||||
case Integer: return asInteger();
|
||||
case Double: return asDouble();
|
||||
case String: return fromString(asString()).toDouble();
|
||||
default: Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
return {};
|
||||
}
|
||||
|
||||
QString toString() const
|
||||
|
@ -239,10 +242,10 @@ public:
|
|||
switch (type()) {
|
||||
case Undefined: return QStringLiteral("undefined");
|
||||
case Null: return QStringLiteral("null");
|
||||
case Boolean: return std::get<bool>(d) ? QStringLiteral("true") : QStringLiteral("false");
|
||||
case Integer: return QString::number(std::get<int>(d));
|
||||
case Boolean: return asBoolean() ? QStringLiteral("true") : QStringLiteral("false");
|
||||
case Integer: return QString::number(asInteger());
|
||||
case Double: {
|
||||
const double result = std::get<double>(d);
|
||||
const double result = asDouble();
|
||||
if (std::isnan(result))
|
||||
return QStringLiteral("NaN");
|
||||
if (std::isfinite(result))
|
||||
|
@ -251,7 +254,7 @@ public:
|
|||
return QStringLiteral("Infinity");
|
||||
return QStringLiteral("-Infinity");
|
||||
}
|
||||
case String: return std::get<QString>(d);
|
||||
case String: return asString();
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
|
@ -512,10 +515,10 @@ private:
|
|||
friend class QJSManagedValue;
|
||||
friend class QJSValue;
|
||||
|
||||
constexpr bool asBoolean() const { return std::get<bool>(d); }
|
||||
constexpr int asInteger() const { return std::get<int>(d); }
|
||||
constexpr double asDouble() const { return std::get<double>(d); }
|
||||
QString asString() const { return std::get<QString>(d); }
|
||||
constexpr bool asBoolean() const { return d.getBool(); }
|
||||
constexpr int asInteger() const { return d.getInt(); }
|
||||
constexpr double asDouble() const { return d.getDouble(); }
|
||||
QString asString() const { return d.getString(); }
|
||||
|
||||
constexpr bool parsedEquals(const QJSPrimitiveValue &other) const
|
||||
{
|
||||
|
@ -548,8 +551,8 @@ private:
|
|||
const QJSPrimitiveValue &rhs)
|
||||
{
|
||||
int result;
|
||||
if (Operators::opOverflow(std::get<Lhs>(lhs.d), std::get<Rhs>(rhs.d), &result))
|
||||
return Operators::op(std::get<Lhs>(lhs.d), std::get<Rhs>(rhs.d));
|
||||
if (Operators::opOverflow(lhs.d.get<Lhs>(), rhs.d.get<Rhs>(), &result))
|
||||
return Operators::op(lhs.d.get<Lhs>(), rhs.d.get<Rhs>());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -632,7 +635,145 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
std::variant<QJSPrimitiveUndefined, QJSPrimitiveNull, bool, int, double, QString> d;
|
||||
struct QJSPrimitiveValuePrivate
|
||||
{
|
||||
// Can't be default because QString has a non-trivial ctor.
|
||||
constexpr QJSPrimitiveValuePrivate() noexcept {}
|
||||
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveUndefined) noexcept {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveNull) noexcept
|
||||
: m_type(Null) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(bool b) noexcept
|
||||
: m_bool(b), m_type(Boolean) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(int i) noexcept
|
||||
: m_int(i), m_type(Integer) {}
|
||||
Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(double d) noexcept
|
||||
: m_double(d), m_type(Double) {}
|
||||
Q_IMPLICIT QJSPrimitiveValuePrivate(QString s) noexcept
|
||||
: m_string(std::move(s)), m_type(String) {}
|
||||
|
||||
constexpr QJSPrimitiveValuePrivate(const QJSPrimitiveValuePrivate &other) noexcept
|
||||
: m_type(other.m_type)
|
||||
{
|
||||
// Not copy-and-swap since swap() would be much more complicated.
|
||||
if (!assignSimple(other))
|
||||
new (&m_string) QString(other.m_string);
|
||||
}
|
||||
|
||||
constexpr QJSPrimitiveValuePrivate(QJSPrimitiveValuePrivate &&other) noexcept
|
||||
: m_type(other.m_type)
|
||||
{
|
||||
// Not move-and-swap since swap() would be much more complicated.
|
||||
if (!assignSimple(other))
|
||||
new (&m_string) QString(std::move(other.m_string));
|
||||
}
|
||||
|
||||
constexpr QJSPrimitiveValuePrivate &operator=(const QJSPrimitiveValuePrivate &other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
if (m_type == String) {
|
||||
if (other.m_type == String) {
|
||||
m_type = other.m_type;
|
||||
m_string = other.m_string;
|
||||
return *this;
|
||||
}
|
||||
m_string.~QString();
|
||||
}
|
||||
|
||||
m_type = other.m_type;
|
||||
if (!assignSimple(other))
|
||||
new (&m_string) QString(other.m_string);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr QJSPrimitiveValuePrivate &operator=(QJSPrimitiveValuePrivate &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
if (m_type == String) {
|
||||
if (other.m_type == String) {
|
||||
m_type = other.m_type;
|
||||
m_string = std::move(other.m_string);
|
||||
return *this;
|
||||
}
|
||||
m_string.~QString();
|
||||
}
|
||||
|
||||
m_type = other.m_type;
|
||||
if (!assignSimple(other))
|
||||
new (&m_string) QString(std::move(other.m_string));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~QJSPrimitiveValuePrivate()
|
||||
{
|
||||
if (m_type == String)
|
||||
m_string.~QString();
|
||||
}
|
||||
|
||||
constexpr Type type() const noexcept { return m_type; }
|
||||
constexpr bool getBool() const noexcept { return m_bool; }
|
||||
constexpr int getInt() const noexcept { return m_int; }
|
||||
constexpr double getDouble() const noexcept { return m_double; }
|
||||
QString getString() const noexcept { return m_string; }
|
||||
|
||||
template<typename T>
|
||||
constexpr T get() const noexcept {
|
||||
if constexpr (std::is_same_v<T, QJSPrimitiveUndefined>)
|
||||
return QJSPrimitiveUndefined();
|
||||
else if constexpr (std::is_same_v<T, QJSPrimitiveNull>)
|
||||
return QJSPrimitiveNull();
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
return getBool();
|
||||
else if constexpr (std::is_same_v<T, int>)
|
||||
return getInt();
|
||||
else if constexpr (std::is_same_v<T, double>)
|
||||
return getDouble();
|
||||
else if constexpr (std::is_same_v<T, QString>)
|
||||
return getString();
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return T();
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr bool assignSimple(const QJSPrimitiveValuePrivate &other) noexcept
|
||||
{
|
||||
switch (other.m_type) {
|
||||
case Undefined:
|
||||
case Null:
|
||||
return true;
|
||||
case Boolean:
|
||||
m_bool = other.m_bool;
|
||||
return true;
|
||||
case Integer:
|
||||
m_int = other.m_int;
|
||||
return true;
|
||||
case Double:
|
||||
m_double = other.m_double;
|
||||
return true;
|
||||
case String:
|
||||
return false;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
union {
|
||||
bool m_bool = false;
|
||||
int m_int;
|
||||
double m_double;
|
||||
QString m_string;
|
||||
};
|
||||
|
||||
Type m_type = Undefined;
|
||||
};
|
||||
|
||||
QJSPrimitiveValuePrivate d;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -911,7 +911,7 @@ QJSValue::QJSValue(QJSPrimitiveValue &&value)
|
|||
d = QV4::Encode(value.asDouble());
|
||||
return;
|
||||
case QJSPrimitiveValue::String:
|
||||
QJSValuePrivate::setString(this, std::move(std::get<QString>(value.d)));
|
||||
QJSValuePrivate::setString(this, value.asString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue