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. If not, see <http://www.gnu.org/licenses/>.
21 */
22#pragma once
23
24#include "wobjectdefs.h"
25#include <QtCore/qobject.h>
26
27namespace w_internal {
28
29// Match MetaDataFlags constants form the MetaDataFlags in qmetaobject_p.h
30enum : uint { IsUnresolvedType = 0x80000000, IsUnresolvedNotifySignal = 0x70000000 };
31
32/// all details about a class T
33template<class T, class Name, size_t L = 1024*1024*1024>
34struct ObjectInfo {
35 using Type = T;
36 static constexpr auto counter = L;
37 static constexpr auto name = StringView{Name::value};
38
39 static constexpr int signalCount = stateCount<L, SignalStateTag, T**>;
40 static constexpr int slotCount = stateCount<L, SlotStateTag, T**>;
41 static constexpr int methodCount = signalCount + slotCount + stateCount<L, MethodStateTag, T**>;
42 static constexpr int constructorCount = stateCount<L, ConstructorStateTag, T**>;
43 static constexpr int propertyCount = stateCount<L, PropertyStateTag, T**>;
44 static constexpr int enumCount = stateCount<L, EnumStateTag, T**>;
45 static constexpr int classInfoCount = stateCount<L, ClassInfoStateTag, T**>;
46 static constexpr int interfaceCount = stateCount<L, InterfaceStateTag, T**>;
47
48 static constexpr auto methodSequence = make_index_sequence<methodCount>{};
49 static constexpr auto constructorSequence = make_index_sequence<constructorCount>{};
50 static constexpr auto propertySequence = make_index_sequence<propertyCount>{};
51 static constexpr auto interfaceSequence = make_index_sequence<interfaceCount>{};
52
53#if __cplusplus > 201700L
54 template<size_t Idx>
55 static constexpr auto method(Index<Idx>) {
56 using TPP = T**;
57 if constexpr (Idx < signalCount) return w_state(index<Idx>, SignalStateTag{}, TPP{});
58 else if constexpr (Idx - signalCount < slotCount) return w_state(index<Idx - signalCount>, SlotStateTag{}, TPP{});
59 else return w_state(index<Idx - signalCount - slotCount>, MethodStateTag{}, TPP{});
60 }
61#else
62 template<size_t Idx>
63 static constexpr auto method(Index<Idx>, std::enable_if_t<(Idx < signalCount)>* = {}) {
64 using TPP = T**;
65 return w_state(index<Idx>, SignalStateTag{}, TPP{});
66 }
67 template<size_t Idx>
68 static constexpr auto method(Index<Idx>, std::enable_if_t<(Idx >= signalCount && Idx - signalCount < slotCount)>* = {}) {
69 using TPP = T**;
70 return w_state(index<Idx - signalCount>, SlotStateTag{}, TPP{});
71 }
72 template<size_t Idx>
73 static constexpr auto method(Index<Idx>, std::enable_if_t<(Idx >= signalCount + slotCount)>* = {}) {
74 using TPP = T**;
75 return w_state(index<Idx - signalCount - slotCount>, MethodStateTag{}, TPP{});
76 }
77#endif
78};
79
80template<class F, size_t... Is>
81constexpr void fold(index_sequence<Is...>, F&& f) {
82 (void)f;
83#if __cplusplus > 201700L
84 (f(index<Is>), ...);
85#else
86 ordered((f(index<Is>),0)...);
87#endif
88}
89
90#if __cplusplus > 201700L
91template <size_t L, class State, class TPP, class F>
92constexpr void foldState(F&& f) {
93 fold(make_index_sequence<stateCount<L, State, TPP>>{}, [&](auto i) { f(w_state(i, State{}, TPP{}), i); });
94}
95#else
96template<class F, class State, class TPP>
97struct FoldState {
98 F&& f;
99 template<class I>
100 constexpr void operator() (I i) { f(w_state(i, State{}, TPP{}), i); }
101};
102template <size_t L, class State, class TPP, class F>
103constexpr void foldState(F&& f) {
104 auto fs = FoldState<F, State, TPP>{std::forward<F>(f)};
105 fold(make_index_sequence<stateCount<L, State, TPP>>{}, fs);
106}
107#endif
108
109template <size_t L, class T, class F>
110constexpr void foldMethods(F&& f) {
111 foldState<L, SignalStateTag, T>(f);
112 foldState<L, SlotStateTag, T>(f);
113 foldState<L, MethodStateTag, T>(f);
114}
115
116/// Helper to get information about the notify signal of the property within object T
117template<size_t L, size_t PropIdx, typename T, typename O>
118struct ResolveNotifySignal {
119private:
120 using TP = T**;
121 using OP = O**;
122 static constexpr auto prop = w_state(index<PropIdx>, PropertyStateTag{}, TP{});
123
124 template<size_t SigIdx, bool Eq = w_state(index<SigIdx>, SignalStateTag{}, OP{}).func == prop.notify>
125 static constexpr auto match(int) { return Eq; }
126 template<size_t SigIdx>
127 static constexpr auto match(float) { return false; }
128
129 template<size_t... Is>
130 static constexpr int indexFold(index_sequence<Is...>) {
131 int r = -1;
132#if __cplusplus > 201700L
133 ((match<Is>(0) ? r = (int)Is : 0), ...);
134#else
135 ordered2<int>({(match<Is>(0) ? r = (int)Is : 0)...});
136#endif
137 return r;
138 }
139public:
140 static constexpr int signalIndex() {
141 return indexFold(make_index_sequence<stateCount<L, SignalStateTag, O**>>{});
142 }
143};
144
145/// returns true if the object T has at least one property with a notify signal
146#if __cplusplus > 201700L
147template <size_t L, typename TPP>
148constexpr bool hasNotifySignal() {
149 auto r = bool{};
150 foldState<L, PropertyStateTag, TPP>([&](auto p, auto) {
151 r = r || !std::is_same<decltype(p.notify), std::nullptr_t>::value;
152 });
153 return r;
154}
155#else
156struct HasNotifySignal {
157 bool r{};
158 template<class P, class I>
159 constexpr void operator() (P p, I) {
160 r = r || !std::is_same<decltype(p.notify), std::nullptr_t>::value;
161 }
162};
163template <size_t L, typename TPP>
164constexpr bool hasNotifySignal() {
165 auto hns = HasNotifySignal{};
166 foldState<L, PropertyStateTag, TPP>(hns);
167 return hns.r;
168}
169#endif
170
171
172template<class State>
173struct ClassInfoGenerator {
174 State& s;
175 constexpr ClassInfoGenerator(State& s) : s(s) {}
176
177 template<class ClassInfo, class Index>
178 constexpr void operator() (const ClassInfo& ci, Index) {
179 s.addString(ci.first);
180 s.addString(ci.second);
181 }
182};
183
184/// auto-detect the access specifiers
185template<class T, class M>
186auto test_public(int) -> std::enable_if_t<std::is_same<void, decltype(T::w_GetAccessSpecifierHelper(M{}))>::value, std::true_type>;
187template<class T, class M>
188auto test_public(float) -> std::false_type;
189template<class T, class M>
190using isPublic = decltype(test_public<T, M>(0));
191
192template <typename T, typename M, typename = void> struct isProtected : std::false_type {};
193template <typename T, typename = std::enable_if_t<!std::is_final<T>::value>>
194struct Derived : T { template<typename M, typename X = T> static decltype(X::w_GetAccessSpecifierHelper(std::declval<M>())) test(M); };
195template <typename T, typename M> struct isProtected<T, M, decltype(Derived<T>::test(std::declval<M>()))> : std::true_type {};
196
197template<class State, class T>
198struct MethodGenerator {
199 State& s;
200 int parameterIndex;
201 MethodGenerator(const MethodGenerator&) = delete;
202 constexpr MethodGenerator(State& s, int pi) : s(s), parameterIndex(pi) {}
203
204 template<class Method, class Index>
205 constexpr void operator() (const Method& method, Index) {
206 s.addString(method.name); // name
207 s.addInts((uint)Method::argCount,
208 parameterIndex, //parameters
209 1, //tag, always \0
210 adjustFlags(Method::flags, typename Method::IntegralConstant()));
211 parameterIndex += 1 + Method::argCount * 2;
212 }
213
214private:
215 template<typename M>
216 static constexpr uint adjustFlags(uint f, M) {
217 if (!(f & (W_Access::Protected.value | W_Access::Private.value | W_Access::Public.value))) {
218 // Auto-detect the access specifier
219 f |= isPublic<T, M>::value ? W_Access::Public.value : isProtected<T,M>::value ? W_Access::Protected.value : W_Access::Private.value;
220 }
221 return f & static_cast<uint>(~W_Access::Private.value); // Because QMetaMethod::Private is 0, but not W_Access::Private;
222 }
223};
224
225/// compute if type T is a builtin QMetaType
226template <typename T, typename = void> struct MetaTypeIdIsBuiltIn : std::false_type {};
227template <typename T> struct MetaTypeIdIsBuiltIn<T, typename std::enable_if<QMetaTypeId2<T>::IsBuiltIn>::type> : std::true_type{};
228
229/// Helper to generate the type information of type 'T':
230/// If T is a builtin QMetaType, its meta type id need to be added in the state.
231/// If it's not builtin, then it would be an reference to T's name.
232#if __cplusplus > 201700L
233template<typename T, typename State, typename TypeStr = int>
234constexpr void handleType(State& s, TypeStr v = {}) {
235 (void)v;
236 if constexpr (MetaTypeIdIsBuiltIn<T>::value) {
237 s.addInts(QMetaTypeId2<T>::MetaType);
238 }
239 else if constexpr (std::is_same_v<std::decay_t<TypeStr>, StringView>) {
240 s.addTypeString(v);
241 }
242 else {
243 s.addTypeString(W_TypeRegistery<T>::name);
244 static_assert(W_TypeRegistery<T>::registered, "Please Register T with W_REGISTER_ARGTYPE");
245 }
246}
247#else
248template<typename T, typename State, typename TypeStr = int>
249constexpr void handleType(State& s, TypeStr = {}, std::enable_if_t<MetaTypeIdIsBuiltIn<T>::value>* = {}) {
250 s.addInts(QMetaTypeId2<T>::MetaType);
251}
252template<typename T, typename State, typename TypeStr = int>
253constexpr void handleType(State& s, TypeStr = {}, std::enable_if_t<!MetaTypeIdIsBuiltIn<T>::value>* = {}) {
254 s.addTypeString(W_TypeRegistery<T>::name);
255 static_assert(W_TypeRegistery<T>::registered, "Please Register T with W_REGISTER_ARGTYPE");
256}
257template<typename T, typename State>
258constexpr void handleType(State& s, StringView v, std::enable_if_t<!MetaTypeIdIsBuiltIn<T>::value>* = {}) {
259 s.addTypeString(v);
260}
261#endif
262
263template<class State, class T>
264struct PropertyGenerator {
265 State& s;
266 constexpr PropertyGenerator(State& s) : s(s) {}
267
268 template<class Prop, class Index>
269 constexpr void operator() (const Prop& prop, Index) {
270 s.addString(prop.name);
271 handleType<typename Prop::PropertyType>(s, prop.typeStr);
272 constexpr uint moreFlags = (QtPrivate::IsQEnumHelper<typename Prop::PropertyType>::Value
273 ? uint(PropertyFlags::EnumOrFlag) : 0);
274 constexpr uint finalFlag = std::is_final<T>::value ? 0 | PropertyFlags::Final : 0;
275 constexpr uint defaultFlags = 0 | PropertyFlags::Stored | PropertyFlags::Scriptable
276 | PropertyFlags::Designable;
277 s.addInts(Prop::flags | moreFlags | finalFlag | defaultFlags);
278 }
279};
280
281#if __cplusplus > 201700L
282template<class State, size_t L, class T, bool hasNotify>
283struct NotifySignalGenerator {
284#else
285template<class State, size_t L, class T, bool hasNotify>
286struct NotifySignalGenerator;
287template<class State, size_t L, class T>
288struct NotifySignalGenerator<State, L, T, false> {
289 constexpr NotifySignalGenerator(State&) {}
290 template<class Prop, size_t Idx>
291 constexpr void operator() (const Prop&, Index<Idx>) {}
292};
293template<class State, size_t L, class T>
294struct NotifySignalGenerator<State, L, T, true> {
295#endif
296 using TP = T**;
297 State& s;
298 constexpr NotifySignalGenerator(State& s) : s(s) {}
299
300#if __cplusplus > 201700L
301 template<class Prop, size_t Idx>
302 constexpr void operator() (const Prop& prop, Index<Idx>) {
303 if constexpr (hasNotify) {
304 process(prop.notify, index<Idx>);
305 }
306 }
307#else
308 template<class Prop, size_t Idx>
309 constexpr void operator() (const Prop& prop, Index<Idx>) {
310 process(prop.notify, index<Idx>);
311 }
312#endif
313
314private:
315 template<size_t Idx>
316 constexpr void process(Empty, Index<Idx>) {
317 s.addInts(0);
318 }
319
320 // Signal in the same class
321 template<size_t Idx, typename Func>
322 constexpr void process(Func, Index<Idx>, std::enable_if_t<std::is_same<T, typename QtPrivate::FunctionPointer<Func>::Object>::value, int> = 0) {
323 constexpr int signalIndex = ResolveNotifySignal<L, Idx, T, T>::signalIndex();
324 static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL");
325 s.addInts(signalIndex);
326 }
327
328 // Signal in a parent class
329 template<size_t Idx, typename Func>
330 constexpr void process(Func, Index<Idx>, std::enable_if_t<!std::is_same<T, typename QtPrivate::FunctionPointer<Func>::Object>::value, int> = 0) {
331 using O = typename QtPrivate::FunctionPointer<Func>::Object;
332 using OP = O**;
333 constexpr int signalIndex = ResolveNotifySignal<L, Idx, T, O>::signalIndex();
334 static_assert(signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL");
335 static_assert(signalIndex < 0 || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0),
336 "NOTIFY signal in parent class requires Qt 5.10");
337 constexpr auto sig = w_state(index<signalIndex>, SignalStateTag{}, OP{});
338 s.template addTypeString<IsUnresolvedNotifySignal>(sig.name);
339 }
340};
341
342template<class State>
343struct EnumGenerator {
344 State& s;
345 int dataIndex{};
346 EnumGenerator(const EnumGenerator&) = delete;
347 constexpr EnumGenerator(State& s, int di) : s(s), dataIndex(di) {}
348
349 template<class Enum, class Index>
350 constexpr void operator() (const Enum& e, Index) {
351 auto nameIndex = s.stringCount; // required for MSVC-2019
352 (void)nameIndex;
353 s.addString(e.name); // name
354#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
355#if __cplusplus > 201700L
356 if constexpr (Enum::hasAlias) s.addString(e.alias); // alias
357#else
358 if (Enum::hasAlias) s.addString(e.alias); // alias
359#endif
360 else s.addInts(nameIndex);
361#endif
362 s.addInts(Enum::flags, (uint)Enum::count, dataIndex);
363 dataIndex += Enum::count * 2;
364 }
365};
366
367template<class State>
368struct EnumValuesGenerator {
369 State& s;
370 constexpr EnumValuesGenerator(State& s) : s(s) {}
371
372 template<class Enum, class Index>
373 constexpr void operator() (const Enum& e, Index) {
374 generateAll(typename Enum::Values{}, e.names, Enum::sequence);
375 }
376
377private:
378 template<size_t... Values, typename Names, size_t... Is>
379 constexpr void generateAll(index_sequence<Values...>, const Names& names, index_sequence<Is...>) {
380#if __cplusplus > 201700L
381 ((s.addString(names[Is]), s.addInts((uint)Values)), ...);
382#else
383 ordered((s.addString(names[Is]), s.addInts((uint)Values), 0)...);
384#endif
385 }
386};
387
388#if __cplusplus > 201700L
389template<size_t I, size_t N>
390constexpr auto stringFetch(const StringViewArray<N>& s) {
391 if constexpr (I < N) {
392 return s[I];
393 }
394 else {
395 (void)s;
396 struct _{};
397 return _{};
398 }
399}
400#else
401template<size_t I, size_t N>
402constexpr auto stringFetch(const StringViewArray<N>& s, std::enable_if_t<(I < N)>* = {}) {
403 return s[I];
404}
405template<size_t I, size_t N>
406constexpr auto stringFetch(const StringViewArray<N>& s, std::enable_if_t<!(I < N)>* = {}) {
407 (void)s;
408 struct _{};
409 return _{};
410}
411#endif
412template<class Arg, class State, class TypeName>
413constexpr void handleArgType(State& ss, const TypeName& typeName) {
414 using Type = typename QtPrivate::RemoveConstRef<Arg>::Type;
415 // This way, the overload of result will not pick the StringView one if it is a tuple (because registered types have the priority)
416 auto typeName2 = std::conditional_t<std::is_same<Arg, Type>::value, TypeName, std::tuple<TypeName>>{typeName};
417 handleType<Type>(ss, typeName2);
418}
419template<class... Args, class State, class TypeNames, size_t... Is>
420constexpr void handleArgTypes(State& ss, const TypeNames& typeNames, index_sequence<Is...>) {
421#if __cplusplus > 201700L
422 (handleArgType<Args>(ss, stringFetch<Is>(typeNames)), ...);
423#else
424 ordered((handleArgType<Args>(ss, stringFetch<Is>(typeNames)), 0)...);
425#endif
426}
427
428template<size_t ArgCount, class State, size_t NameCount>
429constexpr void handleArgNames(State& ss, const StringViewArray<NameCount>& paramNames) {
430 auto i = size_t{};
431 for (; i < ArgCount && i < NameCount; ++i) ss.addString(paramNames[i]);
432 for (; i < ArgCount; ++i) ss.addInts(1);
433}
434
435template<class State>
436struct MethodParametersGenerator {
437 State& s;
438 constexpr MethodParametersGenerator(State& s) : s(s) {}
439 template<class Method, class Index>
440 constexpr void operator() (const Method& method, Index) {
441 generateSingleMethodParameter(method.func, method);
442 }
443
444private:
445 // non-const function
446 template<typename Method, typename Obj, typename Ret, typename... Args>
447 constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...), const Method &method) {
448 handleType<Ret>(s);
449 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
450 handleArgNames<Method::argCount>(s, method.paramNames);
451 }
452#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
453 template<typename Method, typename Obj, typename Ret, typename... Args>
454 constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) noexcept, const Method &method) {
455 handleType<Ret>(s);
456 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
457 handleArgNames<Method::argCount>(s, method.paramNames);
458 }
459#endif
460 template<typename Method, typename Obj, typename Ret, typename... Args>
461 // const function
462 constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const, const Method &method) {
463 handleType<Ret>(s);
464 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
465 handleArgNames<Method::argCount>(s, method.paramNames);
466 }
467#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
468 template<typename Method, typename Obj, typename Ret, typename... Args>
469 constexpr void generateSingleMethodParameter(Ret (Obj::*)(Args...) const noexcept, const Method &method) {
470 handleType<Ret>(s);
471 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
472 handleArgNames<Method::argCount>(s, method.paramNames);
473 }
474#endif
475 // static member functions
476 template<typename Method, typename Ret, typename... Args>
477 constexpr void generateSingleMethodParameter(Ret (*)(Args...), const Method &method) {
478 handleType<Ret>(s);
479 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
480 handleArgNames<Method::argCount>(s, method.paramNames);
481 }
482#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
483 template<typename Method, typename Ret, typename... Args>
484 constexpr void generateSingleMethodParameter(Ret (*)(Args...) noexcept, const Method &method) {
485 handleType<Ret>(s);
486 handleArgTypes<Args...>(s, method.paramTypes, Method::argSequence);
487 handleArgNames<Method::argCount>(s, method.paramNames);
488 }
489#endif
490};
491
492template<class State>
493struct ConstructorParametersGenerator {
494 State& s;
495 constexpr ConstructorParametersGenerator(State& s) : s(s) {}
496
497 template<typename... Args, class Index>
498 constexpr void operator() (const MetaConstructorInfo<Args...>& info, Index) {
499 s.addInts(IsUnresolvedType | 1);
500 handleArgTypes<Args...>(s, StringViewArray<>{}, info.argSequence);
501 s.addInts(((void)sizeof(Args),1)...); // all the names are 1 (for "\0")
502 }
503};
504
505/// Given method, a binary::tree containing information about methods or constructor,
506/// return the amount of item it will add in the int array.
507#if __cplusplus > 201700L
508template<size_t L, class T>
509constexpr int methodsParamOffset() {
510 auto sum = int{};
511 foldMethods<L, T>([&](auto m, auto) { sum += int(1 + m.argCount * 2); });
512 return sum;
513}
514#else
515struct MethodParamOffset {
516 int sum{};
517 template<class M, class I>
518 constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); }
519};
520template<size_t L, class T>
521constexpr int methodsParamOffset() {
522 auto mpo = MethodParamOffset{};
523 foldMethods<L, T>(mpo);
524 return mpo.sum;
525}
526#endif
527#if __cplusplus > 201700L
528template<size_t L, class T>
529constexpr int constructorParamOffset() {
530 auto sum = int{};
531 foldState<L, ConstructorStateTag, T>([&](auto m, auto) { sum += int(1 + m.argCount * 2); });
532 return sum;
533}
534#else
535struct ConstructorParamOffset {
536 int sum{};
537 template<class M, class I>
538 constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); }
539};
540template<size_t L, class T>
541constexpr int constructorParamOffset() {
542 auto cpo = ConstructorParamOffset{};
543 foldState<L, ConstructorStateTag, T>(cpo);
544 return cpo.sum;
545}
546
547#endif
548
549template<class T, size_t N> using RawArray = T[N];
550template<class T, size_t N> struct OwnArray {
551 RawArray<T, N> data{};
552 constexpr OwnArray(const T (&s)[N]) {
553 auto p = data;
554 for (auto c : s) *p++ = c;
555 }
556};
557
558struct LayoutBuilder {
559 size_t stringSize{};
560 uint stringCount{};
561 uint intCount{};
562
563 constexpr void addString(const StringView& s) {
564 stringSize += s.size();
565 stringCount += 1;
566 intCount += 1;
567 }
568 constexpr void addStringUntracked(const StringView& s) {
569 stringSize += s.size();
570 stringCount += 1;
571 }
572 template<uint Flag = IsUnresolvedType>
573 constexpr void addTypeString(const StringView& s) {
574 stringSize += s.size();
575 stringCount += 1;
576 intCount += 1;
577 }
578 template<class... Ts>
579 constexpr void addInts(Ts...) {
580 intCount += sizeof... (Ts);
581 }
582};
583struct DataBuilder {
584 char* stringCharP{};
585 qptrdiff* stringOffestP{};
586 int* stringLengthP{};
587 uint* intP{};
588 uint stringCount{};
589 uint intCount{};
590 qptrdiff stringOffset{};
591
592 constexpr DataBuilder() = default;
593 DataBuilder(const DataBuilder&) = delete;
594 template<class Holder>
595 constexpr DataBuilder(Holder& r)
596 : stringCharP(r.stringChars)
597 , stringOffestP(r.stringOffsets)
598 , stringLengthP(r.stringLengths)
599 , intP(r.ints)
600 , stringOffset(r.stringOffset) {}
601
602 constexpr void addString(const StringView& s) {
603 for (auto c : s) *stringCharP++ = c;
604 *stringOffestP++ = stringOffset;
605 *stringLengthP++ = s.size() - 1;
606 *intP++ = stringCount;
607 stringOffset += s.size() - sizeof(QByteArrayData);
608 stringCount += 1;
609 intCount += 1;
610 }
611 constexpr void addStringUntracked(const StringView& s) {
612 for (auto c : s) *stringCharP++ = c;
613 *stringOffestP++ = stringOffset;
614 *stringLengthP++ = s.size() - 1;
615 stringOffset += s.size() - sizeof(QByteArrayData);
616 stringCount += 1;
617 }
618
619 template<uint Flag = IsUnresolvedType>
620 constexpr void addTypeString(const StringView& s) {
621 for (auto c : s) *stringCharP++ = c;
622 *stringOffestP++ = stringOffset;
623 *stringLengthP++ = s.size() - 1;
624 *intP++ = Flag | stringCount;
625 stringOffset += s.size() - sizeof(QByteArrayData);
626 stringCount += 1;
627 intCount += 1;
628 }
629 template<class... Ts>
630 constexpr void addInts(Ts... vs) {
631#if __cplusplus > 201700L
632 ((*intP++ = vs),...);
633#else
634 ordered2<uint>({(*intP++ = vs)...});
635#endif
636 intCount += sizeof... (Ts);
637 }
638};
639
640
641/// fold ObjectInfo into State
642template<typename T, typename State>
643constexpr void generateDataPass(State& state) {
644 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
645 constexpr size_t L = ObjI::counter;
646 constexpr bool hasNotify = hasNotifySignal<L, T**>();
647 constexpr int classInfoOffset = 14;
648 constexpr int methodOffset = classInfoOffset + ObjI::classInfoCount * 2;
649 constexpr int propertyOffset = methodOffset + ObjI::methodCount * 5;
650 constexpr int enumOffset = propertyOffset + ObjI::propertyCount * (hasNotify ? 4: 3);
651 constexpr int constructorOffset = enumOffset + ObjI::enumCount * (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) ? 5 : 4);
652 constexpr int paramIndex = constructorOffset + ObjI::constructorCount * 5 ;
653 constexpr int constructorParamIndex = paramIndex + methodsParamOffset<L, T**>();
654 constexpr int enumValueOffset = constructorParamIndex + constructorParamOffset<L, T**>();
655
656 state.addInts(QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) ? 8 : 7); // revision
657 state.addString(ObjI::name);
658 state.addStringUntracked(viewLiteral(""));
659 state.addInts(
660 ObjI::classInfoCount, classInfoOffset, // classinfo
661 ObjI::methodCount, methodOffset, // methods
662 ObjI::propertyCount, propertyOffset, // properties
663 ObjI::enumCount, enumOffset, // enums/sets
664 ObjI::constructorCount, constructorOffset, // constructors
665 0x4 /* PropertyAccessInStaticMetaCall */, // flags
666 ObjI::signalCount);
667
668 //if (state.intCount != classInfoOffset) throw "offset mismatch!";
669 foldState<L, ClassInfoStateTag, T**>(ClassInfoGenerator<State>{state});
670
671 //if (state.intCount != methodOffset) throw "offset mismatch!";
672 foldMethods<L, T**>(MethodGenerator<State, T>{state, paramIndex});
673
674 //if (state.intCount != propertyOffset) throw "offset mismatch!";
675 foldState<L, PropertyStateTag, T**>(PropertyGenerator<State, T>{state});
676 foldState<L, PropertyStateTag, T**>(NotifySignalGenerator<State, L, T, hasNotify>{state});
677
678 //if (state.intCount != enumOffset) throw "offset mismatch!";
679 foldState<L, EnumStateTag, T**>(EnumGenerator<State>{state, enumValueOffset});
680
681 //if (state.intCount != constructorOffset) throw "offset mismatch!";
682 foldState<L, ConstructorStateTag, T**>(MethodGenerator<State, T>{state, constructorParamIndex});
683
684 //if (state.intCount != paramIndex) throw "offset mismatch!";
685 foldMethods<L, T**>(MethodParametersGenerator<State>{state});
686
687 //if (state.intCount != constructorParamIndex) throw "offset mismatch!";
688 foldState<L, ConstructorStateTag, T**>(ConstructorParametersGenerator<State>{state});
689
690 //if (state.intCount != enumValueOffset) throw "offset mismatch!";
691 foldState<L, EnumStateTag, T**>(EnumValuesGenerator<State>{state});
692}
693
694#if __cplusplus > 201700L
695template<class T>
696constexpr LayoutBuilder dataLayout = [](){
697 auto r = LayoutBuilder{};
698 generateDataPass<T>(r);
699 return r;
700}();
701#else
702template<class T>
703constexpr auto createLayout() {
704 auto r = LayoutBuilder{};
705 generateDataPass<T>(r);
706 return r;
707}
708template<class T>
709constexpr LayoutBuilder dataLayout = createLayout<T>();
710#endif
711
712/// Final data holder
713template<std::size_t StringSize, std::size_t StringCount, std::size_t IntCount>
714struct MetaDataHolder {
715 RawArray<QByteArrayData,StringCount> byteArrays;
716 OwnArray<char, StringSize> stringChars;
717#if __cplusplus > 201700L
718 const uint* ints;
719#else
720 OwnArray<uint, IntCount> ints;
721#endif
722};
723template<class T>
724struct MetaDataProvider {
725 static constexpr auto stringSize = dataLayout<T>.stringSize;
726 static constexpr auto stringCount = dataLayout<T>.stringCount;
727 static constexpr auto intCount = dataLayout<T>.intCount;
728 using MetaDataType = const MetaDataHolder<stringSize, stringCount, intCount>;
729
730 struct Arrays {
731#ifndef Q_CC_MSVC
732 constexpr static qptrdiff stringOffset = offsetof(MetaDataType, stringChars);
733#else // offsetof does not work with MSVC
734 constexpr static qptrdiff stringOffset = sizeof(MetaDataType::byteArrays);
735#endif
736 RawArray<qptrdiff, stringCount> stringOffsets{};
737 RawArray<int, stringCount> stringLengths{};
738 RawArray<char, stringSize> stringChars{};
739 RawArray<uint, intCount> ints{};
740 };
741#if __cplusplus > 201700L
742 constexpr static Arrays arrays = []() {
743 auto r = Arrays{};
744 DataBuilder b{r};
745 generateDataPass<T>(b);
746 return r;
747 }();
748#else
749 constexpr static auto buildArrays() {
750 auto r = Arrays{};
751 DataBuilder b{r};
752 generateDataPass<T>(b);
753 return r;
754 }
755 constexpr static Arrays arrays = buildArrays();
756#endif
757};
758
759template<class T, class IS>
760struct MetaDataBuilder;
761template<class T, std::size_t... Is>
762struct MetaDataBuilder<T, index_sequence<Is...>> {
763 using P = MetaDataProvider<T>;
764 using MetaDataType = typename P::MetaDataType;
765#if __cplusplus >= 201700L
766 constexpr static MetaDataType meta_data = {
767 {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(P::arrays.stringLengths[Is], P::arrays.stringOffsets[Is])...},
768 P::arrays.stringChars, P::arrays.ints
769 };
770#else
771 static MetaDataType meta_data;
772#endif
773};
774#if __cplusplus < 201700L
775template<class T, std::size_t... Is>
776typename MetaDataBuilder<T, index_sequence<Is...>>::MetaDataType MetaDataBuilder<T, index_sequence<Is...>>::meta_data = {
777 {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(P::arrays.stringLengths[Is], P::arrays.stringOffsets[Is])...},
778 {P::arrays.stringChars}, {P::arrays.ints}
779};
780#endif
781
782/// Returns the QMetaObject* of the base type. Use SFINAE to only return it if it exists
783template<typename T>
784static constexpr auto parentMetaObject(int) W_RETURN(&T::W_BaseType::staticMetaObject)
785template<typename T>
786static constexpr const QMetaObject *parentMetaObject(...) { return nullptr; }
787
788// Bunch of helpers for propertyOperation
789// this uses SFINAE of the return value to work either with F a pointer to member, or to member function
790// or nullptr.
791template <typename F, typename O, typename T>
792inline auto propSet(F f, O *o, const T &t) W_RETURN(((o->*f)(t),0))
793template <typename F, typename O, typename T>
794inline auto propSet(F f, O *o, const T &t) W_RETURN(o->*f = t)
795template <typename O, typename T>
796inline void propSet(Empty, O *, const T &) {}
797
798template <typename F, typename O, typename T>
799inline auto propGet(F f, O *o, T &t) W_RETURN(t = (o->*f)())
800template <typename F, typename O, typename T>
801inline auto propGet(F f, O *o, T &t) W_RETURN(t = o->*f)
802template <typename O, typename T>
803inline void propGet(Empty, O *, T &) {}
804
805template <typename F, typename M, typename O>
806inline auto propNotify(F f, M m, O *o) W_RETURN(((o->*f)(o->*m),0))
807template <typename F, typename M, typename O>
808inline auto propNotify(F f, M, O *o) W_RETURN(((o->*f)(),0))
809template <typename... T>
810inline void propNotify(T...) {}
811
812template <typename F, typename O>
813inline auto propReset(F f, O *o) W_RETURN(((o->*f)(),0))
814template <typename... T>
815inline void propReset(T...) {}
816
817struct FriendHelper {
818
819 template<typename T>
820 static constexpr QMetaObject createMetaObject() {
821 using MetaData = MetaDataBuilder<T, make_index_sequence<dataLayout<T>.stringCount>>;
822#if __cplusplus > 201700L
823 return { { parentMetaObject<T>(0), MetaData::meta_data.byteArrays, MetaData::meta_data.ints, T::qt_static_metacall, {}, {} } };
824#else
825 return { { parentMetaObject<T>(0), MetaData::meta_data.byteArrays, MetaData::meta_data.ints.data, T::qt_static_metacall, {}, {} } };
826#endif
827 }
828
829 template<typename T> static int qt_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a) {
830 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
831 _id = _o->T::W_BaseType::qt_metacall(_c, _id, _a);
832 if (_id < 0)
833 return _id;
834 if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
835 constexpr int methodCount = ObjI::methodCount;
836 if (_id < methodCount)
837 T::qt_static_metacall(_o, _c, _id, _a);
838 _id -= methodCount;
839 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
840 || _c == QMetaObject::RegisterPropertyMetaType) {
841 constexpr int propertyCount = ObjI::propertyCount;
842 if (_id < propertyCount)
843 T::qt_static_metacall(_o, _c, _id, _a);
844 _id -= propertyCount;
845 }
846 return _id;
847 }
848
849QT_WARNING_PUSH
850QT_WARNING_DISABLE_GCC("-Waddress")
851 /// Helper for implementation of qt_static_metacall for QMetaObject::IndexOfMethod
852 /// T is the class, and I is the index of a method.
853 /// Returns I if the argument is equal to the pointer to member function of the signal of index 'I'
854 template<typename T, int I>
855 static int indexOfMethod(void **func) {
856 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
857 constexpr auto m = ObjI::method(index<I>);
858 if ((m.flags & 0xc) == W_MethodType::Signal.value
859 && m.func == *reinterpret_cast<decltype(m.func)*>(func))
860 return I;
861 return -1;
862 }
863QT_WARNING_POP
864
865 /// Helper for implementation of qt_static_metacall for QMetaObject::InvokeMetaMethod
866 /// T is the class, and I is the index of a method.
867 /// Invoke the method with index I if id == I.
868 template <typename T, int I>
869 static void invokeMethod(T *_o, int _id, void **_a) {
870 if (_id == I) {
871 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
872 constexpr auto f = ObjI::method(index<I>).func;
873 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
874 P::template call<typename P::Arguments, typename P::ReturnType>(f, _o, _a);
875 }
876 }
877
878 /// Helper for implementation of qt_static_metacall for QMetaObject::RegisterMethodArgumentMetaType
879 /// T is the class, and I is the index of a method.
880 template <typename T, int I>
881 static void registerMethodArgumentType(int _id, void **_a) {
882 if (_id == I) {
883 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
884 constexpr auto f = ObjI::method(index<I>).func;
885 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
886 auto _t = QtPrivate::ConnectionTypes<typename P::Arguments>::types();
887 uint arg = *reinterpret_cast<uint*>(_a[1]);
888 *reinterpret_cast<int*>(_a[0]) = _t && arg < P::ArgumentCount ?
889 _t[arg] : -1;
890 }
891 }
892
893 /// Helper for implementation of qt_static_metacall for any of the operations in a property
894 /// T is the class, and I is the index of a property.
895 template<typename T, int I>
896 static void propertyOperation(T *_o, QMetaObject::Call _c, int _id, void **_a) {
897 if (_id != I)
898 return;
899 using TPP = T**;
900 constexpr auto p = w_state(index<I>, PropertyStateTag{}, TPP{});
901 using Type = typename decltype(p)::PropertyType;
902 switch(+_c) {
903 case QMetaObject::ReadProperty:
904 if (p.getter) {
905 propGet(p.getter, _o, *reinterpret_cast<Type*>(_a[0]));
906 } else if (p.member) {
907 propGet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
908 }
909 break;
910 case QMetaObject::WriteProperty:
911 if (p.setter) {
912 propSet(p.setter, _o, *reinterpret_cast<Type*>(_a[0]));
913 } else if (p.member) {
914 propSet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
915 propNotify(p.notify, p.member, _o);
916 }
917 break;
918 case QMetaObject::ResetProperty:
919 if (p.reset) {
920 propReset(p.reset, _o);
921 }
922 break;
923 case QMetaObject::RegisterPropertyMetaType:
924 *reinterpret_cast<int*>(_a[0]) = QtPrivate::QMetaTypeIdHelper<Type>::qt_metatype_id();
925 }
926 }
927
928 /// Helper for implementation of qt_static_metacall for QMetaObject::CreateInstance
929 /// T is the class, and I is the index of a constructor.
930 template<typename T, class... Args, std::size_t... I>
931 static void createInstanceImpl(void **_a, const MetaConstructorInfo<Args...>&, index_sequence<I...>) {
932 *reinterpret_cast<T**>(_a[0]) =
933 new T(*reinterpret_cast<std::remove_reference_t<Args> *>(_a[I+1])...);
934 }
935 template<typename T, int I>
936 static void createInstance(int _id, void** _a) {
937 if (_id == I) {
938 using TPP = T**;
939 constexpr auto m = w_state(index<I>, ConstructorStateTag{}, TPP{});
940 createInstanceImpl<T>(_a, m, m.argSequence);
941 }
942 }
943
944 /// Implementation of qt_static_metacall for W_OBJECT_IMPL which should be called with
945 /// std::index_sequence for the amount of method, constructor, and properties.
946 template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
947 static void qt_static_metacall_impl2(QObject *_o, QMetaObject::Call _c, int _id, void** _a,
948 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
949 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
950 if (_c == QMetaObject::InvokeMetaMethod) {
951 Q_ASSERT(T::staticMetaObject.cast(_o));
952#if __cplusplus > 201700L
953 (invokeMethod<T, MethI>(reinterpret_cast<T*>(_o), _id, _a),...);
954#else
955 ordered((invokeMethod<T, MethI>(reinterpret_cast<T*>(_o), _id, _a),0)...);
956#endif
957 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
958#if __cplusplus > 201700L
959 (registerMethodArgumentType<T,MethI>(_id, _a),...);
960#else
961 ordered((registerMethodArgumentType<T,MethI>(_id, _a),0)...);
962#endif
963 } else if (_c == QMetaObject::IndexOfMethod) {
964#if __cplusplus > 201700L
965 *reinterpret_cast<int *>(_a[0]) = ((1+indexOfMethod<T,MethI>(reinterpret_cast<void **>(_a[1]))) + ... + 0)-1;
966#else
967 auto r = int{-1};
968 ordered2<int>({(r += (1+indexOfMethod<T,MethI>(reinterpret_cast<void **>(_a[1]))))...});
969 *reinterpret_cast<int *>(_a[0]) = r;
970#endif
971 } else if (_c == QMetaObject::CreateInstance) {
972#if __cplusplus > 201700L
973 (createInstance<T, ConsI>(_id, _a),...);
974#else
975 ordered((createInstance<T, ConsI>(_id, _a),0)...);
976#endif
977 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
978 || _c == QMetaObject::RegisterPropertyMetaType) {
979#if __cplusplus > 201700L
980 (propertyOperation<T,PropI>(static_cast<T*>(_o), _c, _id, _a),...);
981#else
982 ordered((propertyOperation<T,PropI>(static_cast<T*>(_o), _c, _id, _a),0)...);
983#endif
984 }
985 }
986
987 // Same for W_GADGET
988 template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
989 static void qt_static_metacall_impl2(T *_o, QMetaObject::Call _c, int _id, void** _a,
990 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
991 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
992 if (_c == QMetaObject::InvokeMetaMethod) {
993#if __cplusplus > 201700L
994 (invokeMethod<T, MethI>(_o, _id, _a),...);
995#else
996 ordered((invokeMethod<T, MethI>(_o, _id, _a), 0)...);
997#endif
998 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
999#if __cplusplus > 201700L
1000 (registerMethodArgumentType<T,MethI>(_id, _a),...);
1001#else
1002 ordered((registerMethodArgumentType<T,MethI>(_id, _a), 0)...);
1003#endif
1004 } else if (_c == QMetaObject::IndexOfMethod) {
1005 Q_ASSERT_X(false, "qt_static_metacall", "IndexOfMethod called on a Q_GADGET");
1006 } else if (_c == QMetaObject::CreateInstance) {
1007#if __cplusplus > 201700L
1008 (createInstance<T, ConsI>(_id, _a),...);
1009#else
1010 ordered((createInstance<T, ConsI>(_id, _a), 0)...);
1011#endif
1012 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
1013 || _c == QMetaObject::RegisterPropertyMetaType) {
1014#if __cplusplus > 201700L
1015 (propertyOperation<T,PropI>(_o, _c, _id, _a),...);
1016#else
1017 ordered((propertyOperation<T,PropI>(_o, _c, _id, _a), 0)...);
1018#endif
1019 }
1020 }
1021
1022 template<typename T, typename... Ts>
1023 static void qt_static_metacall_impl(Ts &&... args) {
1024 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
1025 return qt_static_metacall_impl2<T>(std::forward<Ts>(args)...,
1026 ObjI::methodSequence, ObjI::constructorSequence, ObjI::propertySequence);
1027 }
1028
1029 /// implementation of qt_metacast
1030 template<typename T>
1031 static void* qt_metacast_impl(T *o, const char *_clname) {
1032 if (!_clname)
1033 return nullptr;
1034 const QByteArrayDataPtr sd = { const_cast<QByteArrayData*>(T::staticMetaObject.d.stringdata) };
1035 if (_clname == QByteArray(sd))
1036 return o;
1037 using ObjI = typename T::W_MetaObjectCreatorHelper::ObjectInfo;
1038 void *result = {};
1039 auto l = [&](auto i) {
1040 using TPP = T**;
1041 using Interface = decltype(w_state(i, InterfaceStateTag{}, TPP{}));
1042 const char *iid = qobject_interface_iid<Interface>();
1043 if (iid && !strcmp(_clname, iid))
1044 result = static_cast<Interface>(o);
1045 };
1046 fold(ObjI::interfaceSequence, l);
1047 if (!result) return o->T::W_BaseType::qt_metacast(_clname);
1048 return result;
1049 }
1050
1051}; // FriendHelper
1052
1053} // namespace w_internal
1054
1055#ifndef QT_INIT_METAOBJECT // Defined in qglobal.h since Qt 5.10
1056#define QT_INIT_METAOBJECT
1057#endif
1058
1059// W_OBJECT_IMPL was designed to take advantage of the GNU extension that ... can have zero arguments.
1060// So we need to work around that to extract the template stuff which may not exist or be composed
1061// of several macro arguments: If the first argument has parentheses, there must be at least two
1062// arguments, so just do a tail. Otherwise, there should be only one or two argument, so take the second.
1063#define W_MACRO_TEMPLATE_STUFF(...) W_MACRO_CONCAT(W_MACRO_TEMPLATE_STUFF_HELPER, W_MACRO_DELAY(W_MACRO_TEMPLATE_STUFF_QUERY,W_MACRO_TEMPLATE_STUFF_HELPER __VA_ARGS__))(__VA_ARGS__)
1064#define W_MACRO_TEMPLATE_STUFF_QUERY(...) W_MACRO_DELAY2(W_MACRO_FIRST, W_MACRO_TEMPLATE_STUFF_HELPER_ ## __VA_ARGS__)
1065#define W_MACRO_TEMPLATE_STUFF_HELPER(...) YES
1066#define W_MACRO_TEMPLATE_STUFF_HELPER_YES TAIL,
1067#define W_MACRO_TEMPLATE_STUFF_HELPER_W_MACRO_TEMPLATE_STUFF_HELPER SECOND,
1068#define W_MACRO_TEMPLATE_STUFF_HELPER_TAIL(...) W_MACRO_MSVC_EXPAND(W_MACRO_TAIL(__VA_ARGS__))
1069#define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND(...) W_MACRO_MSVC_EXPAND(W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(__VA_ARGS__,,))
1070#define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(A,B,...) B
1071#define W_MACRO_FIRST_REMOVEPAREN(...) W_MACRO_REMOVEPAREN(W_MACRO_FIRST(__VA_ARGS__))
1072
1073#define W_OBJECT_IMPL_COMMON(INLINE, ...) \
1074 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) struct W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_MetaObjectCreatorHelper { \
1075 struct Name { static constexpr auto value = w_internal::viewLiteral(W_MACRO_STRIGNIFY(W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__))); }; \
1076 using ObjectInfo = w_internal::ObjectInfo<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_ThisType, Name>; \
1077 }; \
1078 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) INLINE const QT_INIT_METAOBJECT QMetaObject W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::staticMetaObject = \
1079 w_internal::FriendHelper::createMetaObject<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_ThisType>();
1080
1081/// \macro W_OBJECT_IMPL(TYPE [, TEMPLATE_STUFF])
1082/// This macro expand to the code that instantiate the QMetaObject. It must be placed outside of
1083/// the class, in the .cpp file. The TYPE argument must be the qualified name of the class,
1084/// including the namespace, if any.
1085/// Example: `W_OBJECT_IMPL(Namespace::MyClass)`
1086///
1087/// If the class is a templated class, the second argument contains the template introducer.
1088/// Example: `W_OBJECT_IMPL(MyTemplate<T>, template <typename T>)`
1089/// Parentheses are required if there is several template arguments:
1090/// `W_OBJECT_IMPL((MyTemplate2<A,B>), template<typename A, typename B>)`
1091#define W_OBJECT_IMPL(...) \
1092 W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__) \
1093 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
1094 { w_internal::FriendHelper::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(_o, _c, _id, _a); } \
1095 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) const QMetaObject *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::metaObject() const { return &staticMetaObject; } \
1096 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacast(const char *_clname) \
1097 { return w_internal::FriendHelper::qt_metacast_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _clname); } \
1098 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) int W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \
1099 { return w_internal::FriendHelper::qt_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _c, _id, _a); }
1100
1101
1102/// \macro W_GADGET_IMPL(TYPE [, TEMPLATE_STUFF])
1103/// Same as W_OBJECT_IMPL, but for a W_GADGET
1104#define W_GADGET_IMPL(...) \
1105 W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__) \
1106 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
1107 { w_internal::FriendHelper::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(reinterpret_cast<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)*>(_o), _c, _id, _a); }
1108
1109/// \macro W_NAMESPACE_IMPL(...)
1110/// Same as W_OBJECT_IMPL, but for a W_NAMESPACE
1111#define W_NAMESPACE_IMPL(...) \
1112 W_OBJECT_IMPL_COMMON(W_MACRO_EMPTY, __VA_ARGS__)
1113
1114
1115/// \macro W_OBJECT_IMPL_INLINE(TYPE [, TEMPLATE_STUFF])
1116/// Same as W_OBJECT_IMPL, but to be used in a header
1117/// (Requires support for c++17 inline variables)
1118#define W_OBJECT_IMPL_INLINE(...) \
1119 W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__) \
1120 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
1121 { w_internal::FriendHelper::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(_o, _c, _id, _a); } \
1122 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline const QMetaObject *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::metaObject() const { return &staticMetaObject; } \
1123 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacast(const char *_clname) \
1124 { return w_internal::FriendHelper::qt_metacast_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _clname); } \
1125 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline int W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \
1126 { return w_internal::FriendHelper::qt_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _c, _id, _a); }
1127
1128
1129/// \macro W_GADGET_IMPL_INLINE(TYPE [, TEMPLATE_STUFF])
1130/// Same as W_GADGET_IMPL, but to be used in a header
1131/// (Requires support for c++17 inline variables)
1132#define W_GADGET_IMPL_INLINE(...) \
1133 W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__) \
1134 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) inline void W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
1135 { w_internal::FriendHelper::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(reinterpret_cast<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)*>(_o), _c, _id, _a); }
1136
1137/// \macro W_NAMESPACE_IMPL_INLINE(...)
1138/// Same as W_NAMESPACE_IMPL, but to be used in a header
1139/// (Requires support for c++17 inline variables)
1140#define W_NAMESPACE_IMPL_INLINE(...) \
1141 W_OBJECT_IMPL_COMMON(inline, __VA_ARGS__)
1142