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 | |
27 | namespace w_internal { |
28 | |
29 | // Match MetaDataFlags constants form the MetaDataFlags in qmetaobject_p.h |
30 | enum : uint { IsUnresolvedType = 0x80000000, IsUnresolvedNotifySignal = 0x70000000 }; |
31 | |
32 | /// all details about a class T |
33 | template<class T, class Name, size_t L = 1024*1024*1024> |
34 | struct 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 | |
80 | template<class F, size_t... Is> |
81 | constexpr 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 |
91 | template <size_t L, class State, class TPP, class F> |
92 | constexpr 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 |
96 | template<class F, class State, class TPP> |
97 | struct FoldState { |
98 | F&& f; |
99 | template<class I> |
100 | constexpr void operator() (I i) { f(w_state(i, State{}, TPP{}), i); } |
101 | }; |
102 | template <size_t L, class State, class TPP, class F> |
103 | constexpr 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 | |
109 | template <size_t L, class T, class F> |
110 | constexpr 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 |
117 | template<size_t L, size_t PropIdx, typename T, typename O> |
118 | struct ResolveNotifySignal { |
119 | private: |
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 | } |
139 | public: |
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 |
147 | template <size_t L, typename TPP> |
148 | constexpr 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 |
156 | struct 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 | }; |
163 | template <size_t L, typename TPP> |
164 | constexpr bool hasNotifySignal() { |
165 | auto hns = HasNotifySignal{}; |
166 | foldState<L, PropertyStateTag, TPP>(hns); |
167 | return hns.r; |
168 | } |
169 | #endif |
170 | |
171 | |
172 | template<class State> |
173 | struct 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 |
185 | template<class T, class M> |
186 | auto test_public(int) -> std::enable_if_t<std::is_same<void, decltype(T::w_GetAccessSpecifierHelper(M{}))>::value, std::true_type>; |
187 | template<class T, class M> |
188 | auto test_public(float) -> std::false_type; |
189 | template<class T, class M> |
190 | using isPublic = decltype(test_public<T, M>(0)); |
191 | |
192 | template <typename T, typename M, typename = void> struct isProtected : std::false_type {}; |
193 | template <typename T, typename = std::enable_if_t<!std::is_final<T>::value>> |
194 | struct Derived : T { template<typename M, typename X = T> static decltype(X::w_GetAccessSpecifierHelper(std::declval<M>())) test(M); }; |
195 | template <typename T, typename M> struct isProtected<T, M, decltype(Derived<T>::test(std::declval<M>()))> : std::true_type {}; |
196 | |
197 | template<class State, class T> |
198 | struct 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 | |
214 | private: |
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 |
226 | template <typename T, typename = void> struct MetaTypeIdIsBuiltIn : std::false_type {}; |
227 | template <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 |
233 | template<typename T, typename State, typename TypeStr = int> |
234 | constexpr 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 |
248 | template<typename T, typename State, typename TypeStr = int> |
249 | constexpr void handleType(State& s, TypeStr = {}, std::enable_if_t<MetaTypeIdIsBuiltIn<T>::value>* = {}) { |
250 | s.addInts(QMetaTypeId2<T>::MetaType); |
251 | } |
252 | template<typename T, typename State, typename TypeStr = int> |
253 | constexpr 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 | } |
257 | template<typename T, typename State> |
258 | constexpr void handleType(State& s, StringView v, std::enable_if_t<!MetaTypeIdIsBuiltIn<T>::value>* = {}) { |
259 | s.addTypeString(v); |
260 | } |
261 | #endif |
262 | |
263 | template<class State, class T> |
264 | struct 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 |
282 | template<class State, size_t L, class T, bool hasNotify> |
283 | struct NotifySignalGenerator { |
284 | #else |
285 | template<class State, size_t L, class T, bool hasNotify> |
286 | struct NotifySignalGenerator; |
287 | template<class State, size_t L, class T> |
288 | struct 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 | }; |
293 | template<class State, size_t L, class T> |
294 | struct 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 | |
314 | private: |
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 | |
342 | template<class State> |
343 | struct 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 | |
367 | template<class State> |
368 | struct 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 | |
377 | private: |
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 |
389 | template<size_t I, size_t N> |
390 | constexpr 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 |
401 | template<size_t I, size_t N> |
402 | constexpr auto stringFetch(const StringViewArray<N>& s, std::enable_if_t<(I < N)>* = {}) { |
403 | return s[I]; |
404 | } |
405 | template<size_t I, size_t N> |
406 | constexpr auto stringFetch(const StringViewArray<N>& s, std::enable_if_t<!(I < N)>* = {}) { |
407 | (void)s; |
408 | struct _{}; |
409 | return _{}; |
410 | } |
411 | #endif |
412 | template<class Arg, class State, class TypeName> |
413 | constexpr 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 | } |
419 | template<class... Args, class State, class TypeNames, size_t... Is> |
420 | constexpr 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 | |
428 | template<size_t ArgCount, class State, size_t NameCount> |
429 | constexpr 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 | |
435 | template<class State> |
436 | struct 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 | |
444 | private: |
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 | |
492 | template<class State> |
493 | struct 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 |
508 | template<size_t L, class T> |
509 | constexpr 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 |
515 | struct MethodParamOffset { |
516 | int sum{}; |
517 | template<class M, class I> |
518 | constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); } |
519 | }; |
520 | template<size_t L, class T> |
521 | constexpr int methodsParamOffset() { |
522 | auto mpo = MethodParamOffset{}; |
523 | foldMethods<L, T>(mpo); |
524 | return mpo.sum; |
525 | } |
526 | #endif |
527 | #if __cplusplus > 201700L |
528 | template<size_t L, class T> |
529 | constexpr 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 |
535 | struct ConstructorParamOffset { |
536 | int sum{}; |
537 | template<class M, class I> |
538 | constexpr void operator() (M m, I) { sum += int(1 + m.argCount * 2); } |
539 | }; |
540 | template<size_t L, class T> |
541 | constexpr int constructorParamOffset() { |
542 | auto cpo = ConstructorParamOffset{}; |
543 | foldState<L, ConstructorStateTag, T>(cpo); |
544 | return cpo.sum; |
545 | } |
546 | |
547 | #endif |
548 | |
549 | template<class T, size_t N> using RawArray = T[N]; |
550 | template<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 | |
558 | struct 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 | }; |
583 | struct 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 |
642 | template<typename T, typename State> |
643 | constexpr 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 |
695 | template<class T> |
696 | constexpr LayoutBuilder dataLayout = [](){ |
697 | auto r = LayoutBuilder{}; |
698 | generateDataPass<T>(r); |
699 | return r; |
700 | }(); |
701 | #else |
702 | template<class T> |
703 | constexpr auto createLayout() { |
704 | auto r = LayoutBuilder{}; |
705 | generateDataPass<T>(r); |
706 | return r; |
707 | } |
708 | template<class T> |
709 | constexpr LayoutBuilder dataLayout = createLayout<T>(); |
710 | #endif |
711 | |
712 | /// Final data holder |
713 | template<std::size_t StringSize, std::size_t StringCount, std::size_t IntCount> |
714 | struct 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 | }; |
723 | template<class T> |
724 | struct 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 | |
759 | template<class T, class IS> |
760 | struct MetaDataBuilder; |
761 | template<class T, std::size_t... Is> |
762 | struct 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 |
775 | template<class T, std::size_t... Is> |
776 | typename 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 |
783 | template<typename T> |
784 | static constexpr auto parentMetaObject(int) W_RETURN(&T::W_BaseType::staticMetaObject) |
785 | template<typename T> |
786 | static 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. |
791 | template <typename F, typename O, typename T> |
792 | inline auto propSet(F f, O *o, const T &t) W_RETURN(((o->*f)(t),0)) |
793 | template <typename F, typename O, typename T> |
794 | inline auto propSet(F f, O *o, const T &t) W_RETURN(o->*f = t) |
795 | template <typename O, typename T> |
796 | inline void propSet(Empty, O *, const T &) {} |
797 | |
798 | template <typename F, typename O, typename T> |
799 | inline auto propGet(F f, O *o, T &t) W_RETURN(t = (o->*f)()) |
800 | template <typename F, typename O, typename T> |
801 | inline auto propGet(F f, O *o, T &t) W_RETURN(t = o->*f) |
802 | template <typename O, typename T> |
803 | inline void propGet(Empty, O *, T &) {} |
804 | |
805 | template <typename F, typename M, typename O> |
806 | inline auto propNotify(F f, M m, O *o) W_RETURN(((o->*f)(o->*m),0)) |
807 | template <typename F, typename M, typename O> |
808 | inline auto propNotify(F f, M, O *o) W_RETURN(((o->*f)(),0)) |
809 | template <typename... T> |
810 | inline void propNotify(T...) {} |
811 | |
812 | template <typename F, typename O> |
813 | inline auto propReset(F f, O *o) W_RETURN(((o->*f)(),0)) |
814 | template <typename... T> |
815 | inline void propReset(T...) {} |
816 | |
817 | struct 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 | |
849 | QT_WARNING_PUSH |
850 | QT_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 | } |
863 | QT_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 | |