diff options
Diffstat (limited to 'src/corelib/kernel/qobjectdefs.h')
-rw-r--r-- | src/corelib/kernel/qobjectdefs.h | 365 |
1 files changed, 299 insertions, 66 deletions
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 8309e43d89..190901d5d1 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -11,6 +11,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qobjectdefs_impl.h> +#include <QtCore/qtcoreexports.h> #include <QtCore/qtmetamacros.h> QT_BEGIN_NAMESPACE @@ -59,8 +60,8 @@ Q_CORE_EXPORT const char *qFlagLocation(const char *method); # endif #endif // QT_NO_META_MACROS -#define Q_ARG(type, data) QArgument<type >(#type, data) -#define Q_RETURN_ARG(type, data) QReturnArgument<type >(#type, data) +#define Q_ARG(Type, data) QtPrivate::Invoke::argument<Type>(QT_STRINGIFY(Type), data) +#define Q_RETURN_ARG(Type, data) QtPrivate::Invoke::returnArgument<Type>(QT_STRINGIFY(Type), data) class QObject; class QMetaMethod; @@ -70,6 +71,7 @@ class QMetaClassInfo; namespace QtPrivate { class QMetaTypeInterface; +template<typename T> constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType(); } struct QMethodRawArguments @@ -77,6 +79,7 @@ struct QMethodRawArguments void **arguments; }; +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) class Q_CORE_EXPORT QGenericArgument { public: @@ -124,6 +127,108 @@ public: : QGenericReturnArgument(aName, static_cast<void *>(&aData)) {} }; +#endif + +struct QMetaMethodArgument +{ + const QtPrivate::QMetaTypeInterface *metaType; + const char *name; + const void *data; +}; + +struct QMetaMethodReturnArgument +{ + const QtPrivate::QMetaTypeInterface *metaType; + const char *name; + void *data; +}; + +template <typename T> +struct QTemplatedMetaMethodReturnArgument : QMetaMethodReturnArgument +{ + using Type = T; +}; + +namespace QtPrivate { +namespace Invoke { +#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) +template <typename... Args> +using AreOldStyleArgs = std::disjunction<std::is_base_of<QGenericArgument, Args>...>; + +template <typename T, typename... Args> using IfNotOldStyleArgs = + std::enable_if_t<!AreOldStyleArgs<Args...>::value, T>; +#else +template <typename T, typename... Args> using IfNotOldStyleArgs = T; +#endif + +template <typename T> inline QMetaMethodArgument argument(const char *name, const T &t) +{ + if constexpr ((std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>) || + !std::is_reference_v<T>) { + return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) }; + } else { + return { nullptr, name, std::addressof(t) }; + } +} + +template <typename T> +inline QTemplatedMetaMethodReturnArgument<T> returnArgument(const char *name, T &t) +{ + return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) }; +} + +template <typename T> inline const char *typenameHelper(const T &) +{ + return nullptr; +} +template <typename T> inline const void *dataHelper(const T &t) +{ + return std::addressof(t); +} +template <typename T> inline const QMetaTypeInterface *metaTypeHelper(const T &) +{ + return qMetaTypeInterfaceForType<T>(); +} + +inline const char *typenameHelper(QMetaMethodArgument a) +{ return a.name; } +inline const void *dataHelper(QMetaMethodArgument a) +{ return a.data; } +inline const QMetaTypeInterface *metaTypeHelper(QMetaMethodArgument a) +{ return a.metaType; } + +inline const char *typenameHelper(const char *) = delete; +template <typename T> inline const void *dataHelper(const char *) = delete; +inline const QMetaTypeInterface *metaTypeHelper(const char *) = delete; +inline const char *typenameHelper(const char16_t *) = delete; +template <typename T> inline const void *dataHelper(const char16_t *) = delete; +inline const QMetaTypeInterface *metaTypeHelper(const char16_t *) = delete; + +} // namespace QtPrivate::Invoke + +template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, const Args &... arguments) +{ + std::array params = { const_cast<const void *>(r.data), Invoke::dataHelper(arguments)... }; + std::array names = { r.name, Invoke::typenameHelper(arguments)... }; + std::array types = { r.metaType, Invoke::metaTypeHelper(arguments)... }; + static_assert(params.size() == types.size()); + static_assert(params.size() == names.size()); + + struct R { + decltype(params) parameters; + decltype(names) typeNames; + decltype(types) metaTypes; + constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); } + }; + return R { params, names, types }; +} +} // namespace QtPrivate + +template <typename T> void qReturnArg(const T &&) = delete; +template <typename T> inline QTemplatedMetaMethodReturnArgument<T> qReturnArg(T &data) +{ + return QtPrivate::Invoke::returnArgument(nullptr, data); +} struct Q_CORE_EXPORT QMetaObject { @@ -136,7 +241,7 @@ struct Q_CORE_EXPORT QMetaObject { return const_cast<QObject *>(cast(const_cast<const QObject *>(obj))); } const QObject *cast(const QObject *obj) const; -#if !defined(QT_NO_TRANSLATION) || defined(Q_CLANG_QDOC) +#if !defined(QT_NO_TRANSLATION) || defined(Q_QDOC) QString tr(const char *s, const char *c, int n = -1) const; #endif // QT_NO_TRANSLATION @@ -158,6 +263,7 @@ struct Q_CORE_EXPORT QMetaObject int indexOfSignal(const char *signal) const; int indexOfSlot(const char *slot) const; int indexOfEnumerator(const char *name) const; + int indexOfProperty(const char *name) const; int indexOfClassInfo(const char *name) const; @@ -191,6 +297,7 @@ struct Q_CORE_EXPORT QMetaObject static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv); static void activate(QObject *sender, int signal_offset, int local_signal_index, void **argv); +#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, @@ -224,7 +331,7 @@ struct Q_CORE_EXPORT QMetaObject static inline bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, - QGenericArgument val0 = QGenericArgument(nullptr), + QGenericArgument val0, QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -240,7 +347,7 @@ struct Q_CORE_EXPORT QMetaObject } static inline bool invokeMethod(QObject *obj, const char *member, - QGenericArgument val0 = QGenericArgument(nullptr), + QGenericArgument val0, QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -254,89 +361,162 @@ struct Q_CORE_EXPORT QMetaObject return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } +#endif // Qt < 7.0 + + template <typename ReturnArg, typename... Args> static +#ifdef Q_QDOC + bool +#else + QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...> +#endif + invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, + QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments) + { + auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...); + return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(), + h.typeNames.data(), h.metaTypes.data()); + } + + template <typename... Args> static +#ifdef Q_QDOC + bool +#else + QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...> +#endif + invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, Args &&... arguments) + { + QTemplatedMetaMethodReturnArgument<void> r = {}; + return invokeMethod(obj, member, c, r, std::forward<Args>(arguments)...); + } -#ifdef Q_CLANG_QDOC + template <typename ReturnArg, typename... Args> static +#ifdef Q_QDOC + bool +#else + QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...> +#endif + invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> r, + Args &&... arguments) + { + return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...); + } + + template <typename... Args> static +#ifdef Q_QDOC + bool +#else + QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...> +#endif + invokeMethod(QObject *obj, const char *member, Args &&... arguments) + { + QTemplatedMetaMethodReturnArgument<void> r = {}; + return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...); + } + +#ifdef Q_QDOC template<typename Functor, typename FunctorReturnType> - static bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr); + static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr); template<typename Functor, typename FunctorReturnType> - static bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret); + static bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret); + + template<typename Functor, typename FunctorReturnType, typename... Args> + static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments); + template<typename Functor, typename FunctorReturnType, typename... Args> + static bool invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments); + template<typename Functor, typename... Args> + static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments); + template<typename Functor, typename... Args> + static bool invokeMethod(QObject *context, Functor &&function, Args &&...arguments); #else - - // invokeMethod() for member function pointer template <typename Func> - static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && !std::is_convertible<Func, const char*>::value - && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type - invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object, - Func function, - Qt::ConnectionType type = Qt::AutoConnection, - typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr) + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Func>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, Qt::ConnectionType type, + typename QtPrivate::Callable<Func>::ReturnType *ret) { - return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret); + using R = typename QtPrivate::Callable<Func>::ReturnType; + const auto getReturnArg = [ret]() -> QTemplatedMetaMethodReturnArgument<R> { + if constexpr (std::is_void_v<R>) + return {}; + else + return ret ? qReturnArg(*ret) : QTemplatedMetaMethodReturnArgument<R>{}; + }; + return invokeMethod(object, std::forward<Func>(function), type, getReturnArg()); } - template <typename Func> - static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && !std::is_convertible<Func, const char*>::value - && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type - invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object, - Func function, - typename QtPrivate::FunctionPointer<Func>::ReturnType *ret) + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Func>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, typename QtPrivate::Callable<Func>::ReturnType *ret) { - return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret); + return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret); } - // invokeMethod() for function pointer (not member) - template <typename Func> - static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && !std::is_convertible<Func, const char*>::value - && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type - invokeMethod(QObject *context, Func function, - Qt::ConnectionType type = Qt::AutoConnection, - typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr) + template <typename Func, typename... Args> + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Args...>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, Qt::ConnectionType type, + QTemplatedMetaMethodReturnArgument< + typename QtPrivate::Callable<Func, Args...>::ReturnType> + ret, + Args &&...args) { - return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret); + return invokeMethodCallableHelper(object, std::forward<Func>(function), type, ret, + std::forward<Args>(args)...); } - template <typename Func> - static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && !std::is_convertible<Func, const char*>::value - && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type - invokeMethod(QObject *context, Func function, - typename QtPrivate::FunctionPointer<Func>::ReturnType *ret) + template <typename Func, typename... Args> + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Args...>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, Qt::ConnectionType type, Args &&...args) { - return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret); + using R = typename QtPrivate::Callable<Func, Args...>::ReturnType; + QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr, + nullptr }; + return invokeMethod(object, std::forward<Func>(function), type, r, + std::forward<Args>(args)...); } - // invokeMethod() for Functor - template <typename Func> - static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1 - && !std::is_convertible<Func, const char*>::value, bool>::type - invokeMethod(QObject *context, Func function, - Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr) + template <typename Func, typename... Args> + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Args...>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, + QTemplatedMetaMethodReturnArgument< + typename QtPrivate::Callable<Func, Args...>::ReturnType> + ret, + Args &&...args) { - return invokeMethodImpl(context, - new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)), - type, - ret); + return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret, + std::forward<Args>(args)...); } - template <typename Func> - static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction - && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1 - && !std::is_convertible<Func, const char*>::value, bool>::type - invokeMethod(QObject *context, Func function, decltype(function()) *ret) + template <typename Func, typename... Args> + static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>, + QtPrivate::Invoke::AreOldStyleArgs<Args...>>, + bool> + invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, Args &&...args) { - return invokeMethodImpl(context, - new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)), - Qt::AutoConnection, - ret); + using R = typename QtPrivate::Callable<Func, Args...>::ReturnType; + QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr, + nullptr }; + return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, r, + std::forward<Args>(args)...); } #endif - QObject *newInstance(QGenericArgument val0 = QGenericArgument(nullptr), +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + QObject *newInstance(QGenericArgument val0, QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), @@ -346,6 +526,20 @@ struct Q_CORE_EXPORT QMetaObject QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) const; +#endif + + template <typename... Args> +#ifdef Q_QDOC + QObject * +#else + QtPrivate::Invoke::IfNotOldStyleArgs<QObject *, Args...> +#endif + newInstance(Args &&... arguments) const + { + auto h = QtPrivate::invokeMethodHelper(QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...); + return newInstanceImpl(this, h.parameterCount(), h.parameters.data(), + h.typeNames.data(), h.metaTypes.data()); + } enum Call { InvokeMetaMethod, @@ -357,7 +551,8 @@ struct Q_CORE_EXPORT QMetaObject RegisterPropertyMetaType, RegisterMethodArgumentMetaType, BindableProperty, - CustomCall + CustomCall, + ConstructInPlace, }; int static_metacall(Call, int, void **) const; @@ -405,8 +600,46 @@ struct Q_CORE_EXPORT QMetaObject } d; private: + // Just need to have this here with a separate name so the other inline + // functions can call this without any ambiguity + template <typename Func, typename... Args> + static bool + invokeMethodCallableHelper(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object, + Func &&function, Qt::ConnectionType type, const QMetaMethodReturnArgument &ret, + Args &&...args) + { + using Callable = QtPrivate::Callable<Func, Args...>; + using ExpectedArguments = typename Callable::Arguments; + static_assert(sizeof...(Args) <= ExpectedArguments::size, "Too many arguments"); + using ActualArguments = QtPrivate::List<Args...>; + static_assert(QtPrivate::CheckCompatibleArguments<ActualArguments, + ExpectedArguments>::value, + "Incompatible arguments"); + + auto h = QtPrivate::invokeMethodHelper(ret, std::forward<Args>(args)...); + + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + auto callable = new QtPrivate::QCallableObject<std::decay_t<Func>, ActualArguments, + typename Callable::ReturnType>(std::forward<Func>(function)); + return invokeMethodImpl(object, callable, type, h.parameterCount(), h.parameters.data(), + h.typeNames.data(), h.metaTypes.data()); + } + + static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type, + qsizetype parameterCount, const void *const *parameters, const char *const *names, + const QtPrivate::QMetaTypeInterface * const *metaTypes); + static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, + Qt::ConnectionType type, qsizetype parameterCount, + const void *const *params, const char *const *names, + const QtPrivate::QMetaTypeInterface *const *metaTypes); +#if QT_CORE_REMOVED_SINCE(6, 7) static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret); +#endif + static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount, + const void **parameters, const char **typeNames, + const QtPrivate::QMetaTypeInterface **metaTypes); friend class QTimer; + friend class QChronoTimer; }; class Q_CORE_EXPORT QMetaObject::Connection { @@ -430,7 +663,7 @@ public: operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : nullptr; } #endif - Connection(Connection &&other) noexcept : d_ptr(qExchange(other.d_ptr, nullptr)) {} + Connection(Connection &&other) noexcept : d_ptr(std::exchange(other.d_ptr, nullptr)) {} QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Connection) void swap(Connection &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); } }; @@ -444,7 +677,7 @@ inline const QMetaObject *QMetaObject::superClass() const { return d.superdata; } namespace QtPrivate { - /* Trait that tells is a the Object has a Q_OBJECT macro */ + // Trait that tells if a QObject has a Q_OBJECT macro template <typename Object> struct HasQ_OBJECT_Macro { template <typename T> static char test(int (T::*)(QMetaObject::Call, int, void **)); |