1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.objectdefs_impl;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.atomic;
17 import qt.core.object;
18 import qt.helpers;
19 
20 /+ #ifndef QOBJECTDEFS_H
21 #error Do not include qobjectdefs_impl.h directly
22 #endif
23 
24 #if 0
25 #pragma qt_sync_skip_header_check
26 #pragma qt_sync_stop_processing
27 #endif +/
28 
29 
30 extern(C++, "QtPrivate") {
31     /+ template <typename T> struct RemoveRef { typedef T Type; };
32     template <typename T> struct RemoveRef<T&> { typedef T Type; };
33     template <typename T> struct RemoveConstRef { typedef T Type; };
34     template <typename T> struct RemoveConstRef<const T&> { typedef T Type; };
35 
36     /*
37        The following List classes are used to help to handle the list of arguments.
38        It follow the same principles as the lisp lists.
39        List_Left<L,N> take a list and a number as a parameter and returns (via the Value typedef,
40        the list composed of the first N element of the list
41      */
42     // With variadic template, lists are represented using a variadic template argument instead of the lisp way
43     template <typename...> struct List {};
44     template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; };
45     template <typename, typename> struct List_Append;
46     template <typename... L1, typename...L2> struct List_Append<List<L1...>, List<L2...>> { typedef List<L1..., L2...> Value; };
47     template <typename L, int N> struct List_Left {
48         typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value;
49     };
50     template <typename L> struct List_Left<L, 0> { typedef List<> Value; };
51     // List_Select<L,N> returns (via typedef Value) the Nth element of the list L
52     template <typename L, int N> struct List_Select { typedef typename List_Select<typename L::Cdr, N - 1>::Value Value; };
53     template <typename L> struct List_Select<L,0> { typedef typename L::Car Value; };
54 
55     /*
56        trick to set the return value of a slot that works even if the signal or the slot returns void
57        to be used like     function(), ApplyReturnValue<ReturnType>(&return_value)
58        if function() returns a value, the operator,(T, ApplyReturnValue<ReturnType>) is called, but if it
59        returns void, the builtin one is used without an error.
60     */
61     template <typename T>
62     struct ApplyReturnValue {
63         void *data;
64         explicit ApplyReturnValue(void *data_) : data(data_) {}
65     };
66     template<typename T, typename U>
67     void operator,(T &&value, const ApplyReturnValue<U> &container) {
68         if (container.data)
69             *reinterpret_cast<U *>(container.data) = std::forward<T>(value);
70     } +/
71     /+void operator ,(T)(T, ref const(ApplyReturnValue!(void)) ) {}+/
72 
73 
74     /*
75       The FunctionPointer<Func> struct is a type trait for function pointer.
76         - ArgumentCount  is the number of argument, or -1 if it is unknown
77         - the Object typedef is the Object of a pointer to member function
78         - the Arguments typedef is the list of argument (in a QtPrivate::List)
79         - the Function typedef is an alias to the template parameter Func
80         - the call<Args, R>(f,o,args) method is used to call that slot
81             Args is the list of argument of the signal
82             R is the return type of the signal
83             f is the function pointer
84             o is the receiver object
85             and args is the array of pointer to arguments, as used in qt_metacall
86 
87        The Functor<Func,N> struct is the helper to call a functor of N argument.
88        its call function is the same as the FunctionPointer::call function.
89      */
90     /+ template<class T> using InvokeGenSeq = typename T::Type;
91 
92     template<int...> struct IndexesList { using Type = IndexesList; };
93 
94     template<int N, class S1, class S2> struct ConcatSeqImpl;
95 
96     template<int N, int... I1, int... I2>
97     struct ConcatSeqImpl<N, IndexesList<I1...>, IndexesList<I2...>>
98         : IndexesList<I1..., (N + I2)...>{};
99 
100     template<int N, class S1, class S2>
101     using ConcatSeq = InvokeGenSeq<ConcatSeqImpl<N, S1, S2>>;
102 
103     template<int N> struct GenSeq;
104     template<int N> using makeIndexSequence = InvokeGenSeq<GenSeq<N>>;
105 
106     template<int N>
107     struct GenSeq : ConcatSeq<N/2, makeIndexSequence<N/2>, makeIndexSequence<N - N/2>>{};
108 
109     template<> struct GenSeq<0> : IndexesList<>{};
110     template<> struct GenSeq<1> : IndexesList<0>{};
111 
112     template<int N>
113     struct Indexes { using Value = makeIndexSequence<N>; };
114 
115     template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
116 
117     template <typename, typename, typename, typename> struct FunctorCall;
118     template <int... II, typename... SignalArgs, typename R, typename Function>
119     struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
120         static void call(Function &f, void **arg) {
121             f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
122         }
123     };
124     template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
125     struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> {
126         static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) {
127             (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
128         }
129     };
130     template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
131     struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const> {
132         static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg) {
133             (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
134         }
135     };
136 #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
137     template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
138     struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> {
139         static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg) {
140             (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
141         }
142     };
143     template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
144     struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> {
145         static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg) {
146             (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
147         }
148     };
149 #endif
150 
151     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
152     {
153         typedef Obj Object;
154         typedef List<Args...>  Arguments;
155         typedef Ret ReturnType;
156         typedef Ret (Obj::*Function) (Args...);
157         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
158         template <typename SignalArgs, typename R>
159         static void call(Function f, Obj *o, void **arg) {
160             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
161         }
162     };
163     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const>
164     {
165         typedef Obj Object;
166         typedef List<Args...>  Arguments;
167         typedef Ret ReturnType;
168         typedef Ret (Obj::*Function) (Args...) const;
169         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
170         template <typename SignalArgs, typename R>
171         static void call(Function f, Obj *o, void **arg) {
172             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
173         }
174     };
175 
176     template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...)>
177     {
178         typedef List<Args...> Arguments;
179         typedef Ret ReturnType;
180         typedef Ret (*Function) (Args...);
181         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
182         template <typename SignalArgs, typename R>
183         static void call(Function f, void *, void **arg) {
184             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
185         }
186     };
187 
188 #if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
189     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) noexcept>
190     {
191         typedef Obj Object;
192         typedef List<Args...>  Arguments;
193         typedef Ret ReturnType;
194         typedef Ret (Obj::*Function) (Args...) noexcept;
195         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
196         template <typename SignalArgs, typename R>
197         static void call(Function f, Obj *o, void **arg) {
198             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
199         }
200     };
201     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const noexcept>
202     {
203         typedef Obj Object;
204         typedef List<Args...>  Arguments;
205         typedef Ret ReturnType;
206         typedef Ret (Obj::*Function) (Args...) const noexcept;
207         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
208         template <typename SignalArgs, typename R>
209         static void call(Function f, Obj *o, void **arg) {
210             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
211         }
212     };
213 
214     template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...) noexcept>
215     {
216         typedef List<Args...> Arguments;
217         typedef Ret ReturnType;
218         typedef Ret (*Function) (Args...) noexcept;
219         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
220         template <typename SignalArgs, typename R>
221         static void call(Function f, void *, void **arg) {
222             FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
223         }
224     };
225 #endif
226 
227     template<typename Function, int N> struct Functor
228     {
229         template <typename SignalArgs, typename R>
230         static void call(Function &f, void *, void **arg) {
231             FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg);
232         }
233     }; +/
234 
235     // Traits to detect if there is a conversion between two types,
236     // and that conversion does not include a narrowing conversion.
237     struct NarrowingDetector(T) { T[1] t; } // from P0608
238 
239     struct IsConvertibleWithoutNarrowing(From, To, Enable) {
240         /+ std:: +/false_type base0;
241         alias base0 this;
242 }
243 
244     /+ template <typename From, typename To>
245     struct IsConvertibleWithoutNarrowing<From, To,
246             std::void_t< decltype( NarrowingDetector<To>{ {std::declval<From>()} } ) >
247         > : std::true_type {}; +/
248 
249     // Check for the actual arguments. If they are exactly the same,
250     // then don't bother checking for narrowing; as a by-product,
251     // this solves the problem of incomplete types (which must be supported,
252     // or they would error out in the trait above).
253     struct AreArgumentsConvertibleWithoutNarrowingBase(From, To, Enable) {
254         /+ std:: +/false_type base0;
255         alias base0 this;
256 }
257 
258     /+ template <typename From, typename To>
259     struct AreArgumentsConvertibleWithoutNarrowingBase<From, To,
260         std::enable_if_t<
261             std::disjunction_v<std::is_same<From, To>, IsConvertibleWithoutNarrowing<From, To>>
262         >
263     > : std::true_type {};
264 
265     /*
266        Logic that check if the arguments of the slot matches the argument of the signal.
267        To be used like this:
268        static_assert(CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::value)
269     */
270     template<typename A1, typename A2> struct AreArgumentsCompatible {
271         static int test(const typename RemoveRef<A2>::Type&);
272         static char test(...);
273         static const typename RemoveRef<A1>::Type &dummy();
274         enum { value = sizeof(test(dummy())) == sizeof(int) };
275 #ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
276         using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase<std::decay_t<A1>, std::decay_t<A2>>;
277         static_assert(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)");
278 #endif
279     };
280     template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; };
281     template<typename A> struct AreArgumentsCompatible<A&, A&> { enum { value = true }; };
282     // void as a return value
283     template<typename A> struct AreArgumentsCompatible<void, A> { enum { value = true }; };
284     template<typename A> struct AreArgumentsCompatible<A, void> { enum { value = true }; };
285     template<> struct AreArgumentsCompatible<void, void> { enum { value = true }; };
286 
287     template <typename List1, typename List2> struct CheckCompatibleArguments { enum { value = false }; };
288     template <> struct CheckCompatibleArguments<List<>, List<>> { enum { value = true }; };
289     template <typename List1> struct CheckCompatibleArguments<List1, List<>> { enum { value = true }; };
290     template <typename Arg1, typename Arg2, typename... Tail1, typename... Tail2>
291     struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
292     {
293         enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
294                     && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
295     };
296 
297     /*
298        Find the maximum number of arguments a functor object can take and be still compatible with
299        the arguments from the signal.
300        Value is the number of arguments, or -1 if nothing matches.
301      */
302     template <typename Functor, typename ArgList> struct ComputeFunctorArgumentCount;
303 
304     template <typename Functor, typename ArgList, bool Done> struct ComputeFunctorArgumentCountHelper
305     { enum { Value = -1 }; };
306     template <typename Functor, typename First, typename... ArgList>
307     struct ComputeFunctorArgumentCountHelper<Functor, List<First, ArgList...>, false>
308         : ComputeFunctorArgumentCount<Functor,
309             typename List_Left<List<First, ArgList...>, sizeof...(ArgList)>::Value> {};
310 
311     template <typename Functor, typename... ArgList> struct ComputeFunctorArgumentCount<Functor, List<ArgList...>>
312     {
313         template <typename D> static D dummy();
314         template <typename F> static auto test(F f) -> decltype(((f.operator()((dummy<ArgList>())...)), int()));
315         static char test(...);
316         enum {
317             Ok = sizeof(test(dummy<Functor>())) == sizeof(int),
318             Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value)
319         };
320     };
321 
322     /* get the return type of a functor, given the signal argument list  */
323     template <typename Functor, typename ArgList> struct FunctorReturnType;
324     template <typename Functor, typename ... ArgList> struct FunctorReturnType<Functor, List<ArgList...>> {
325         template <typename D> static D dummy();
326         typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value;
327     }; +/
328 
329     // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
330     extern(C++, class) struct QSlotObjectBase {
331     private:
332         QAtomicInt m_ref;
333         // don't use virtual functions here; we don't want the
334         // compiler to create tons of per-polymorphic-class stuff that
335         // we'll never need. We just use one function pointer.
336         alias ImplFn = ExternCPPFunc!(void function(int which, QSlotObjectBase* this_, QObject receiver, void** args, bool* ret));
337         const(ImplFn) m_impl;
338     protected:
339         enum Operation {
340             Destroy,
341             Call,
342             Compare,
343 
344             NumOperations
345         }
346     public:
347         /+ explicit +/this(ImplFn fn)
348         {
349             this.m_ref = QAtomicInt(1);
350             this.m_impl = fn;
351         }
352 
353 //        pragma(inline, true) int ref_()/+ noexcept+/ { return m_ref.ref_(); }
354 /*        pragma(inline, true) void destroyIfLastRef()/+ noexcept+/
355         { if (!m_ref.deref()) m_impl(Operation.Destroy, &this, null, null, null); }
356 */
357         pragma(inline, true) bool compare(void** a) { bool ret = false; m_impl(Operation.Compare, &this, null, a, &ret); return ret; }
358         /+ inline void call(QObject *r, void **a)  { m_impl(Call,    this, r, a, nullptr); } +/
359     protected:
360         ~this() {}
361     private:
362         /+ Q_DISABLE_COPY_MOVE(QSlotObjectBase) +/
363 @disable this(this);
364 /+this(ref const(QSlotObjectBase));+//+ref QSlotObjectBase operator =(ref const(QSlotObjectBase));+/    }
365 
366     // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
367     // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
368     /+ template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
369     {
370         typedef QtPrivate::FunctionPointer<Func> FuncType;
371         Func function;
372         static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
373         {
374             switch (which) {
375             case Destroy:
376                 delete static_cast<QSlotObject*>(this_);
377                 break;
378             case Call:
379                 FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
380                 break;
381             case Compare:
382                 *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
383                 break;
384             case NumOperations: ;
385             }
386         }
387     public:
388         explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
389     };
390     // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
391     // N is the number of arguments
392     // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
393     template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
394     {
395         typedef QtPrivate::Functor<Func, N> FuncType;
396         Func function;
397         static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
398         {
399             switch (which) {
400             case Destroy:
401                 delete static_cast<QFunctorSlotObject*>(this_);
402                 break;
403             case Call:
404                 FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
405                 break;
406             case Compare: // not implemented
407             case NumOperations:
408                 Q_UNUSED(ret);
409             }
410         }
411     public:
412         explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {}
413     };
414 
415     // typedefs for readability for when there are no parameters
416     template <typename Func>
417     using QSlotObjectWithNoArgs = QSlotObject<Func,
418                                               QtPrivate::List<>,
419                                               typename QtPrivate::FunctionPointer<Func>::ReturnType>;
420 
421     template <typename Func, typename R>
422     using QFunctorSlotObjectWithNoArgs = QFunctorSlotObject<Func, 0, QtPrivate::List<>, R>;
423 
424     template <typename Func>
425     using QFunctorSlotObjectWithNoArgsImplicitReturn = QFunctorSlotObjectWithNoArgs<Func, typename QtPrivate::FunctionPointer<Func>::ReturnType>; +/
426 }
427 
428 extern(D) struct DQtStaticSlotObject(Params...)
429 {
430     QSlotObjectBase base;
431     alias Dg = void delegate(Params);
432     Dg dg;
433 
434     extern(C++) static void impl(int which, QSlotObjectBase *this_, QObject r, void **a, bool *ret)
435     {
436         import core.stdcpp.new_;
437         switch (which) {
438         case QSlotObjectBase.Operation.Destroy:
439             cpp_delete(cast(DQtStaticSlotObject*)(this_));
440             break;
441         case QSlotObjectBase.Operation.Call:
442             (cast(DQtStaticSlotObject*)(this_)).dg();
443             break;
444         case QSlotObjectBase.Operation.Compare: // not implemented
445         case QSlotObjectBase.Operation.NumOperations:
446             //Q_UNUSED(ret);
447         default:
448         }
449     }
450 public:
451     this(Dg dg)
452     {
453         base = QSlotObjectBase(&impl);
454         this.dg = dg;
455     }
456 }
457 
458 extern(D) struct DQtMemberSlotObject(T, alias F, Params...) if(is(T: QObject))
459 {
460     QSlotObjectBase base;
461 
462     /* Need to use a custom mangling, because the template parameters
463      * may not have a C++ mangling. */
464     pragma(mangle, DQtMemberSlotObject.mangleof ~ "__impl")
465     extern(C++) static void impl(int which, QSlotObjectBase *this_, QObject r, void **a, bool *ret)
466     {
467         import core.stdcpp.new_;
468         import std.traits;
469         switch (which) {
470         case QSlotObjectBase.Operation.Destroy:
471             cpp_delete(cast(DQtMemberSlotObject*)(this_));
472             break;
473         case QSlotObjectBase.Operation.Call:
474             mixin("extern(" ~ functionLinkage!F ~ ") ReturnType!F delegate(Parameters!F) dg;");
475             dg.ptr = cast(void*)r;
476             dg.funcptr = &F;
477             mixin((){
478                 import std.conv;
479                 string r;
480                 r = "dg(";
481                 foreach(i; 0..Params.length)
482                 {
483                     r ~= text("*cast(Params[", i, "]*)a[", i + 1, "], ");
484                 }
485                 r ~= ");";
486                 return r;
487                 }());
488             break;
489         case QSlotObjectBase.Operation.Compare: // not implemented
490         case QSlotObjectBase.Operation.NumOperations:
491             //Q_UNUSED(ret);
492         default:
493         }
494     }
495 public:
496     @disable this();
497     this(int dummy)
498     {
499         base = QSlotObjectBase(&impl);
500     }
501 }