1/****************************************************************************
2 * Copyright (C) 2016-2018 Woboq GmbH
3 * Olivier Goffart <ogoffart at woboq.com>
4 * https://woboq.com/
5 *
6 * This file is part of Verdigris: a way to use Qt without moc.
7 * https://github.com/woboq/verdigris
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program.
21 * If not, see <http://www.gnu.org/licenses/>.
22 */
23#pragma once
24
25#ifndef Q_MOC_RUN // don't define anything when moc is run
26
27#include <QtCore/qobjectdefs.h>
28#include <QtCore/qmetatype.h>
29#include <utility>
30
31#define W_VERSION 0x010100
32
33namespace w_internal {
34using std::index_sequence; // From C++14, make sure to enable the C++14 option in your compiler
35
36/* The default std::make_index_sequence from libstdc++ is recursing O(N) times which is reaching
37 recursion limits level for big strings. This implementation has only O(log N) recursion */
38template<size_t... I1, size_t... I2>
39index_sequence<I1... , (I2 +(sizeof...(I1)))...>
40make_index_sequence_helper_merge(index_sequence<I1...>, index_sequence<I2...>);
41
42template<std::size_t N> struct make_index_sequence_helper {
43 using part1 = typename make_index_sequence_helper<(N+1)/2>::result;
44 using part2 = typename make_index_sequence_helper<N/2>::result;
45 using result = decltype(make_index_sequence_helper_merge(part1(), part2()));
46};
47template<> struct make_index_sequence_helper<1> { using result = index_sequence<0>; };
48template<> struct make_index_sequence_helper<0> { using result = index_sequence<>; };
49template<std::size_t N> using make_index_sequence = typename make_index_sequence_helper<N>::result;
50
51/* workaround for MSVC bug that can't do decltype(xxx)::foo when xxx is dependent of a template */
52template<typename T> using identity_t = T;
53
54/**
55 * In this namespace we find the implementation of a template binary tree container
56 * It has a similar API than std::tuple, but is stored in a binary way.
57 * the libstdc++ std::tuple recurse something like 16*N for a tuple of N elements. (Because the copy
58 * constructor uses traits for stuff like noexcept.) Which means we are quickly reaching the
59 * implementation limit of recursion. (Cannot have more than ~16 items in a tuple)
60 * Also, a linear tuple happens to lead to very slow compilation times.
61 *
62 * So a std::tuple<T1, T2, T3, T4> is represented by a
63 * binary::tree<Node<Node<Leaf<T1>, Leaf<T2>>, Node<Leaf<T3>, Leaf<T4>>>
64 */
65namespace binary {
66
67 template <typename T> struct Leaf {
68 T data;
69 static constexpr int Depth = 0;
70 static constexpr int Count = 1;
71 static constexpr bool Balanced = true;
72 template <int> constexpr T get() { return data; }
73 };
74
75 template <class A, class B> struct Node {
76 A a;
77 B b;
78 static constexpr int Count = A::Count + B::Count;
79 static constexpr int Depth = A::Depth + 1;
80 static constexpr bool Balanced = A::Depth == B::Depth && B::Balanced;
81 template <int N, typename = std::enable_if_t<(N < A::Count)>>
82 constexpr auto get(int = 0) { return a.template get<N>(); }
83 template <int N, typename = std::enable_if_t<(N >= A::Count)>>
84 constexpr auto get(uint = 0) { return b.template get<N - A::Count>(); }
85 };
86
87 /** Add the node 'N' to the tree 'T' (helper for tree_append) */
88 template <class T, typename N, bool Balanced = T::Balanced > struct Add {
89 typedef Node<T, Leaf<N> > Result;
90 static constexpr Result add(T t, N n) { return {t, {n} }; }
91 };
92 template <class A, class B, typename N> struct Add<Node<A, B>, N, false> {
93 typedef Node<A, typename Add<B, N>::Result > Result;
94 static constexpr Result add(Node<A, B> t, N n) { return {t.a , Add<B, N>::add(t.b, n) }; }
95 };
96
97 /** Add the node 'N' to the tree 'T', on the left (helper for tree_prepend) */
98 template <class T, typename N, bool Balanced = T::Balanced > struct AddPre {
99 typedef Node<Leaf<N> , T > Result;
100 static constexpr Result add(T t, N n) { return {{n}, t}; }
101 };
102 template <class A, class B, typename N> struct AddPre<Node<A, B>, N, false> {
103 typedef Node<typename AddPre<A, N>::Result, B > Result;
104 static constexpr Result add(Node<A, B> t, N n) { return {AddPre<A, N>::add(t.a, n) , t.b }; }
105 };
106
107 /** helper for tree_tail */
108 template<typename A, typename B> struct Tail;
109 template<typename A, typename B> struct Tail<Leaf<A>, B> {
110 using Result = B;
111 static constexpr B tail(Node<Leaf<A>,B> t) { return t.b; }
112 };
113 template<typename A, typename B, typename C> struct Tail<Node<A,B>, C> {
114 using Result = Node<typename Tail<A,B>::Result, C>;
115 static constexpr Result tail(Node<Node<A,B>, C> t) { return { Tail<A,B>::tail(t.a) , t.b }; }
116 };
117
118 /** An equivalent of std::tuple hold in a binary tree for faster compile time */
119 template<typename T = void> struct tree {
120 static constexpr int size = T::Count;
121 T root;
122 };
123 template<> struct tree<> { static constexpr int size = 0; };
124
125 /**
126 * tree_append(tree, T): append an element at the end of the tree.
127 */
128 template<typename T>
129 constexpr tree<Leaf<T>> tree_append(tree<>, T n)
130 { return {{n}}; }
131 template<typename Root, typename T>
132 constexpr tree<typename Add<Root,T>::Result> tree_append(tree<Root> t, T n)
133 { return {Add<Root,T>::add(t.root,n)}; }
134
135 /**
136 * tree_append(tree, T): prepend an element at the beginning of the tree.
137 */
138 template<typename T>
139 constexpr tree<Leaf<T>> tree_prepend(tree<>, T n)
140 { return {{n}}; }
141 template<typename Root, typename T>
142 constexpr tree<typename AddPre<Root,T>::Result> tree_prepend(tree<Root> t, T n)
143 { return {AddPre<Root,T>::add(t.root,n)}; }
144
145 /**
146 * get<N>(tree): Returns the element from the tree at index N.
147 */
148 template<int N, typename Root> constexpr auto get(tree<Root> t)
149 { return t.root.template get<N>(); }
150
151 /**
152 * tree_tail(tree): Returns a tree with the first element removed.
153 */
154 template<typename A, typename B>
155 constexpr tree<typename Tail<A,B>::Result> tree_tail(tree<Node<A, B>> t)
156 { return { Tail<A,B>::tail(t.root) }; }
157 template<typename N>
158 constexpr tree<> tree_tail(tree<Leaf<N>>) { return {}; }
159 constexpr tree<> tree_tail(tree<>) { return {}; }
160
161 /**
162 * tree_head(tree): same as get<O> but return something invalid in case the tuple is too small.
163 */
164 template<typename T> constexpr auto tree_head(tree<T> t) { return get<0>(t); }
165 constexpr auto tree_head(tree<void>) { struct _{}; return _{}; }
166 template<typename T> constexpr auto tree_head(T) { struct _{}; return _{}; }
167
168 template<std::size_t I, typename T> using tree_element_t = decltype(get<I>(std::declval<T>()));
169
170 /**
171 * tree_cat(tree1, tree2, ....): concatenate trees (like tuple_cat)
172 */
173 // FIXME: Should we balance?
174 template<class A, class B>
175 constexpr tree<Node<A,B>> tree_cat(tree<A> a, tree<B> b) { return { { a.root, b.root } }; }
176 template<class A>
177 constexpr tree<A> tree_cat(tree<>, tree<A> a) { return a; }
178 template<class A>
179 constexpr tree<A> tree_cat(tree<A> a, tree<>) { return a; }
180 constexpr tree<> tree_cat(tree<>, tree<>) { return {}; }
181 template<class A, class B, class C, class...D>
182 constexpr auto tree_cat(A a, B b, C c, D... d) { return tree_cat(a, tree_cat(b, c, d...)); }
183} // namespace binary
184
185
186/** Compute the sum of many integers */
187constexpr int sums() { return 0; }
188template<typename... Args>
189constexpr int sums(int i, Args... args) { return i + sums(args...); }
190// This indirection is required to work around a MSVC bug. (See https://github.com/woboq/verdigris/issues/6 )
191template <int ...Args>
192constexpr int summed = sums(Args...);
193
194/*
195 * Helpers to play with static strings
196 */
197
198/** A compile time character array of size N */
199template<std::size_t N> using StaticStringArray = const char [N];
200
201/** Represents a string of size N (N includes the '\0' at the end) */
202template<std::size_t N, typename = make_index_sequence<N>> struct StaticString;
203template<std::size_t N, std::size_t... I> struct StaticString<N, std::index_sequence<I...>>
204{
205 StaticStringArray<N> data;
206 constexpr StaticString(StaticStringArray<N> &d) : data{ (d[I])... } { }
207 static constexpr std::size_t size = N;
208 constexpr char operator[](int p) const { return data[p]; }
209};
210template <std::size_t N> constexpr StaticString<N> makeStaticString(StaticStringArray<N> &d) { return {d}; }
211
212/** A list containing many StaticString with possibly different sizes */
213template<typename T = void> using StaticStringList = binary::tree<T>;
214
215/** Make a StaticStringList out of many char array */
216constexpr StaticStringList<> makeStaticStringList() { return {}; }
217template<typename... T>
218constexpr StaticStringList<> makeStaticStringList(StaticStringArray<1> &, T...)
219{ return {}; }
220template<std::size_t N, typename... T>
221constexpr auto makeStaticStringList(StaticStringArray<N> &h, T&...t)
222{ return binary::tree_prepend(makeStaticStringList(t...), StaticString<N>(h)); }
223template<typename... T>
224constexpr StaticStringList<> makeStaticStringList(StaticString<1>, T...)
225{ return {}; }
226template<std::size_t N, typename... T>
227constexpr auto makeStaticStringList(StaticString<N> h, T...t)
228{ return binary::tree_prepend(makeStaticStringList(t...), h); }
229
230
231/** Add a string in a StaticStringList */
232template<std::size_t L, typename T>
233constexpr auto addString(const StaticStringList<T> &l, const StaticString<L> & s) {
234 return binary::tree_append(l, s);
235}
236
237
238/*-----------*/
239
240 // From qmetaobject_p.h
241enum class PropertyFlags {
242 Invalid = 0x00000000,
243 Readable = 0x00000001,
244 Writable = 0x00000002,
245 Resettable = 0x00000004,
246 EnumOrFlag = 0x00000008,
247 StdCppSet = 0x00000100,
248 // Override = 0x00000200,
249 Constant = 0x00000400,
250 Final = 0x00000800,
251 Designable = 0x00001000,
252 ResolveDesignable = 0x00002000,
253 Scriptable = 0x00004000,
254 ResolveScriptable = 0x00008000,
255 Stored = 0x00010000,
256 ResolveStored = 0x00020000,
257 Editable = 0x00040000,
258 ResolveEditable = 0x00080000,
259 User = 0x00100000,
260 ResolveUser = 0x00200000,
261 Notify = 0x00400000,
262 Revisioned = 0x00800000
263};
264constexpr uint operator|(uint a, PropertyFlags b) { return a | uint(b); }
265
266/** w_number<I> is a helper to implement state */
267template<int N = 255> struct w_number : public w_number<N - 1> {
268 static constexpr int value = N;
269 static constexpr w_number<N-1> prev() { return {}; }
270};
271template<> struct w_number<0> { static constexpr int value = 0; };
272
273template <int N> struct W_MethodFlags { static constexpr int value = N; };
274constexpr W_MethodFlags<0> W_EmptyFlag{};
275} // w_internal
276
277/** Objects that can be used as flags in the W_SLOT macro */
278
279// Mirror of QMetaMethod::Access
280namespace W_Access {
281/* // From qmetaobject_p.h MethodFlags
282 AccessPrivate = 0x00,
283 AccessProtected = 0x01,
284 AccessPublic = 0x02,
285 AccessMask = 0x03, //mask
286 */
287 constexpr w_internal::W_MethodFlags<0x1000> Private{}; // Note: Private has a higher number to differentiate it from the default
288 constexpr w_internal::W_MethodFlags<0x01> Protected{};
289 constexpr w_internal::W_MethodFlags<0x02> Public{};
290}
291
292// Mirror of QMetaMethod::MethodType
293namespace W_MethodType {
294 /* // From qmetaobject_p.h MethodFlags
295 MethodMethod = 0x00,
296 MethodSignal = 0x04,
297 MethodSlot = 0x08,
298 MethodConstructor = 0x0c,
299 MethodTypeMask = 0x0c,
300 */
301 constexpr w_internal::W_MethodFlags<0x00> Method{};
302 constexpr w_internal::W_MethodFlags<0x04> Signal{};
303 constexpr w_internal::W_MethodFlags<0x08> Slot{};
304 constexpr w_internal::W_MethodFlags<0x0c> Constructor{};
305}
306
307/*
308MethodCompatibility = 0x10,
309MethodCloned = 0x20,
310MethodScriptable = 0x40,
311MethodRevisioned = 0x80
312*/
313constexpr w_internal::W_MethodFlags<0x10> W_Compat{};
314constexpr w_internal::W_MethodFlags<0x40> W_Scriptable{};
315constexpr struct {} W_Notify{};
316constexpr struct {} W_Reset{};
317constexpr std::integral_constant<int, int(w_internal::PropertyFlags::Constant)> W_Constant{};
318constexpr std::integral_constant<int, int(w_internal::PropertyFlags::Final)> W_Final{};
319
320namespace w_internal {
321
322/** Holds information about a method */
323template<typename F, std::size_t NameLength, int Flags, typename IC, typename ParamTypes, typename ParamNames = StaticStringList<>>
324struct MetaMethodInfo {
325 F func;
326 StaticString<NameLength> name;
327 ParamTypes paramTypes;
328 ParamNames paramNames;
329 static constexpr int argCount = QtPrivate::FunctionPointer<F>::ArgumentCount;
330 static constexpr int flags = Flags;
331 using IntegralConstant = IC;
332};
333
334// Called from the W_SLOT macro
335template<typename F, std::size_t N, typename ParamTypes, int... Flags, typename IntegralConstant>
336constexpr MetaMethodInfo<F, N, summed<Flags...> | W_MethodType::Slot.value, IntegralConstant, ParamTypes>
337makeMetaSlotInfo(F f, StaticStringArray<N> &name, IntegralConstant, const ParamTypes &paramTypes, W_MethodFlags<Flags>...)
338{ return { f, {name}, paramTypes, {} }; }
339
340// Called from the W_METHOD macro
341template<typename F, std::size_t N, typename ParamTypes, int... Flags, typename IntegralConstant>
342constexpr MetaMethodInfo<F, N, summed<Flags...> | W_MethodType::Method.value, IntegralConstant, ParamTypes>
343makeMetaMethodInfo(F f, StaticStringArray<N> &name, IntegralConstant, const ParamTypes &paramTypes, W_MethodFlags<Flags>...)
344{ return { f, {name}, paramTypes, {} }; }
345
346// Called from the W_SIGNAL macro
347template<typename F, std::size_t N, typename ParamTypes, typename ParamNames, int... Flags, typename IntegralConstant>
348constexpr MetaMethodInfo<F, N, summed<Flags...> | W_MethodType::Signal.value, IntegralConstant,
349 ParamTypes, ParamNames>
350makeMetaSignalInfo(F f, StaticStringArray<N> &name, IntegralConstant, const ParamTypes &paramTypes,
351 const ParamNames &paramNames, W_MethodFlags<Flags>...)
352{ return { f, {name}, paramTypes, paramNames }; }
353
354/** Holds information about a constructor */
355template<std::size_t NameLength, typename... Args> struct MetaConstructorInfo {
356 static constexpr std::size_t argCount = sizeof...(Args);
357 static constexpr int flags = W_MethodType::Constructor.value | W_Access::Public.value;
358 using IntegralConstant = void*; // Used to detect the access specifier, but it is always public, so no need for this
359 StaticString<NameLength> name;
360 template<std::size_t N>
361 constexpr MetaConstructorInfo<N, Args...> setName(StaticStringArray<N> &n)
362 { return { { n } }; }
363 template<typename T, std::size_t... I>
364 void createInstance(void **_a, std::index_sequence<I...>) const {
365 *reinterpret_cast<T**>(_a[0]) =
366 new T(*reinterpret_cast<std::remove_reference_t<Args> *>(_a[I+1])...);
367 }
368};
369// called from the W_CONSTRUCTOR macro
370template<typename... Args> constexpr MetaConstructorInfo<1,Args...> makeMetaConstructorInfo()
371{ return { {""} }; }
372
373struct Empty{
374 constexpr operator bool() const { return false; }
375};
376
377/** Holds information about a property */
378template<typename Type, std::size_t NameLength, std::size_t TypeLength, typename Getter = Empty,
379 typename Setter = Empty, typename Member = Empty,
380 typename Notify = Empty, typename Reset = Empty, int Flags = 0>
381struct MetaPropertyInfo {
382 using PropertyType = Type;
383 StaticString<NameLength> name;
384 StaticString<TypeLength> typeStr;
385 Getter getter;
386 Setter setter;
387 Member member;
388 Notify notify;
389 Reset reset;
390 static constexpr uint flags = Flags;
391
392 template <typename S> constexpr auto setGetter(const S&s) const {
393 return MetaPropertyInfo<Type, NameLength, TypeLength, S, Setter, Member, Notify, Reset,
394 Flags | PropertyFlags::Readable>
395 {name, typeStr, s, setter, member, notify, reset};
396 }
397 template <typename S> constexpr auto setSetter(const S&s) const {
398 return MetaPropertyInfo<Type, NameLength, TypeLength, Getter, S, Member, Notify, Reset,
399 Flags | PropertyFlags::Writable>
400 {name, typeStr, getter, s, member, notify, reset};
401 }
402 template <typename S> constexpr auto setMember(const S&s) const {
403 return MetaPropertyInfo<Type, NameLength, TypeLength, Getter, Setter, S, Notify, Reset,
404 Flags | PropertyFlags::Writable | PropertyFlags::Readable>
405 {name, typeStr, getter, setter, s, notify, reset};
406 }
407 template <typename S> constexpr auto setNotify(const S&s) const {
408 return MetaPropertyInfo<Type, NameLength, TypeLength, Getter, Setter, Member, S, Reset,
409 Flags | PropertyFlags::Notify>
410 { name, typeStr, getter, setter, member, s, reset};
411 }
412 template <typename S> constexpr auto setReset(const S&s) const {
413 return MetaPropertyInfo<Type, NameLength, TypeLength, Getter, Setter, Member, Notify, S,
414 Flags | PropertyFlags::Resettable>
415 { name, typeStr, getter, setter, member, notify, s};
416 }
417 template <int Flag> constexpr auto addFlag() const {
418 return MetaPropertyInfo<Type, NameLength, TypeLength, Getter, Setter, Member, Notify, Reset,
419 Flags | Flag>
420 { name, typeStr, getter, setter, member, notify, reset};
421 }
422};
423
424/** Parse a property and fill a MetaPropertyInfo (called from W_PRPERTY macro) */
425// base case
426template <typename PropInfo> constexpr auto parseProperty(const PropInfo &p) { return p; }
427// setter
428template <typename PropInfo, typename Obj, typename Arg, typename Ret, typename... Tail>
429constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(Arg), Tail... t)
430{ return parseProperty(p.setSetter(s) , t...); }
431#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
432template <typename PropInfo, typename Obj, typename Arg, typename Ret, typename... Tail>
433constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(Arg) noexcept, Tail... t)
434{ return parseProperty(p.setSetter(s) , t...); }
435#endif
436// getter
437template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
438constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)(), Tail... t)
439{ return parseProperty(p.setGetter(s), t...); }
440template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
441constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() const, Tail... t)
442{ return parseProperty(p.setGetter(s), t...); }
443#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
444template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
445constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() noexcept, Tail... t)
446{ return parseProperty(p.setGetter(s), t...); }
447template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
448constexpr auto parseProperty(const PropInfo &p, Ret (Obj::*s)() const noexcept, Tail... t)
449{ return parseProperty(p.setGetter(s), t...); }
450#endif
451// member
452template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
453constexpr auto parseProperty(const PropInfo &p, Ret Obj::*s, Tail... t)
454{ return parseProperty(p.setMember(s) ,t...); }
455// notify
456template <typename PropInfo, typename F, typename... Tail>
457constexpr auto parseProperty(const PropInfo &p, decltype(W_Notify), F f, Tail... t)
458{ return parseProperty(p.setNotify(f) ,t...); }
459// reset
460template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
461constexpr auto parseProperty(const PropInfo &p, decltype(W_Reset), Ret (Obj::*s)(), Tail... t)
462{ return parseProperty(p.setReset(s) ,t...); }
463#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
464template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
465constexpr auto parseProperty(const PropInfo &p, decltype(W_Reset), Ret (Obj::*s)() noexcept, Tail... t)
466{ return parseProperty(p.setReset(s) ,t...); }
467#endif
468// other flags flags
469template <typename PropInfo, int Flag, typename... Tail>
470constexpr auto parseProperty(const PropInfo &p, std::integral_constant<int, Flag>, Tail... t)
471{ return parseProperty(p.template addFlag<Flag>() ,t...); }
472
473template<typename T, std::size_t N1, std::size_t N2, typename ... Args>
474constexpr auto makeMetaPropertyInfo(StaticStringArray<N1> &name, StaticStringArray<N2> &type, Args... args) {
475 MetaPropertyInfo<T, N1, N2> meta
476 { {name}, {type}, {}, {}, {}, {}, {} };
477 return parseProperty(meta, args...);
478}
479
480template <typename T, typename = void> struct EnumIsScoped {
481 enum { Value = std::is_convertible<T, int>::value ? 0 : 2 };
482};
483template <typename T> struct EnumIsScoped<QFlags<T>, void> : EnumIsScoped<typename QFlags<T>::enum_type> {};
484
485/** Holds information about an enum */
486template<std::size_t NameLength, std::size_t AliasLenght, typename Values_, typename Names, int Flags>
487struct MetaEnumInfo {
488 StaticString<NameLength> name;
489 StaticString<AliasLenght> alias;
490 Names names;
491 using Values = Values_;
492 static constexpr uint flags = Flags;
493 static constexpr auto count = Values::size();
494 static constexpr auto hasAlias = AliasLenght > 1;
495};
496template<typename Enum, Enum... Value> struct enum_sequence {};
497// called from W_ENUM and W_FLAG
498template<typename Enum, int Flag, std::size_t NameLength, std::size_t AliasLenght, Enum... Values, typename Names>
499constexpr MetaEnumInfo<NameLength, AliasLenght, std::index_sequence<size_t(Values)...> , Names,
500 Flag | EnumIsScoped<Enum>::Value> makeMetaEnumInfo(
501 StaticStringArray<NameLength> &name, StaticString<AliasLenght> alias,
502 enum_sequence<Enum, Values...>, Names names) {
503 return { {name}, alias, names };
504}
505
506// Helper function to remove the scope in a scoped enum name. (so "Foo::Bar" -> Bar)
507template<int N> constexpr int removedScopeSize(StaticStringArray<N> &name) {
508 // Find the position of the last colon (or 0 if it is not there)
509 int p = N - 1;
510 while (p > 0 && name[p] != ':')
511 p--;
512 if (name[p] == ':')
513 p++;
514 return N - p;
515}
516
517template<int R, int N> constexpr StaticString<R> removeScope(StaticStringArray<N> &name) {
518 char result[R] = {};
519 for (int i = 0; i < R; ++i) {
520 result[i] = name[N - R + i];
521 }
522 return { result };
523}
524
525// STRing REMove SCOPE: strignify while removing the scope
526#define W_MACRO_STRREMSCOPE(...) w_internal::removeScope<w_internal::removedScopeSize("" #__VA_ARGS__)>("" #__VA_ARGS__)
527
528
529/**
530 * Helper for the implementation of a signal.
531 * Called from the signal implementation within the W_SIGNAL macro.
532 *
533 * 'Func' is the type of the signal. 'Idx' is the signal index (relative).
534 * It is implemented as a functor so the operator() has exactly the same amount of argument of the
535 * signal so the __VA_ARGS__ works also if there is no arguments (no leading commas)
536 *
537 * There is specialization for const and non-const, and for void and non-void signals.
538 *
539 * the last argument of the operator() is an int, to workaround the ",0" required in the W_SIGNAL
540 * macro to make sure there is at least one argument for the ...
541 */
542template<typename Func, int Idx> struct SignalImplementation {};
543template<typename Obj, typename Ret, typename... Args, int Idx>
544struct SignalImplementation<Ret (Obj::*)(Args...), Idx>{
545 Obj *this_;
546 Ret operator()(Args... args, int) const {
547 Ret r{};
548 const void * a[]= { &r, (&args)... };
549 QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, const_cast<void **>(a));
550 return r;
551 }
552};
553template<typename Obj, typename... Args, int Idx>
554struct SignalImplementation<void (Obj::*)(Args...), Idx>{
555 Obj *this_;
556 void operator()(Args... args, int) {
557 const void *a[]= { nullptr, (&args)... };
558 QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, const_cast<void **>(a));
559 }
560};
561template<typename Obj, typename Ret, typename... Args, int Idx>
562struct SignalImplementation<Ret (Obj::*)(Args...) const, Idx>{
563 const Obj *this_;
564 Ret operator()(Args... args, int) const {
565 Ret r{};
566 const void * a[]= { &r, (&args)... };
567 QMetaObject::activate(const_cast<Obj*>(this_), &Obj::staticMetaObject, Idx, const_cast<void **>(a));
568 return r;
569 }
570};
571template<typename Obj, typename... Args, int Idx>
572struct SignalImplementation<void (Obj::*)(Args...) const, Idx>{
573 const Obj *this_;
574 void operator()(Args... args, int) {
575 const void *a[]= { nullptr, (&args)... };
576 QMetaObject::activate(const_cast<Obj*>(this_), &Obj::staticMetaObject, Idx, const_cast<void **>(a));
577 }
578};
579
580/**
581 * Used in the W_OBJECT macro to compute the base type.
582 * Used like this:
583 * using W_BaseType = std::remove_reference_t<decltype(getParentObjectHelper(&W_ThisType::qt_metacast))>;
584 * Since qt_metacast for W_ThisType will be declared later, the pointer to member function will be
585 * pointing to the qt_metacast of the base class, so T will be deduced to the base class type.
586 *
587 * Returns a reference so this work if T is an abstract class.
588 */
589template<typename T> T &getParentObjectHelper(void* (T::*)(const char*));
590
591// helper class that can access the private member of any class with W_OBJECT
592struct FriendHelper;
593
594inline namespace w_ShouldBeInQt {
595// qOverload is already in Qt 5.7, but we need it with older version.
596// Note that as of Qt 5.11, it is still not enabled with MSVC as Qt relies on feature macro.
597template <typename... Args>
598struct QNonConstOverload
599{
600 template <typename R, typename T>
601 constexpr auto operator()(R (T::*ptr)(Args...)) const
602 { return ptr; }
603};
604template <typename... Args>
605struct QConstOverload
606{
607 template <typename R, typename T>
608 constexpr auto operator()(R (T::*ptr)(Args...) const) const
609 { return ptr; }
610};
611template <typename... Args>
612struct QOverload : QConstOverload<Args...>, QNonConstOverload<Args...>
613{
614 using QConstOverload<Args...>::operator();
615 using QNonConstOverload<Args...>::operator();
616
617 template <typename R>
618 constexpr auto operator()(R (*ptr)(Args...)) const
619 { return ptr; }
620};
621template <typename... Args> constexpr QOverload<Args...> qOverload = {};
622
623#ifndef QT_ANNOTATE_CLASS // Was added in Qt 5.6.1
624#define QT_ANNOTATE_CLASS(...)
625#endif
626}
627
628} // w_internal
629
630#ifdef Q_CC_MSVC
631// Workaround for MSVC: expension rules are different so we need some extra macro.
632#define W_MACRO_MSVC_EXPAND(...) __VA_ARGS__
633#define W_MACRO_MSVC_DELAY(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__))
634#define W_MACRO_MSVC_EMPTY /##* *##/
635#else
636#define W_MACRO_MSVC_EXPAND(...) __VA_ARGS__
637#define W_MACRO_MSVC_DELAY(X,...) X(__VA_ARGS__)
638#define W_MACRO_MSVC_EMPTY
639#endif
640
641// Private macro helpers for macro programming
642#define W_MACRO_EMPTY
643#define W_MACRO_EVAL(...) __VA_ARGS__
644#define W_MACRO_DELAY(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__))
645#define W_MACRO_DELAY2(X,...) W_MACRO_MSVC_EXPAND(X(__VA_ARGS__))
646#define W_MACRO_TAIL(A, ...) __VA_ARGS__
647#define W_MACRO_FIRST(...) W_MACRO_MSVC_EXPAND(W_MACRO_FIRST2(__VA_ARGS__,))
648#define W_MACRO_FIRST2(A, ...) A
649#define W_MACRO_STRIGNIFY(...) W_MACRO_STRIGNIFY2(__VA_ARGS__)
650#define W_MACRO_STRIGNIFY2(...) #__VA_ARGS__
651#define W_MACRO_CONCAT(A, B) W_MACRO_CONCAT2(A,B)
652#define W_MACRO_CONCAT2(A, B) A##_##B
653
654// strignify and make a StaticStringList out of an array of arguments
655#define W_PARAM_TOSTRING(...) W_MACRO_MSVC_EMPTY W_MACRO_MSVC_DELAY(W_PARAM_TOSTRING2,__VA_ARGS__ ,,,,,,,,,,,,,,,,)
656#define W_PARAM_TOSTRING2(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,...) \
657 w_internal::makeStaticStringList(#A1,#A2,#A3,#A4,#A5,#A6,#A7,#A8,#A9,#A10,#A11,#A12,#A13,#A14,#A15,#A16)
658
659#define W_PARAM_TOSTRING_REMOVE_SCOPE(...) W_MACRO_MSVC_EMPTY W_MACRO_MSVC_DELAY(W_PARAM_TOSTRING2_REMOVE_SCOPE,__VA_ARGS__ ,,,,,,,,,,,,,,,,)
660#define W_PARAM_TOSTRING2_REMOVE_SCOPE(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,...) \
661 w_internal::makeStaticStringList(W_MACRO_STRREMSCOPE(A1), W_MACRO_STRREMSCOPE(A2), W_MACRO_STRREMSCOPE(A3), \
662 W_MACRO_STRREMSCOPE(A4), W_MACRO_STRREMSCOPE(A5), W_MACRO_STRREMSCOPE(A6), \
663 W_MACRO_STRREMSCOPE(A7), W_MACRO_STRREMSCOPE(A8), W_MACRO_STRREMSCOPE(A9), \
664 W_MACRO_STRREMSCOPE(A10), W_MACRO_STRREMSCOPE(A11), W_MACRO_STRREMSCOPE(A12), \
665 W_MACRO_STRREMSCOPE(A13), W_MACRO_STRREMSCOPE(A14), W_MACRO_STRREMSCOPE(A15), \
666 W_MACRO_STRREMSCOPE(A16))
667
668
669// remove the surrounding parentheses
670#define W_MACRO_REMOVEPAREN(A) W_MACRO_DELAY(W_MACRO_REMOVEPAREN2, W_MACRO_REMOVEPAREN_HELPER A)
671#define W_MACRO_REMOVEPAREN2(...) W_MACRO_DELAY2(W_MACRO_TAIL, W_MACRO_REMOVEPAREN_HELPER_##__VA_ARGS__)
672#define W_MACRO_REMOVEPAREN_HELPER(...) _ , __VA_ARGS__
673#define W_MACRO_REMOVEPAREN_HELPER_W_MACRO_REMOVEPAREN_HELPER ,
674
675// if __VA_ARGS__ is "(types), foobar" then return just the types, otherwise return nothing
676#define W_OVERLOAD_TYPES(...) W_MACRO_DELAY(W_OVERLOAD_TYPES2,W_OVERLOAD_TYPES_HELPER __VA_ARGS__,)
677#define W_OVERLOAD_TYPES2(A,...) W_MACRO_DELAY2(W_OVERLOAD_TYPES3, W_OVERLOAD_TYPES_HELPER_##A ...)
678#define W_OVERLOAD_TYPES3(A,...) W_MACRO_EVAL A
679#define W_OVERLOAD_TYPES_HELPER(...) YES(__VA_ARGS__)
680#define W_OVERLOAD_TYPES_HELPER_W_OVERLOAD_TYPES_HELPER (),
681#define W_OVERLOAD_TYPES_HELPER_YES(...) (__VA_ARGS__),
682
683#define W_OVERLOAD_RESOLVE(...) W_MACRO_DELAY(W_OVERLOAD_RESOLVE2,W_OVERLOAD_RESOLVE_HELPER __VA_ARGS__,)
684#define W_OVERLOAD_RESOLVE2(A, ...) W_MACRO_DELAY2(W_MACRO_FIRST,W_OVERLOAD_RESOLVE_HELPER_##A)
685#define W_OVERLOAD_RESOLVE_HELPER(...) YES(w_internal::qOverload<__VA_ARGS__>)
686#define W_OVERLOAD_RESOLVE_HELPER_YES(...) (__VA_ARGS__)
687#define W_OVERLOAD_RESOLVE_HELPER_W_OVERLOAD_RESOLVE_HELPER ,
688
689
690// remove the first argument if it is in parentheses"
691#define W_OVERLOAD_REMOVE(...) W_MACRO_DELAY(W_OVERLOAD_REMOVE2, W_OVERLOAD_REMOVE_HELPER __VA_ARGS__)
692#define W_OVERLOAD_REMOVE2(...) W_MACRO_DELAY2(W_MACRO_TAIL, W_OVERLOAD_REMOVE_HELPER_##__VA_ARGS__)
693
694#define W_OVERLOAD_REMOVE_HELPER(...) _
695#define W_OVERLOAD_REMOVE_HELPER_W_OVERLOAD_REMOVE_HELPER ,
696
697#define W_RETURN(R) -> decltype(R) { return R; }
698
699#ifndef Q_CC_MSVC
700//Define a unique integral_constant type for a given function pointer
701#define W_INTEGRAL_CONSTANT_HELPER(NAME, ...) std::integral_constant<decltype(W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME)), &W_ThisType::NAME>
702#else
703// On MSVC 2017 we trying to get a function pointer in the type cause compiler internal error, so use a simple hash function
704namespace w_internal {
705constexpr auto simple_hash(char const *p) {
706 unsigned long long h = *p;
707 while (*p++) h = ((h >> 8)*37ull) ^ *p ^ ((h & 0xff) << 56) ;
708 return h;
709}
710}
711#define W_INTEGRAL_CONSTANT_HELPER(NAME, ...) std::integral_constant<unsigned long long, w_internal::simple_hash(#NAME #__VA_ARGS__)>
712#endif
713
714#define W_OBJECT_COMMON(TYPE) \
715 using W_ThisType = TYPE; \
716 static constexpr auto &W_UnscopedName = #TYPE; /* so we don't repeat it in W_CONSTRUCTOR */ \
717 friend struct w_internal::FriendHelper; \
718 friend constexpr w_internal::binary::tree<> w_SlotState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
719 friend constexpr w_internal::binary::tree<> w_SignalState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
720 friend constexpr w_internal::binary::tree<> w_MethodState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
721 friend constexpr w_internal::binary::tree<> w_ConstructorState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
722 friend constexpr w_internal::binary::tree<> w_PropertyState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
723 friend constexpr w_internal::binary::tree<> w_EnumState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
724 friend constexpr w_internal::binary::tree<> w_ClassInfoState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
725 friend constexpr w_internal::binary::tree<> w_InterfaceState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
726 template<typename W_Flag> static inline constexpr w_internal::StaticString<1> w_flagAlias(W_Flag) { return {""}; } \
727 public: \
728 struct W_MetaObjectCreatorHelper;
729
730#if defined Q_CC_GNU && !defined Q_CC_CLANG
731// workaround gcc bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69836)
732#define W_STATE_APPEND(STATE, ...) \
733 static constexpr int W_MACRO_CONCAT(W_WORKAROUND_, __LINE__) = \
734 decltype(STATE(w_internal::w_number<>{}, static_cast<W_ThisType**>(nullptr)))::size+1; \
735 friend constexpr auto STATE(w_internal::w_number<W_MACRO_CONCAT(W_WORKAROUND_, __LINE__)> w_counter, W_ThisType **w_this) \
736 W_RETURN(w_internal::binary::tree_append(STATE(w_counter.prev(), w_this), __VA_ARGS__))
737#else
738#define W_STATE_APPEND(STATE, ...) \
739 friend constexpr auto STATE(w_internal::w_number<w_internal::identity_t<decltype(STATE( \
740 w_internal::w_number<>{}, static_cast<W_ThisType**>(nullptr)))>::size+1> w_counter, \
741 W_ThisType **w_this) \
742 W_RETURN(w_internal::binary::tree_append(STATE(w_counter.prev(), w_this), __VA_ARGS__))
743#endif
744#define W_STATE_APPEND_NS(STATE, ...) \
745 static constexpr auto STATE(w_internal::w_number<decltype(STATE( \
746 w_internal::w_number<>{}, static_cast<W_ThisType**>(nullptr)))::size+1> w_counter, \
747 W_ThisType **w_this) \
748 W_RETURN(w_internal::binary::tree_append(STATE(w_counter.prev(), w_this), __VA_ARGS__))
749
750//
751// public macros
752
753/** \macro W_OBJECT(TYPE)
754 * Like the Q_OBJECT macro, this declare that the object might have signals, slots or properties.
755 * Must contains the class name as a parameter and need to be put before any other W_ macro in the class.
756 */
757#define W_OBJECT(TYPE) \
758 W_OBJECT_COMMON(TYPE) \
759 public: \
760 using W_BaseType = std::remove_reference_t<decltype(\
761 w_internal::getParentObjectHelper(&W_ThisType::qt_metacast))>; \
762 Q_OBJECT \
763 QT_ANNOTATE_CLASS(qt_fake, "")
764
765/** \macro W_GADGET(TYPE)
766 * Like the Q_GADGET macro, this declare that the object might have properties.
767 * Must contains the class name as a parameter and need to be put before any other W_ macro in the class.
768 */
769#define W_GADGET(TYPE) \
770 W_OBJECT_COMMON(TYPE) \
771 Q_GADGET \
772 QT_ANNOTATE_CLASS(qt_fake, "")
773
774/** \macro W_NAMESPACE(NAMESPACE)
775 * Like the Q_GADGET macro, this declare that the object might have properties.
776 * Must contains the class name as a parameter and need to be put before any other W_ macro in the class.
777 */
778#define W_NAMESPACE(NAMESPACE) \
779 Q_NAMESPACE \
780 struct W_MetaObjectCreatorHelper; \
781 struct W_ThisType { \
782 using W_MetaObjectCreatorHelper = NAMESPACE::W_MetaObjectCreatorHelper; \
783 static constexpr auto qt_static_metacall = nullptr; \
784 }; \
785 constexpr auto &W_UnscopedName = #NAMESPACE; \
786 static constexpr w_internal::binary::tree<> w_SlotState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
787 static constexpr w_internal::binary::tree<> w_SignalState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
788 static constexpr w_internal::binary::tree<> w_MethodState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
789 static constexpr w_internal::binary::tree<> w_ConstructorState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
790 static constexpr w_internal::binary::tree<> w_PropertyState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
791 static constexpr w_internal::binary::tree<> w_EnumState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
792 static constexpr w_internal::binary::tree<> w_ClassInfoState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
793 static constexpr w_internal::binary::tree<> w_InterfaceState(w_internal::w_number<0>, W_ThisType**) { return {}; } \
794 template<typename W_Flag> static inline constexpr w_internal::StaticString<1> w_flagAlias(W_Flag) { return {""}; } \
795 QT_ANNOTATE_CLASS(qt_fake, "")
796
797/**
798 * W_SLOT( <slot name> [, (<parameters types>) ] [, <flags>]* )
799 *
800 * The W_SLOT macro needs to be put after the slot declaration.
801 *
802 * The W_SLOT macro can optionally have a list of parameter types as second argument to disambiguate
803 * overloads or use types that are not registered with W_REGISTER_ARGTYPE. The list of parameter
804 * need to be within parentheses (even if there is 0 or 1 argument).
805 *
806 * The W_SLOT macro can have flags:
807 * - Specifying the the access: W_Access::Protected, W_Access::Private
808 * or W_Access::Public. (By default, it is auto-detected from the location of this macro.)
809 * - W_Compat: for deprecated methods (equivalent of Q_MOC_COMPAT)
810 */
811#define W_SLOT(...) W_MACRO_MSVC_EXPAND(W_SLOT2(__VA_ARGS__, w_internal::W_EmptyFlag))
812#define W_SLOT2(NAME, ...) \
813 W_STATE_APPEND(w_SlotState, w_internal::makeMetaSlotInfo( \
814 W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), #NAME, \
815 W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \
816 W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), \
817 W_OVERLOAD_REMOVE(__VA_ARGS__))) \
818 static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {}
819
820/**
821 * W_INVOKABLE( <slot name> [, (<parameters types>) ] [, <flags>]* )
822 * Exactly like W_SLOT but for Q_INVOKABLE methods.
823 */
824#define W_INVOKABLE(...) W_MACRO_MSVC_EXPAND(W_INVOKABLE2(__VA_ARGS__, w_internal::W_EmptyFlag))
825#define W_INVOKABLE2(NAME, ...) \
826 W_STATE_APPEND(w_MethodState, w_internal::makeMetaMethodInfo( \
827 W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), #NAME, \
828 W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \
829 W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), \
830 W_OVERLOAD_REMOVE(__VA_ARGS__))) \
831 static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {}
832
833/**
834 * <signal signature>
835 * W_SIGNAL(<signal name> [, (<parameter types>) ] , <parameter names> )
836 *
837 * Unlike W_SLOT, W_SIGNAL must be placed directly after the signal signature declaration.
838 * There should not be a semi colon between the signal signature and the macro
839 *
840 * Like W_SLOT, there can be the types of the parametter as a second argument, within parentheses.
841 * You must then follow with the parameter names
842 *
843 * Note about exported classes: since the signal is inline, GCC won't export it when compiling
844 * with -fvisibility-inlines-hidden (which is the default), so connecting using pointer to member
845 * functions won't work accross library boundaries. You need to explicitly export the signal with
846 * your MYLIB_EXPORT macro in front of the signal declaration.
847 */
848#define W_SIGNAL(...) W_MACRO_MSVC_EXPAND(W_SIGNAL2(__VA_ARGS__ , 0))
849#define W_SIGNAL2(NAME, ...) \
850 { /* W_SIGNAL need to be placed directly after the signal declaration, without semicolon. */\
851 using w_SignalType = decltype(W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME)); \
852 return w_internal::SignalImplementation<w_SignalType, W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__)>{this}(W_OVERLOAD_REMOVE(__VA_ARGS__)); \
853 } \
854 static constexpr int W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) = \
855 decltype(w_SignalState(w_internal::w_number<>{}, static_cast<W_ThisType**>(nullptr)))::size; \
856 friend constexpr auto w_SignalState(w_internal::w_number<W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) + 1> w_counter, W_ThisType **w_this) \
857 W_RETURN(w_internal::binary::tree_append(w_SignalState(w_counter.prev(), w_this), \
858 w_internal::makeMetaSignalInfo( \
859 W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), #NAME, \
860 W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \
861 W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), W_PARAM_TOSTRING(W_OVERLOAD_REMOVE(__VA_ARGS__))))) \
862 static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {}
863
864/** \macro W_SIGNAL_COMPAT
865 * Same as W_SIGNAL, but set the W_Compat flag
866 */
867#define W_SIGNAL_COMPAT(...) W_MACRO_MSVC_EXPAND(W_SIGNAL_COMPAT2(__VA_ARGS__, 0))
868#define W_SIGNAL_COMPAT2(NAME, ...) \
869 { \
870 using w_SignalType = decltype(W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME)); \
871 return w_internal::SignalImplementation<w_SignalType, W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__)>{this}(W_OVERLOAD_REMOVE(__VA_ARGS__)); \
872 } \
873 static constexpr int W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) = \
874 decltype(w_SignalState(w_internal::w_number<>{}, static_cast<W_ThisType**>(nullptr)))::size; \
875 friend constexpr auto w_SignalState(w_internal::w_number<W_MACRO_CONCAT(w_signalIndex_##NAME,__LINE__) + 1> w_counter, W_ThisType **w_this) \
876 W_RETURN(w_internal::binary::tree_append(w_SignalState(w_counter.prev(), w_this), \
877 w_internal::makeMetaSignalInfo( \
878 W_OVERLOAD_RESOLVE(__VA_ARGS__)(&W_ThisType::NAME), #NAME, \
879 W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)(), \
880 W_PARAM_TOSTRING(W_OVERLOAD_TYPES(__VA_ARGS__)), W_PARAM_TOSTRING(W_OVERLOAD_REMOVE(__VA_ARGS__)), W_Compat))) \
881 static inline void w_GetAccessSpecifierHelper(W_INTEGRAL_CONSTANT_HELPER(NAME, __VA_ARGS__)) {}
882
883/** W_CONSTRUCTOR(<parameter types>)
884 * Declares that this class can be constructed with this list of argument.
885 * Equivalent to Q_INVOKABLE constructor.
886 * One can have W_CONSTRUCTOR() for the default constructor even if it is implicit.
887 */
888#define W_CONSTRUCTOR(...) \
889 W_STATE_APPEND(w_ConstructorState, \
890 w_internal::makeMetaConstructorInfo<__VA_ARGS__>().setName(W_UnscopedName))
891
892
893/** W_PROPERTY(<type>, <name> [, <flags>]*)
894 *
895 * Declare a property <name> with the type <type>.
896 * The flags can be function pointers that are detected to be setter, getters, notify signal or
897 * other flags. Use the macro READ, WRITE, MEMBER, ... for the flag so you can write W_PROPERTY
898 * just like in a Q_PROPERTY. The only difference with Q_PROPERTY would be the semicolon before the
899 * name.
900 * W_PROPERTY need to be put after all the setters, getters, signals and members have been declared.
901 *
902 * <type> can optionally be put in parentheses, if you have a type containing a comma
903 */
904#define W_PROPERTY(...) W_MACRO_MSVC_EXPAND(W_PROPERTY2(__VA_ARGS__)) // expands the READ, WRITE, and other sub marcos
905#define W_PROPERTY2(TYPE, NAME, ...) \
906 W_STATE_APPEND(w_PropertyState, \
907 w_internal::makeMetaPropertyInfo<W_MACRO_REMOVEPAREN(TYPE)>(\
908 #NAME, W_MACRO_STRIGNIFY(W_MACRO_REMOVEPAREN(TYPE)), __VA_ARGS__))
909
910#define WRITE , &W_ThisType::
911#define READ , &W_ThisType::
912#define NOTIFY , W_Notify, &W_ThisType::
913#define RESET , W_Reset, &W_ThisType::
914#define MEMBER , &W_ThisType::
915#define CONSTANT , W_Constant
916#define FINAL , W_Final
917
918#undef Q_PRIVATE_PROPERTY // the official macro is not a variadic macro, and the coma in READ would break it
919#define Q_PRIVATE_PROPERTY(...)
920
921/** W_ENUM(<name>, <values>)
922 * Similar to Q_ENUM, but one must also manually write all the values.
923 */
924#define W_ENUM(NAME, ...) \
925 W_STATE_APPEND(w_EnumState, w_internal::makeMetaEnumInfo<NAME,false>( \
926 #NAME, w_flagAlias(NAME{}), \
927 w_internal::enum_sequence<NAME,__VA_ARGS__>{}, W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \
928 Q_ENUM(NAME)
929
930
931/** W_ENUM_NS(<name>, <values>)
932 * Similar to Q_ENUM_NS, like W_ENUM
933 */
934#define W_ENUM_NS(NAME, ...) \
935 W_STATE_APPEND_NS(w_EnumState, w_internal::makeMetaEnumInfo<NAME,false>( \
936 #NAME, w_flagAlias(NAME{}), \
937 w_internal::enum_sequence<NAME,__VA_ARGS__>{}, W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \
938 Q_ENUM_NS(NAME)
939
940/** W_FLAG(<name>, <values>)
941 * Similar to Q_FLAG, but one must also manually write all the values.
942 */
943namespace w_internal {
944template<typename T> struct QEnumOrQFlags { using Type = T; };
945template<typename T> struct QEnumOrQFlags<QFlags<T>> { using Type = T; };
946}
947#define W_FLAG(NAME, ...) \
948 W_STATE_APPEND(w_EnumState, w_internal::makeMetaEnumInfo<w_internal::QEnumOrQFlags<NAME>::Type,true>( \
949 #NAME, w_flagAlias(NAME{}), \
950 w_internal::enum_sequence<w_internal::QEnumOrQFlags<NAME>::Type,__VA_ARGS__>{}, \
951 W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \
952 Q_FLAG(NAME)
953
954/** W_FLAG_NS(<name>, <values>)
955 * Similar to Q_FLAG_NS, like W_FLAG.
956 */
957#define W_FLAG_NS(NAME, ...) \
958 W_STATE_APPEND_NS(w_EnumState, w_internal::makeMetaEnumInfo<w_internal::QEnumOrQFlags<NAME>::Type,true>( \
959 #NAME, w_flagAlias(NAME{}), \
960 w_internal::enum_sequence<w_internal::QEnumOrQFlags<NAME>::Type,__VA_ARGS__>{}, \
961 W_PARAM_TOSTRING_REMOVE_SCOPE(__VA_ARGS__))) \
962 Q_FLAG_NS(NAME)
963
964/** Same as Q_CLASSINFO. Note, Q_CLASSINFO_NS is required for namespace */
965#define W_CLASSINFO(A, B) \
966 W_STATE_APPEND(w_ClassInfoState, \
967 std::pair<w_internal::StaticString<sizeof(A)>, w_internal::StaticString<sizeof(B)>>{ {A}, {B} })
968
969/** Same as Q_CLASSINFO, but within a namespace */
970#define W_CLASSINFO_NS(A, B) \
971 W_STATE_APPEND_NS(w_ClassInfoState, \
972 std::pair<w_internal::StaticString<sizeof(A)>, w_internal::StaticString<sizeof(B)>>{ {A}, {B} })
973
974
975/** Same as Q_INTERFACE */
976#define W_INTERFACE(A) \
977 W_STATE_APPEND(w_InterfaceState, static_cast<A*>(nullptr))
978
979/** Same as Q_DECLARE_FLAGS */
980#define W_DECLARE_FLAGS(Flags, Enum) \
981 Q_DECLARE_FLAGS(Flags, Enum) \
982 static inline constexpr w_internal::StaticString<sizeof(#Enum)> w_flagAlias(Flags) { return {#Enum}; }
983
984/** \macro W_REGISTER_ARGTYPE(TYPE)
985 Registers TYPE so it can be used as a parameter of a signal/slot or return value.
986 The normalized signature must be used.
987 Note: This does not imply Q_DECLARE_METATYPE, and Q_DECLARE_METATYPE does not imply this
988*/
989namespace w_internal { template<typename T> struct W_TypeRegistery { enum { registered = false }; }; }
990#define W_REGISTER_ARGTYPE(...) namespace w_internal { \
991 template<> struct W_TypeRegistery<__VA_ARGS__> { \
992 enum { registered = true }; \
993 static constexpr auto name = makeStaticString(#__VA_ARGS__); \
994 };}
995W_REGISTER_ARGTYPE(char*)
996W_REGISTER_ARGTYPE(const char*)
997
998#else // Q_MOC_RUN
999// just to avoid parse errors when moc is run over things that it should ignore
1000#define W_SIGNAL(...) ;
1001#define W_SIGNAL_COMPAT(...) ;
1002#define W_PROPERTY(...)
1003#define W_SLOT(...)
1004#define W_CLASSINFO(...)
1005#define W_INTERFACE(...)
1006#define W_CONSTRUCTOR(...)
1007#define W_FLAG(...)
1008#define W_ENUM(...)
1009#define W_DECLARE_FLAGS(...)
1010#endif
1011