/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2013 Olivier Goffart ** 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$ ** ****************************************************************************/ #ifndef QOBJECTDEFS_H #error Do not include qobjectdefs_impl.h directly #include #endif #if 0 #pragma qt_sync_skip_header_check #pragma qt_sync_stop_processing #endif QT_BEGIN_NAMESPACE class QObject; namespace QtPrivate { template struct RemoveRef { typedef T Type; }; template struct RemoveRef { typedef T Type; }; template struct RemoveConstRef { typedef T Type; }; template struct RemoveConstRef { typedef T Type; }; /* The following List classes are used to help to handle the list of arguments. It follow the same principles as the lisp lists. List_Left take a list and a number as a parameter and returns (via the Value typedef, the list composed of the first N element of the list */ // With variadic template, lists are represented using a variadic template argument instead of the lisp way template struct List {}; template struct List { typedef Head Car; typedef List Cdr; }; template struct List_Append; template struct List_Append, List> { typedef List Value; }; template struct List_Left { typedef typename List_Append,typename List_Left::Value>::Value Value; }; template struct List_Left { typedef List<> Value; }; // List_Select returns (via typedef Value) the Nth element of the list L template struct List_Select { typedef typename List_Select::Value Value; }; template struct List_Select { typedef typename L::Car Value; }; /* trick to set the return value of a slot that works even if the signal or the slot returns void to be used like function(), ApplyReturnValue(&return_value) if function() returns a value, the operator,(T, ApplyReturnValue) is called, but if it returns void, the builtin one is used without an error. */ template struct ApplyReturnValue { void *data; explicit ApplyReturnValue(void *data_) : data(data_) {} }; template void operator,(T &&value, const ApplyReturnValue &container) { if (container.data) *reinterpret_cast(container.data) = std::forward(value); } template void operator,(T, const ApplyReturnValue &) {} /* The FunctionPointer struct is a type trait for function pointer. - ArgumentCount is the number of argument, or -1 if it is unknown - the Object typedef is the Object of a pointer to member function - the Arguments typedef is the list of argument (in a QtPrivate::List) - the Function typedef is an alias to the template parameter Func - the call(f,o,args) method is used to call that slot Args is the list of argument of the signal R is the return type of the signal f is the function pointer o is the receiver object and args is the array of pointer to arguments, as used in qt_metacall The Functor struct is the helper to call a functor of N argument. its call function is the same as the FunctionPointer::call function. */ template using InvokeGenSeq = typename T::Type; template struct IndexesList { using Type = IndexesList; }; template struct ConcatSeqImpl; template struct ConcatSeqImpl, IndexesList> : IndexesList{}; template using ConcatSeq = InvokeGenSeq>; template struct GenSeq; template using makeIndexSequence = InvokeGenSeq>; template struct GenSeq : ConcatSeq, makeIndexSequence>{}; template<> struct GenSeq<0> : IndexesList<>{}; template<> struct GenSeq<1> : IndexesList<0>{}; template struct Indexes { using Value = makeIndexSequence; }; template struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; }; template struct FunctorCall; template struct FunctorCall, List, R, Function> { static void call(Function &f, void **arg) { f((*reinterpret_cast::Type *>(arg[II+1]))...), ApplyReturnValue(arg[0]); } }; template struct FunctorCall, List, R, SlotRet (Obj::*)(SlotArgs...)> { static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), ApplyReturnValue(arg[0]); } }; template struct FunctorCall, List, R, SlotRet (Obj::*)(SlotArgs...) const> { static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), ApplyReturnValue(arg[0]); } }; #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template struct FunctorCall, List, R, SlotRet (Obj::*)(SlotArgs...) noexcept> { static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), ApplyReturnValue(arg[0]); } }; template struct FunctorCall, List, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> { static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg) { (o->*f)((*reinterpret_cast::Type *>(arg[II+1]))...), ApplyReturnValue(arg[0]); } }; #endif template struct FunctionPointer { typedef Obj Object; typedef List Arguments; typedef Ret ReturnType; typedef Ret (Obj::*Function) (Args...); enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true}; template static void call(Function f, Obj *o, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, o, arg); } }; template struct FunctionPointer { typedef Obj Object; typedef List Arguments; typedef Ret ReturnType; typedef Ret (Obj::*Function) (Args...) const; enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true}; template static void call(Function f, Obj *o, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, o, arg); } }; template struct FunctionPointer { typedef List Arguments; typedef Ret ReturnType; typedef Ret (*Function) (Args...); enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false}; template static void call(Function f, void *, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, arg); } }; #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 template struct FunctionPointer { typedef Obj Object; typedef List Arguments; typedef Ret ReturnType; typedef Ret (Obj::*Function) (Args...) noexcept; enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true}; template static void call(Function f, Obj *o, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, o, arg); } }; template struct FunctionPointer { typedef Obj Object; typedef List Arguments; typedef Ret ReturnType; typedef Ret (Obj::*Function) (Args...) const noexcept; enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true}; template static void call(Function f, Obj *o, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, o, arg); } }; template struct FunctionPointer { typedef List Arguments; typedef Ret ReturnType; typedef Ret (*Function) (Args...) noexcept; enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false}; template static void call(Function f, void *, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, arg); } }; #endif template struct Functor { template static void call(Function &f, void *, void **arg) { FunctorCall::Value, SignalArgs, R, Function>::call(f, arg); } }; // Traits to detect if there is a conversion between two types, // and that conversion does not include a narrowing conversion. template struct NarrowingDetector { T t[1]; }; // from P0608 template struct IsConvertibleWithoutNarrowing : std::false_type {}; template struct IsConvertibleWithoutNarrowing{ {std::declval()} } ) > > : std::true_type {}; // Check for the actual arguments. If they are exactly the same, // then don't bother checking for narrowing; as a by-product, // this solves the problem of incomplete types (which must be supported, // or they would error out in the trait above). template struct AreArgumentsConvertibleWithoutNarrowingBase : std::false_type {}; template struct AreArgumentsConvertibleWithoutNarrowingBase, IsConvertibleWithoutNarrowing> > > : std::true_type {}; /* Logic that check if the arguments of the slot matches the argument of the signal. To be used like this: Q_STATIC_ASSERT(CheckCompatibleArguments::Arguments, FunctionPointer::Arguments>::value) */ template struct AreArgumentsCompatible { static int test(const typename RemoveRef::Type&); static char test(...); static const typename RemoveRef::Type &dummy(); enum { value = sizeof(test(dummy())) == sizeof(int) }; #ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase, std::decay_t>; Q_STATIC_ASSERT_X(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)"); #endif }; template struct AreArgumentsCompatible { enum { value = false }; }; template struct AreArgumentsCompatible { enum { value = true }; }; // void as a return value template struct AreArgumentsCompatible { enum { value = true }; }; template struct AreArgumentsCompatible { enum { value = true }; }; template<> struct AreArgumentsCompatible { enum { value = true }; }; template struct CheckCompatibleArguments { enum { value = false }; }; template <> struct CheckCompatibleArguments, List<>> { enum { value = true }; }; template struct CheckCompatibleArguments> { enum { value = true }; }; template struct CheckCompatibleArguments, List> { enum { value = AreArgumentsCompatible::Type, typename RemoveConstRef::Type>::value && CheckCompatibleArguments, List>::value }; }; /* Find the maximum number of arguments a functor object can take and be still compatible with the arguments from the signal. Value is the number of arguments, or -1 if nothing matches. */ template struct ComputeFunctorArgumentCount; template struct ComputeFunctorArgumentCountHelper { enum { Value = -1 }; }; template struct ComputeFunctorArgumentCountHelper, false> : ComputeFunctorArgumentCount, sizeof...(ArgList)>::Value> {}; template struct ComputeFunctorArgumentCount> { template static D dummy(); template static auto test(F f) -> decltype(((f.operator()((dummy())...)), int())); static char test(...); enum { Ok = sizeof(test(dummy())) == sizeof(int), Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper, Ok>::Value) }; }; /* get the return type of a functor, given the signal argument list */ template struct FunctorReturnType; template struct FunctorReturnType> { template static D dummy(); typedef decltype(dummy().operator()((dummy())...)) Value; }; // internal base class (interface) containing functions required to call a slot managed by a pointer to function. class QSlotObjectBase { QAtomicInt m_ref; // don't use virtual functions here; we don't want the // compiler to create tons of per-polymorphic-class stuff that // we'll never need. We just use one function pointer. typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret); const ImplFn m_impl; protected: enum Operation { Destroy, Call, Compare, NumOperations }; public: explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {} inline int ref() noexcept { return m_ref.ref(); } inline void destroyIfLastRef() noexcept { if (!m_ref.deref()) m_impl(Destroy, this, nullptr, nullptr, nullptr); } inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, nullptr, a, &ret); return ret; } inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, nullptr); } protected: ~QSlotObjectBase() {} private: Q_DISABLE_COPY_MOVE(QSlotObjectBase) }; // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject // Args and R are the List of arguments and the return type of the signal to which the slot is connected. template class QSlotObject : public QSlotObjectBase { typedef QtPrivate::FunctionPointer FuncType; Func function; static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) { switch (which) { case Destroy: delete static_cast(this_); break; case Call: FuncType::template call(static_cast(this_)->function, static_cast(r), a); break; case Compare: *ret = *reinterpret_cast(a) == static_cast(this_)->function; break; case NumOperations: ; } } public: explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} }; // implementation of QSlotObjectBase for which the slot is a functor (or lambda) // N is the number of arguments // Args and R are the List of arguments and the return type of the signal to which the slot is connected. template class QFunctorSlotObject : public QSlotObjectBase { typedef QtPrivate::Functor FuncType; Func function; static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) { switch (which) { case Destroy: delete static_cast(this_); break; case Call: FuncType::template call(static_cast(this_)->function, r, a); break; case Compare: // not implemented case NumOperations: Q_UNUSED(ret); } } public: explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {} }; // typedefs for readability for when there are no parameters template using QSlotObjectWithNoArgs = QSlotObject, typename QtPrivate::FunctionPointer::ReturnType>; template using QFunctorSlotObjectWithNoArgs = QFunctorSlotObject, R>; template using QFunctorSlotObjectWithNoArgsImplicitReturn = QFunctorSlotObjectWithNoArgs::ReturnType>; } QT_END_NAMESPACE