summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qvariant.h')
-rw-r--r--src/corelib/kernel/qvariant.h1066
1 files changed, 543 insertions, 523 deletions
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 87fb16485f..d567bcbb7c 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -1,137 +1,147 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVARIANT_H
#define QVARIANT_H
#include <QtCore/qatomic.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qmetatype.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qobject.h>
-#ifndef QT_BOOTSTRAPPED
-#include <QtCore/qbytearraylist.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
#endif
#include <memory>
-
-#if __has_include(<variant>) && __cplusplus >= 201703L
+#include <QtCore/q20type_traits.h>
+#include <QtCore/q23utility.h>
#include <variant>
-#elif defined(Q_CLANG_QDOC)
-namespace std { template<typename...> struct variant; }
+
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 1
+# include <QtCore/qlist.h>
+# include <QtCore/qstringlist.h>
+# include <QtCore/qbytearraylist.h>
+# include <QtCore/qhash.h>
+# include <QtCore/qmap.h>
+# include <QtCore/qobject.h>
#endif
QT_BEGIN_NAMESPACE
+QT_ENABLE_P0846_SEMANTICS_FOR(get_if)
+QT_ENABLE_P0846_SEMANTICS_FOR(get)
class QBitArray;
class QDataStream;
class QDate;
class QDateTime;
-#if QT_CONFIG(easingcurve)
class QEasingCurve;
-#endif
class QLine;
class QLineF;
class QLocale;
-class QTransform;
-class QStringList;
-class QTime;
+class QModelIndex;
+class QPersistentModelIndex;
class QPoint;
class QPointF;
-class QSize;
-class QSizeF;
class QRect;
class QRectF;
-#if QT_CONFIG(regularexpression)
class QRegularExpression;
-#endif // QT_CONFIG(regularexpression)
+class QSize;
+class QSizeF;
class QTextFormat;
class QTextLength;
+class QTime;
+class QTransform;
class QUrl;
class QVariant;
-class QVariantComparisonHelper;
template<typename T>
inline T qvariant_cast(const QVariant &);
namespace QtPrivate {
+template<> constexpr inline bool qIsRelocatable<QVariant> = true;
+}
+class Q_CORE_EXPORT QVariant
+{
+ template <typename T, typename... Args>
+ using if_constructible = std::enable_if_t<
+ std::conjunction_v<
+ std::is_copy_constructible<q20::remove_cvref_t<T>>,
+ std::is_destructible<q20::remove_cvref_t<T>>,
+ std::is_constructible<q20::remove_cvref_t<T>, Args...>
+ >,
+ bool>;
+
+ template <typename T>
+ using if_rvalue = std::enable_if_t<!std::is_reference_v<T>, bool>;
+
+ struct CborValueStandIn { qint64 n; void *c; int t; };
+public:
+ struct PrivateShared
+ {
+ private:
+ inline PrivateShared() : ref(1) { }
+ public:
+ static int computeOffset(PrivateShared *ps, size_t align);
+ static size_t computeAllocationSize(size_t size, size_t align);
+ static PrivateShared *create(size_t size, size_t align);
+ static void free(PrivateShared *p);
+
+ alignas(8) QAtomicInt ref;
+ int offset;
+
+ const void *data() const { return reinterpret_cast<const uchar *>(this) + offset; }
+ void *data() { return reinterpret_cast<uchar *>(this) + offset; }
+ };
- template <typename Derived, typename Argument, typename ReturnType>
- struct ObjectInvoker
+ struct Private
{
- static ReturnType invoke(Argument a)
+ static constexpr size_t MaxInternalSize = 3 * sizeof(void *);
+ template <size_t S> static constexpr bool FitsInInternalSize = S <= MaxInternalSize;
+ template<typename T> static constexpr bool CanUseInternalSpace =
+ (QTypeInfo<T>::isRelocatable && FitsInInternalSize<sizeof(T)> && alignof(T) <= alignof(double));
+ static constexpr bool canUseInternalSpace(const QtPrivate::QMetaTypeInterface *type)
{
- return Derived::object(a);
+ Q_ASSERT(type);
+ return QMetaType::TypeFlags(type->flags) & QMetaType::RelocatableType &&
+ size_t(type->size) <= MaxInternalSize && size_t(type->alignment) <= alignof(double);
}
- };
- template <typename Derived, typename Argument, typename ReturnType>
- struct MetaTypeInvoker
- {
- static ReturnType invoke(Argument a)
+ union
+ {
+ uchar data[MaxInternalSize] = {};
+ PrivateShared *shared;
+ double _forAlignment; // we want an 8byte alignment on 32bit systems as well
+ } data;
+ quintptr is_shared : 1;
+ quintptr is_null : 1;
+ quintptr packedType : sizeof(QMetaType) * 8 - 2;
+
+ constexpr Private() noexcept : is_shared(false), is_null(true), packedType(0) {}
+ explicit Private(const QtPrivate::QMetaTypeInterface *iface) noexcept;
+ template <typename T> explicit Private(std::piecewise_construct_t, const T &t);
+
+ const void *storage() const
+ { return is_shared ? data.shared->data() : &data.data; }
+
+ // determine internal storage at compile time
+ template<typename T> const T &get() const
+ { return *static_cast<const T *>(CanUseInternalSpace<T> ? &data.data : data.shared->data()); }
+
+ inline const QtPrivate::QMetaTypeInterface *typeInterface() const
{
- return Derived::metaType(a);
+ return reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(packedType << 2);
}
- };
- template <typename Derived, typename T, typename Argument, typename ReturnType, bool = IsPointerToTypeDerivedFromQObject<T>::Value>
- struct TreatAsQObjectBeforeMetaType : ObjectInvoker<Derived, Argument, ReturnType>
- {
+ inline QMetaType type() const
+ {
+ return QMetaType(typeInterface());
+ }
};
- template <typename Derived, typename T, typename Argument, typename ReturnType>
- struct TreatAsQObjectBeforeMetaType<Derived, T, Argument, ReturnType, false> : MetaTypeInvoker<Derived, Argument, ReturnType>
+#if QT_DEPRECATED_SINCE(6, 0)
+ enum QT_DEPRECATED_VERSION_X_6_0("Use QMetaType::Type instead.") Type
{
- };
-
- template<typename T> struct QVariantValueHelper;
-}
-
-class Q_CORE_EXPORT QVariant
-{
- public:
- enum Type {
Invalid = QMetaType::UnknownType,
Bool = QMetaType::Bool,
Int = QMetaType::Int,
@@ -204,44 +214,110 @@ class Q_CORE_EXPORT QVariant
UserType = QMetaType::User,
LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type
};
-
+#endif
QVariant() noexcept : d() {}
~QVariant();
- QVariant(Type type);
- QVariant(int typeId, const void *copy, uint flags = 0); // ### Qt6 TODO deprecate
- explicit QVariant(QMetaType type, const void *copy);
+ explicit QVariant(QMetaType type, const void *copy = nullptr);
QVariant(const QVariant &other);
-#ifndef QT_NO_DATASTREAM
- QVariant(QDataStream &s);
+private:
+ template <typename T, typename ...Args>
+ using is_noexcept_constructible = std::conjunction<
+ std::bool_constant<Private::CanUseInternalSpace<T>>,
+ std::is_nothrow_constructible<T, Args...>
+ >;
+
+public:
+ template <typename T, typename... Args,
+ if_constructible<T, Args...> = true>
+ explicit QVariant(std::in_place_type_t<T>, Args&&... args)
+ noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value)
+ : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>() )
+ {
+ void *data = const_cast<void *>(constData());
+ new (data) T(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename U, typename... Args,
+ if_constructible<T, std::initializer_list<U> &, Args...> = true>
+ explicit QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args)
+ noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>,
+ std::initializer_list<U> &,
+ Args...
+ >::value)
+ : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>())
+ {
+ char *data = static_cast<char *>(const_cast<void *>(constData()));
+ new (data) T(il, std::forward<Args>(args)...);
+ }
+
+ // primitives
+ QVariant(int i) noexcept;
+ QVariant(uint ui) noexcept;
+ QVariant(qlonglong ll) noexcept;
+ QVariant(qulonglong ull) noexcept;
+ QVariant(bool b) noexcept;
+ QVariant(double d) noexcept;
+ QVariant(float f) noexcept;
+
+ // trivial, trivially-copyable or COW
+ QVariant(QChar qchar) noexcept;
+ QVariant(QDate date) noexcept;
+ QVariant(QTime time) noexcept;
+#ifndef QT_BOOTSTRAPPED
+ QVariant(const QBitArray &bitarray) noexcept;
+#endif
+ QVariant(const QByteArray &bytearray) noexcept;
+ QVariant(const QDateTime &datetime) noexcept;
+ QVariant(const QHash<QString, QVariant> &hash) noexcept;
+ QVariant(const QJsonArray &jsonArray) noexcept;
+ QVariant(const QJsonObject &jsonObject) noexcept;
+ QVariant(const QList<QVariant> &list) noexcept;
+ QVariant(const QLocale &locale) noexcept;
+ QVariant(const QMap<QString, QVariant> &map) noexcept;
+ QVariant(const QRegularExpression &re) noexcept;
+ QVariant(const QString &string) noexcept;
+ QVariant(const QStringList &stringlist) noexcept;
+ QVariant(const QUrl &url) noexcept;
+
+ // conditionally noexcept trivial or trivially-copyable
+ // (most of these are noexcept on 64-bit)
+ QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize<sizeof(CborValueStandIn)>);
+ QVariant(const QModelIndex &modelIndex) noexcept(Private::FitsInInternalSize<8 + 2 * sizeof(quintptr)>);
+ QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>);
+#ifndef QT_NO_GEOM_VARIANT
+ QVariant(QSize size) noexcept;
+ QVariant(QSizeF size) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>);
+ QVariant(QPoint pt) noexcept;
+ QVariant(QPointF pt) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 2>);
+ QVariant(QLine line) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>);
+ QVariant(QLineF line) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>);
+ QVariant(QRect rect) noexcept(Private::FitsInInternalSize<sizeof(int) * 4>);
+ QVariant(QRectF rect) noexcept(Private::FitsInInternalSize<sizeof(qreal) * 4>);
#endif
- QVariant(int i);
- QVariant(uint ui);
- QVariant(qlonglong ll);
- QVariant(qulonglong ull);
- QVariant(bool b);
- QVariant(double d);
- QVariant(float f);
+ // not noexcept
+ QVariant(const QEasingCurve &easing) noexcept(false);
+ QVariant(const QJsonDocument &jsonDocument) noexcept(false);
+ QVariant(const QPersistentModelIndex &modelIndex) noexcept(false);
+
#ifndef QT_NO_CAST_FROM_ASCII
- QT_ASCII_CAST_WARN QVariant(const char *str)
+ QT_ASCII_CAST_WARN QVariant(const char *str) noexcept(false)
: QVariant(QString::fromUtf8(str))
{}
#endif
+ QVariant(QLatin1StringView string) noexcept(false); // converts to QString
- QVariant(const QByteArray &bytearray);
- QVariant(const QBitArray &bitarray);
- QVariant(const QString &string);
- QVariant(QLatin1String string);
- QVariant(const QStringList &stringlist);
- QVariant(QChar qchar);
- QVariant(QDate date);
- QVariant(QTime time);
- QVariant(const QDateTime &datetime);
- QVariant(const QList<QVariant> &list);
- QVariant(const QMap<QString,QVariant> &map);
- QVariant(const QHash<QString,QVariant> &hash);
-#ifndef QT_NO_GEOM_VARIANT
+#if !defined(Q_CC_GHS)
+ // GHS has an ICE with this code; use the simplified version below
+ template <typename T,
+ std::enable_if_t<std::disjunction_v<std::is_pointer<T>, std::is_member_pointer<T>>, bool> = false>
+ QVariant(T) = delete;
+#else
+ QVariant(const volatile void *) = delete;
+#endif
+
+#if QT_CORE_REMOVED_SINCE(6, 5)
QVariant(const QSize &size);
QVariant(const QSizeF &size);
QVariant(const QPoint &pt);
@@ -250,42 +326,37 @@ class Q_CORE_EXPORT QVariant
QVariant(const QLineF &line);
QVariant(const QRect &rect);
QVariant(const QRectF &rect);
-#endif
- QVariant(const QLocale &locale);
-#if QT_CONFIG(regularexpression)
- QVariant(const QRegularExpression &re);
-#endif // QT_CONFIG(regularexpression)
-#if QT_CONFIG(easingcurve)
- QVariant(const QEasingCurve &easing);
-#endif
QVariant(const QUuid &uuid);
-#ifndef QT_BOOTSTRAPPED
- QVariant(const QUrl &url);
- QVariant(const QJsonValue &jsonValue);
- QVariant(const QJsonObject &jsonObject);
- QVariant(const QJsonArray &jsonArray);
- QVariant(const QJsonDocument &jsonDocument);
-#endif // QT_BOOTSTRAPPED
-#if QT_CONFIG(itemmodel)
- QVariant(const QModelIndex &modelIndex);
- QVariant(const QPersistentModelIndex &modelIndex);
#endif
QVariant& operator=(const QVariant &other);
inline QVariant(QVariant &&other) noexcept : d(other.d)
{ other.d = Private(); }
- inline QVariant &operator=(QVariant &&other) noexcept
- { QVariant moved(std::move(other)); swap(moved); return *this; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QVariant)
- inline void swap(QVariant &other) noexcept { qSwap(d, other.d); }
+ inline void swap(QVariant &other) noexcept { std::swap(d, other.d); }
+
+ int userType() const { return typeId(); }
+ int typeId() const { return metaType().id(); }
- Type type() const;
- int userType() const;
const char *typeName() const;
QMetaType metaType() const;
- bool canConvert(int targetTypeId) const;
- bool convert(int targetTypeId);
+ bool canConvert(QMetaType targetType) const
+ { return QMetaType::canConvert(d.type(), targetType); }
+ bool convert(QMetaType type);
+
+ bool canView(QMetaType targetType) const
+ { return QMetaType::canView(d.type(), targetType); }
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_VERSION_6_0
+ bool canConvert(int targetTypeId) const
+ { return QMetaType::canConvert(d.type(), QMetaType(targetTypeId)); }
+ QT_DEPRECATED_VERSION_6_0
+ bool convert(int targetTypeId)
+ { return convert(QMetaType(targetTypeId)); }
+#endif
inline bool isValid() const;
bool isNull() const;
@@ -304,7 +375,9 @@ class Q_CORE_EXPORT QVariant
float toFloat(bool *ok = nullptr) const;
qreal toReal(bool *ok = nullptr) const;
QByteArray toByteArray() const;
+#ifndef QT_BOOTSTRAPPED
QBitArray toBitArray() const;
+#endif
QString toString() const;
QStringList toStringList() const;
QChar toChar() const;
@@ -349,13 +422,73 @@ class Q_CORE_EXPORT QVariant
void load(QDataStream &ds);
void save(QDataStream &ds) const;
#endif
- static const char *typeToName(int typeId);
- static Type nameToType(const char *name);
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ QT_DEPRECATED_VERSION_X_6_0("Use the constructor taking a QMetaType instead.")
+ explicit QVariant(Type type)
+ : QVariant(QMetaType(int(type)))
+ {}
+ QT_DEPRECATED_VERSION_X_6_0("Use typeId() or metaType().")
+ Type type() const
+ {
+ int type = d.type().id();
+ return type >= QMetaType::User ? UserType : static_cast<Type>(type);
+ }
+ QT_DEPRECATED_VERSION_6_0
+ static const char *typeToName(int typeId)
+ { return QMetaType(typeId).name(); }
+ QT_DEPRECATED_VERSION_6_0
+ static Type nameToType(const char *name)
+ {
+ int metaType = QMetaType::fromName(name).id();
+ return metaType <= int(UserType) ? QVariant::Type(metaType) : UserType;
+ }
+ QT_WARNING_POP
+#endif
void *data();
- const void *constData() const;
+ const void *constData() const
+ { return d.storage(); }
inline const void *data() const { return constData(); }
+private:
+ template <typename T>
+ void verifySuitableForEmplace()
+ {
+ static_assert(!std::is_reference_v<T>,
+ "QVariant does not support reference types");
+ static_assert(!std::is_const_v<T>,
+ "QVariant does not support const types");
+ static_assert(std::is_copy_constructible_v<T>,
+ "QVariant requires that the type is copyable");
+ static_assert(std::is_destructible_v<T>,
+ "QVariant requires that the type is destructible");
+ }
+
+ template <typename T, typename... Args>
+ T &emplaceImpl(Args&&... args)
+ {
+ verifySuitableForEmplace<T>();
+ auto data = static_cast<T *>(prepareForEmplace(QMetaType::fromType<T>()));
+ return *q20::construct_at(data, std::forward<Args>(args)...);
+ }
+
+public:
+ template <typename T, typename... Args,
+ if_constructible<T, Args...> = true>
+ T &emplace(Args&&... args)
+ {
+ return emplaceImpl<T>(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename U, typename... Args,
+ if_constructible<T, std::initializer_list<U> &, Args...> = true>
+ T &emplace(std::initializer_list<U> list, Args&&... args)
+ {
+ return emplaceImpl<T>(list, std::forward<Args>(args)...);
+ }
+
template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>>
void setValue(T &&avalue)
{
@@ -380,129 +513,168 @@ class Q_CORE_EXPORT QVariant
}
template<typename T>
- inline T value() const
+ inline T value() const &
{ return qvariant_cast<T>(*this); }
template<typename T>
+ inline T view()
+ {
+ T t{};
+ QMetaType::view(metaType(), data(), QMetaType::fromType<T>(), &t);
+ return t;
+ }
+
+ template<typename T>
+ inline T value() &&
+ { return qvariant_cast<T>(std::move(*this)); }
+
+ template<typename T, if_rvalue<T> = true>
+#ifndef Q_QDOC
+ /* needs is_copy_constructible for variants semantics, is_move_constructible so that moveConstruct works
+ (but copy_constructible implies move_constructble, so don't bother checking)
+ */
+ static inline auto fromValue(T &&value)
+ noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
+ -> std::enable_if_t<std::conjunction_v<std::is_copy_constructible<T>,
+ std::is_destructible<T>>, QVariant>
+#else
+ static inline QVariant fromValue(T &&value)
+#endif
+ {
+ // handle special cases
+ using Type = std::remove_cv_t<T>;
+ if constexpr (std::is_null_pointer_v<Type>)
+ return QVariant::fromMetaType(QMetaType::fromType<std::nullptr_t>());
+ else if constexpr (std::is_same_v<Type, QVariant>)
+ return std::forward<T>(value);
+ else if constexpr (std::is_same_v<Type, std::monostate>)
+ return QVariant();
+ QMetaType mt = QMetaType::fromType<Type>();
+ mt.registerType(); // we want the type stored in QVariant to always be registered
+ // T is a forwarding reference, so if T satifies the enable-ifery,
+ // we get this overload even if T is an lvalue reference and thus must check here
+ // Moreover, we only try to move if the type is actually moveable and not if T is const
+ // as in const int i; QVariant::fromValue(std::move(i));
+ if constexpr (std::conjunction_v<std::is_move_constructible<Type>, std::negation<std::is_const<T>>>)
+ return moveConstruct(QMetaType::fromType<Type>(), std::addressof(value));
+ else
+ return copyConstruct(mt, std::addressof(value));
+ }
+
+ template<typename T>
+#ifndef Q_QDOC
+ static inline auto fromValue(const T &value)
+ noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
+ -> std::enable_if_t<std::is_copy_constructible_v<T> && std::is_destructible_v<T>, QVariant>
+#else
static inline QVariant fromValue(const T &value)
+#endif
{
+ if constexpr (std::is_null_pointer_v<T>)
+ return QVariant(QMetaType::fromType<std::nullptr_t>());
+ else if constexpr (std::is_same_v<T, QVariant>)
+ return value;
+ else if constexpr (std::is_same_v<T, std::monostate>)
+ return QVariant();
return QVariant(QMetaType::fromType<T>(), std::addressof(value));
}
-#if (__has_include(<variant>) && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC)
template<typename... Types>
static inline QVariant fromStdVariant(const std::variant<Types...> &value)
{
- if (value.valueless_by_exception())
- return QVariant();
- return std::visit([](const auto &arg) { return fromValue(arg); }, value);
+ return fromStdVariantImpl(value);
}
-#endif
+
+ template<typename... Types>
+ static QVariant fromStdVariant(std::variant<Types...> &&value)
+ {
+ return fromStdVariantImpl(std::move(value));
+ }
+
+ static QVariant fromMetaType(QMetaType type, const void *copy = nullptr);
template<typename T>
bool canConvert() const
- { return canConvert(qMetaTypeId<T>()); }
+ { return canConvert(QMetaType::fromType<T>()); }
- public:
- struct PrivateShared
- {
- inline PrivateShared(void *v) : ptr(v), ref(1) { }
- void *ptr;
- QAtomicInt ref;
- };
- struct Private
- {
- Private() noexcept : packedType(0), is_shared(false), is_null(true) {}
- explicit Private(const QMetaType &type) noexcept : is_shared(false), is_null(false)
- {
- if (type.d_ptr)
- type.d_ptr->ref.ref();
- quintptr mt = quintptr(type.d_ptr);
- Q_ASSERT((mt & 0x3) == 0);
- packedType = mt >> 2;
- }
- explicit Private(int type) noexcept : Private(QMetaType(type)) {}
- Private(const Private &other) : Private(other.type())
- {
- data = other.data;
- is_shared = other.is_shared;
- is_null = other.is_null;
- }
- Private &operator=(const Private &other)
- {
- if (&other != this) {
- this->~Private();
- new (this) Private(other);
- }
- return *this;
- }
- Q_CORE_EXPORT ~Private();
+ template<typename T>
+ bool canView() const
+ { return canView(QMetaType::fromType<T>()); }
- union Data
- {
- void *threeptr[3] = { nullptr, nullptr, nullptr };
- char c;
- uchar uc;
- short s;
- signed char sc;
- ushort us;
- int i;
- uint u;
- long l;
- ulong ul;
- bool b;
- double d;
- float f;
- qreal real;
- qlonglong ll;
- qulonglong ull;
- QObject *o;
- void *ptr;
- PrivateShared *shared;
- } data;
- quintptr packedType : sizeof(QMetaType) * 8 - 2;
- quintptr is_shared : 1;
- quintptr is_null : 1;
- inline QMetaType type() const
- {
- return QMetaType(reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2));
- }
- };
- public:
- typedef bool (*f_null)(const Private *);
- typedef bool (*f_compare)(const Private *, const Private *);
- typedef bool (*f_convert)(const QVariant::Private *d, int t, void *, bool *);
- typedef void (*f_debugStream)(QDebug, const QVariant &);
- struct Handler {
- f_null isNull;
- f_compare compare;
- f_convert convert;
- f_debugStream debugStream;
- };
+ static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs);
+
+private:
+ template <typename StdVariant>
+ static QVariant fromStdVariantImpl(StdVariant &&v)
+ {
+ if (Q_UNLIKELY(v.valueless_by_exception()))
+ return QVariant();
+ auto visitor = [](auto &&arg) {
+ return QVariant::fromValue(q23::forward_like<StdVariant>(arg));
+ };
+ return std::visit(visitor, std::forward<StdVariant>(v));
+ }
- inline bool operator==(const QVariant &v) const
- { return cmp(v); }
- inline bool operator!=(const QVariant &v) const
- { return !cmp(v); }
+ friend bool comparesEqual(const QVariant &a, const QVariant &b)
+ { return a.equals(b); }
+ Q_DECLARE_EQUALITY_COMPARABLE(QVariant)
-protected:
- friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &);
#ifndef QT_NO_DEBUG_STREAM
- friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &);
+ template <typename T>
+ friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> {
+ return variant.qdebugHelper(debug);
+ }
+ QDebug qdebugHelper(QDebug) const;
#endif
-// ### Qt6: FIXME: Remove the special Q_CC_MSVC handling, it was introduced to maintain BC for QTBUG-41810 .
-#if !defined(Q_NO_TEMPLATE_FRIENDS) && !defined(Q_CC_MSVC)
+
+ template <typename T>
+ friend T *get_if(QVariant *v) noexcept
+ {
+ // data() will detach from is_null, returning non-nullptr
+ if (!v || v->d.type() != QMetaType::fromType<T>())
+ return nullptr;
+ return static_cast<T*>(v->data());
+ }
+ template <typename T>
+ friend const T *get_if(const QVariant *v) noexcept
+ {
+ // (const) data() will not detach from is_null, return nullptr
+ if (!v || v->d.is_null || v->d.type() != QMetaType::fromType<T>())
+ return nullptr;
+ return static_cast<const T*>(v->data());
+ }
+
+#define Q_MK_GET(cvref) \
+ template <typename T> \
+ friend T cvref get(QVariant cvref v) \
+ { \
+ if constexpr (std::is_const_v<T cvref>) \
+ Q_ASSERT(!v.d.is_null); \
+ Q_ASSERT(v.d.type() == QMetaType::fromType<q20::remove_cvref_t<T>>()); \
+ return static_cast<T cvref>(*get_if<T>(&v)); \
+ } \
+ /* end */
+ Q_MK_GET(&)
+ Q_MK_GET(const &)
+ Q_MK_GET(&&)
+ Q_MK_GET(const &&)
+#undef Q_MK_GET
+
+ static QVariant moveConstruct(QMetaType type, void *data);
+ static QVariant copyConstruct(QMetaType type, const void *data);
+
template<typename T>
friend inline T qvariant_cast(const QVariant &);
- template<typename T> friend struct QtPrivate::QVariantValueHelper;
+ template<typename T>
+ friend inline T qvariant_cast(QVariant &&);
+
protected:
-#else
-public:
-#endif
Private d;
void create(int type, const void *copy);
- bool cmp(const QVariant &other) const;
- bool convert(const int t, void *ptr) const; // ### Qt6: drop const
+ void create(QMetaType type, const void *copy);
+ bool equals(const QVariant &other) const;
+ bool convert(int type, void *ptr) const;
+ bool view(int type, void *ptr);
private:
// force compile error, prevent QVariant(bool) to be called
@@ -515,7 +687,12 @@ private:
// int variant, so delete this constructor:
QVariant(QMetaType::Type) = delete;
- // These constructors don't create QVariants of the type associcated
+ // used to setup the QVariant internals for the "real" inplace ctor
+ QVariant(std::in_place_t, QMetaType type);
+ // helper for emplace
+ void *prepareForEmplace(QMetaType type);
+
+ // These constructors don't create QVariants of the type associated
// with the enum, as expected, but they would create a QVariant of
// type int with the value of the enum value.
// Use QVariant v = QColor(Qt::red) instead of QVariant v = Qt::red for
@@ -534,330 +711,173 @@ public:
inline const DataPtr &data_ptr() const { return d; }
};
-template<>
-inline QVariant QVariant::fromValue(const QVariant &value)
+inline bool QVariant::isValid() const
{
- return value;
+ return d.type().isValid();
}
-#if __has_include(<variant>) && __cplusplus >= 201703L
-template<>
-inline QVariant QVariant::fromValue(const std::monostate &)
+#ifndef QT_NO_DATASTREAM
+Q_CORE_EXPORT QDataStream &operator>>(QDataStream &s, QVariant &p);
+Q_CORE_EXPORT QDataStream &operator<<(QDataStream &s, const QVariant &p);
+
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+QT_DEPRECATED_VERSION_6_0
+inline QDataStream &operator>>(QDataStream &s, QVariant::Type &p)
{
- return QVariant();
+ quint32 u;
+ s >> u;
+ p = static_cast<QVariant::Type>(u);
+ return s;
}
-#endif
-
-inline bool QVariant::isValid() const
+QT_DEPRECATED_VERSION_6_0
+inline QDataStream &operator<<(QDataStream &s, const QVariant::Type p)
{
- return d.type().isValid();
+ s << static_cast<quint32>(p);
+ return s;
}
+QT_WARNING_POP
+#endif
-#ifndef QT_NO_DATASTREAM
-Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant& p);
-Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant& p);
-Q_CORE_EXPORT QDataStream& operator>> (QDataStream& s, QVariant::Type& p);
-Q_CORE_EXPORT QDataStream& operator<< (QDataStream& s, const QVariant::Type p);
#endif
inline bool QVariant::isDetached() const
{ return !d.is_shared || d.data.shared->ref.loadRelaxed() == 1; }
+inline void swap(QVariant &value1, QVariant &value2) noexcept
+{ value1.swap(value2); }
-#ifdef Q_QDOC
- inline bool operator==(const QVariant &v1, const QVariant &v2);
- inline bool operator!=(const QVariant &v1, const QVariant &v2);
-#else
+#ifndef QT_MOC
-/* Helper class to add one more level of indirection to prevent
- implicit casts.
-*/
-class QVariantComparisonHelper
+template<typename T> inline T qvariant_cast(const QVariant &v)
{
-public:
- inline QVariantComparisonHelper(const QVariant &var)
- : v(&var) {}
-private:
- friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &);
- const QVariant *v;
-};
+ QMetaType targetType = QMetaType::fromType<T>();
+ if (v.d.type() == targetType)
+ return v.d.get<T>();
+ if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
+ using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
+ QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
+ if (v.d.type() == nonConstTargetType)
+ return v.d.get<nonConstT>();
+ }
-inline bool operator==(const QVariant &v1, const QVariantComparisonHelper &v2)
-{
- return v1.cmp(*v2.v);
+ T t{};
+ QMetaType::convert(v.metaType(), v.constData(), targetType, &t);
+ return t;
}
-inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2)
+template<typename T> inline T qvariant_cast(QVariant &&v)
{
- return !operator==(v1, v2);
+ QMetaType targetType = QMetaType::fromType<T>();
+ if (v.d.type() == targetType) {
+ if constexpr (QVariant::Private::CanUseInternalSpace<T>) {
+ return std::move(*reinterpret_cast<T *>(v.d.data.data));
+ } else {
+ if (v.d.data.shared->ref.loadRelaxed() == 1)
+ return std::move(*reinterpret_cast<T *>(v.d.data.shared->data()));
+ else
+ return v.d.get<T>();
+ }
+ }
+ if constexpr (std::is_same_v<T, QVariant>) {
+ // if the metatype doesn't match, but we want a QVariant, just return the current variant
+ return v;
+ } if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
+ // moving a pointer is pointless, just do the same as the const & overload
+ using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
+ QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
+ if (v.d.type() == nonConstTargetType)
+ return v.d.get<nonConstT>();
+ }
+
+ T t{};
+ QMetaType::convert(v.metaType(), v.constData(), targetType, &t);
+ return t;
}
-#endif
-Q_DECLARE_SHARED(QVariant)
-class Q_CORE_EXPORT QSequentialIterable
+# ifndef QT_NO_VARIANT
+template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v)
{
- QtMetaTypePrivate::QSequentialIterableImpl m_impl;
-public:
- struct Q_CORE_EXPORT const_iterator
- {
- private:
- QtMetaTypePrivate::QSequentialIterableImpl m_impl;
- QAtomicInt *ref;
- friend class QSequentialIterable;
- explicit const_iterator(const QSequentialIterable &iter, QAtomicInt *ref_);
-
- explicit const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref_);
-
- void begin();
- void end();
- public:
- ~const_iterator();
-
- const_iterator(const const_iterator &other);
-
- const_iterator& operator=(const const_iterator &other);
-
- const QVariant operator*() const;
- bool operator==(const const_iterator &o) const;
- bool operator!=(const const_iterator &o) const;
- const_iterator &operator++();
- const_iterator operator++(int);
- const_iterator &operator--();
- const_iterator operator--(int);
- const_iterator &operator+=(int j);
- const_iterator &operator-=(int j);
- const_iterator operator+(int j) const;
- const_iterator operator-(int j) const;
- friend inline const_iterator operator+(int j, const const_iterator &k) { return k + j; }
- };
-
- friend struct const_iterator;
-
- explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl);
-
- const_iterator begin() const;
- const_iterator end() const;
+ if (v.metaType().id() == QMetaType::QVariant)
+ return *reinterpret_cast<const QVariant *>(v.constData());
+ return v;
+}
+# endif
- QVariant at(int idx) const;
- int size() const;
+#endif // QT_MOC
- bool canReverseIterate() const;
-};
+#ifndef QT_NO_DEBUG_STREAM
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+QT_DEPRECATED_VERSION_6_0
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type);
+QT_WARNING_POP
+#endif
+#endif
-class Q_CORE_EXPORT QAssociativeIterable
+namespace QtPrivate {
+class Q_CORE_EXPORT QVariantTypeCoercer
{
- QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
public:
- struct Q_CORE_EXPORT const_iterator
- {
- private:
- QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
- QAtomicInt *ref;
- friend class QAssociativeIterable;
- explicit const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_);
-
- explicit const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_);
+ // ### Qt7: Pass QMetaType as value rather than const ref.
+ const void *convert(const QVariant &value, const QMetaType &type);
+ const void *coerce(const QVariant &value, const QMetaType &type);
- void begin();
- void end();
- void find(const QVariant &key);
- public:
- ~const_iterator();
- const_iterator(const const_iterator &other);
-
- const_iterator& operator=(const const_iterator &other);
-
- const QVariant key() const;
-
- const QVariant value() const;
-
- const QVariant operator*() const;
- bool operator==(const const_iterator &o) const;
- bool operator!=(const const_iterator &o) const;
- const_iterator &operator++();
- const_iterator operator++(int);
- const_iterator &operator--();
- const_iterator operator--(int);
- const_iterator &operator+=(int j);
- const_iterator &operator-=(int j);
- const_iterator operator+(int j) const;
- const_iterator operator-(int j) const;
- friend inline const_iterator operator+(int j, const const_iterator &k) { return k + j; }
- };
-
- friend struct const_iterator;
-
- explicit QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl);
+private:
+ QVariant converted;
+};
+}
- const_iterator begin() const;
- const_iterator end() const;
- const_iterator find(const QVariant &key) const;
+template<typename Pointer>
+class QVariantRef
+{
+private:
+ const Pointer *m_pointer = nullptr;
- QVariant value(const QVariant &key) const;
+public:
+ explicit QVariantRef(const Pointer *reference) : m_pointer(reference) {}
+ QVariantRef(const QVariantRef &) = default;
+ QVariantRef(QVariantRef &&) = default;
+ ~QVariantRef() = default;
- int size() const;
-};
+ operator QVariant() const;
+ QVariantRef &operator=(const QVariant &value);
+ QVariantRef &operator=(const QVariantRef &value) { return operator=(QVariant(value)); }
+ QVariantRef &operator=(QVariantRef &&value) { return operator=(QVariant(value)); }
-#ifndef QT_MOC
-namespace QtPrivate {
- template<typename T>
- struct QVariantValueHelper : TreatAsQObjectBeforeMetaType<QVariantValueHelper<T>, T, const QVariant &, T>
+ friend void swap(QVariantRef a, QVariantRef b)
{
- static T metaType(const QVariant &v)
- {
- const int vid = qMetaTypeId<T>();
- if (vid == v.userType())
- return *reinterpret_cast<const T *>(v.constData());
- T t;
- if (v.convert(vid, &t))
- return t;
- return T();
- }
-#ifndef QT_NO_QOBJECT
- static T object(const QVariant &v)
- {
- return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject
- ? v.d.data.o
- : QVariantValueHelper::metaType(v));
- }
-#endif
- };
+ QVariant tmp = a;
+ a = b;
+ b = std::move(tmp);
+ }
+};
- template<typename T>
- struct QVariantValueHelperInterface : QVariantValueHelper<T>
- {
- };
+class Q_CORE_EXPORT QVariantConstPointer
+{
+private:
+ QVariant m_variant;
- template<>
- struct QVariantValueHelperInterface<QSequentialIterable>
- {
- static QSequentialIterable invoke(const QVariant &v)
- {
- const int typeId = v.userType();
- if (typeId == qMetaTypeId<QVariantList>()) {
- return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QVariantList*>(v.constData())));
- }
- if (typeId == qMetaTypeId<QStringList>()) {
- return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData())));
- }
-#ifndef QT_BOOTSTRAPPED
- if (typeId == qMetaTypeId<QByteArrayList>()) {
- return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QByteArrayList*>(v.constData())));
- }
-#endif
- return QSequentialIterable(qvariant_cast<QtMetaTypePrivate::QSequentialIterableImpl>(v));
- }
- };
- template<>
- struct QVariantValueHelperInterface<QAssociativeIterable>
- {
- static QAssociativeIterable invoke(const QVariant &v)
- {
- const int typeId = v.userType();
- if (typeId == qMetaTypeId<QVariantMap>()) {
- return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantMap*>(v.constData())));
- }
- if (typeId == qMetaTypeId<QVariantHash>()) {
- return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantHash*>(v.constData())));
- }
- return QAssociativeIterable(qvariant_cast<QtMetaTypePrivate::QAssociativeIterableImpl>(v));
- }
- };
- template<>
- struct QVariantValueHelperInterface<QVariantList>
- {
- static QVariantList invoke(const QVariant &v)
- {
- const int typeId = v.userType();
- if (typeId == qMetaTypeId<QStringList>() || typeId == qMetaTypeId<QByteArrayList>() ||
- (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantList>()))) {
- QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v);
- QVariantList l;
- l.reserve(iter.size());
- for (QSequentialIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
- l << *it;
- return l;
- }
- return QVariantValueHelper<QVariantList>::invoke(v);
- }
- };
- template<>
- struct QVariantValueHelperInterface<QVariantHash>
- {
- static QVariantHash invoke(const QVariant &v)
- {
- const int typeId = v.userType();
- if (typeId == qMetaTypeId<QVariantMap>() || ((QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantHash>()))) {
- QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v);
- QVariantHash l;
- l.reserve(iter.size());
- for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
- l.insert(it.key().toString(), it.value());
- return l;
- }
- return QVariantValueHelper<QVariantHash>::invoke(v);
- }
- };
- template<>
- struct QVariantValueHelperInterface<QVariantMap>
- {
- static QVariantMap invoke(const QVariant &v)
- {
- const int typeId = v.userType();
- if (typeId == qMetaTypeId<QVariantHash>() || (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()) && !QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QVariantMap>()))) {
- QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v);
- QVariantMap l;
- for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
- static_cast<QMultiMap<QString, QVariant> &>(l).insert(it.key().toString(), it.value());
- return l;
- }
- return QVariantValueHelper<QVariantMap>::invoke(v);
- }
- };
- template<>
- struct QVariantValueHelperInterface<QPair<QVariant, QVariant> >
- {
- static QPair<QVariant, QVariant> invoke(const QVariant &v)
- {
- const int typeId = v.userType();
-
- if (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>()) && !(typeId == qMetaTypeId<QPair<QVariant, QVariant> >())) {
- QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
- const QtMetaTypePrivate::VariantData d1 = pi.first();
- QVariant v1(d1.metaTypeId, d1.data, d1.flags);
- if (d1.metaTypeId == qMetaTypeId<QVariant>())
- v1 = *reinterpret_cast<const QVariant*>(d1.data);
-
- const QtMetaTypePrivate::VariantData d2 = pi.second();
- QVariant v2(d2.metaTypeId, d2.data, d2.flags);
- if (d2.metaTypeId == qMetaTypeId<QVariant>())
- v2 = *reinterpret_cast<const QVariant*>(d2.data);
-
- return QPair<QVariant, QVariant>(v1, v2);
- }
- return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v);
- }
- };
-}
+public:
+ explicit QVariantConstPointer(QVariant variant);
-template<typename T> inline T qvariant_cast(const QVariant &v)
-{
- return QtPrivate::QVariantValueHelperInterface<T>::invoke(v);
-}
+ QVariant operator*() const;
+ const QVariant *operator->() const;
+};
-template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v)
+template<typename Pointer>
+class QVariantPointer
{
- if (v.userType() == QMetaType::QVariant)
- return *reinterpret_cast<const QVariant *>(v.constData());
- return v;
-}
-
-#endif
+private:
+ const Pointer *m_pointer = nullptr;
-#ifndef QT_NO_DEBUG_STREAM
-Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant &);
-Q_CORE_EXPORT QDebug operator<<(QDebug, const QVariant::Type);
-#endif
+public:
+ explicit QVariantPointer(const Pointer *pointer) : m_pointer(pointer) {}
+ QVariantRef<Pointer> operator*() const { return QVariantRef<Pointer>(m_pointer); }
+ Pointer operator->() const { return *m_pointer; }
+};
QT_END_NAMESPACE