1/****************************************************************************
2 * Copyright (C) 2016 Woboq GmbH
3 * Olivier Goffart <contact at woboq.com>
4 * https://woboq.com/
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#pragma once
20
21#include "wobjectdefs.h"
22#include <QtCore/qobject.h>
23
24namespace w_internal {
25
26/** concatenate()
27 * Returns a StaticString which is the concatenation of all the strings in a StaticStringList
28 * Note: keeps the \0 between the strings
29 */
30template<typename I1, typename I2> struct concatenate_helper;
31template<std::size_t... I1, std::size_t... I2> struct concatenate_helper<std::index_sequence<I1...>, std::index_sequence<I2...>> {
32 static constexpr int size = sizeof...(I1) + sizeof...(I2);
33 static constexpr auto concatenate(const StaticString<sizeof...(I1)> &s1, const StaticString<sizeof...(I2)> &s2) {
34 StaticStringArray<size> d = { s1[I1]... , s2[I2]... };
35 return StaticString<size>( d );
36 }
37};
38constexpr StaticString<1> concatenate(StaticStringList<>) { return {""}; }
39template<typename T> constexpr auto concatenate(StaticStringList<binary::Leaf<T>> s) { return s.root.data; }
40template<typename A, typename B> constexpr auto concatenate(StaticStringList<binary::Node<A,B>> s) {
41 auto a = concatenate(binary::tree<A>{s.root.a});
42 auto b = concatenate(binary::tree<B>{s.root.b});
43 return concatenate_helper<make_index_sequence<a.size>, make_index_sequence<b.size>>::concatenate(a, b);
44}
45
46enum { IsUnresolvedType = 0x80000000 };
47
48/*
49 * The QMetaObject is basically an array of int and an array of string.
50 * Some of the int in the array are index in the string array.
51 *
52 * The IntermediateState class helps building the QMetaObject.
53 * It contains the StaticStringList of strings within this meta object, and the array of int as
54 * template parameter.
55 *
56 * It has helper method that helps extending the state
57 */
58template<typename Strings, uint... Ints>
59struct IntermediateState {
60 Strings strings;
61 /// add a string to the strings state and add its index to the end of the int array
62 template<int L>
63 constexpr auto addString(const StaticString<L> & s) const {
64 auto s2 = binary::tree_append(strings, s);
65 return IntermediateState<decltype(s2), Ints..., Strings::size>{s2};
66 }
67
68 /// same as before but ass the IsUnresolvedType flag
69 template<int L>
70 constexpr auto addTypeString(const StaticString<L> & s) const {
71 auto s2 = binary::tree_append(strings, s);
72 return IntermediateState<decltype(s2), Ints...,
73 IsUnresolvedType | Strings::size>{s2};
74 }
75
76
77 template<uint... Add>
78 constexpr IntermediateState<Strings, Ints..., Add...> add() const
79 { return { strings }; }
80
81 static constexpr std::index_sequence<Ints ...> sequence = {};
82};
83
84/**
85 * Iterate over all the items of a tree and call the Generator::generate function
86 *
87 * The first parameter f the function is the IntermediateState, and it returns a new
88 * InterMediateState with all the information from the tree added to it.
89 *
90 * The 'Ofst' template parameter is the offset in the integer array to which new data can be added.
91 *
92 * The Generator template type has a method generate which will be called for every element of the
93 * tree with the IntermediateState. It is called with the offset as a template parameter.
94 *
95 * The Generator also has an offset() method that returns how much things will be added later in
96 * the array for this element.
97 */
98template<typename Generator, int Ofst, typename State>
99constexpr auto generate(State s, binary::tree<>)
100{ return s; }
101template<typename Generator, int Ofst, typename State, typename Tree>
102constexpr auto generate(State s, Tree t) {
103 return generate<Generator, Ofst + Generator::template offset<binary::tree_element_t<0,Tree>>()>(
104 Generator::template generate<Ofst>(s, binary::tree_head(t)), binary::tree_tail(t));
105}
106
107/**
108 * Helper comparator that compare function pointers and return true if they are the same or
109 * false if they are different. If they are of different type, they are different */
110template <typename T1, typename T2> constexpr bool getSignalIndexHelperCompare(T1, T2) { return false; }
111template <typename T> constexpr bool getSignalIndexHelperCompare(T f1, T f2) { return f1 == f2; }
112
113/** Helper to get information bout the notify signal of the property with index Idx of the object T */
114template<typename T, int Idx, typename = make_index_sequence<w_SignalState(w_number<>{},static_cast<T**>(nullptr)).size>>
115struct ResolveNotifySignal;
116template<typename T, int Idx, size_t ...I>
117struct ResolveNotifySignal<T, Idx, index_sequence<I...>> {
118private:
119 static constexpr auto propertyInfo = w_PropertyState(w_number<>{},static_cast<T**>(nullptr));
120 static constexpr auto property = binary::get<Idx>(propertyInfo);
121 static constexpr auto signalState = w_SignalState(w_number<>{},static_cast<T**>(nullptr));
122
123 // We need to use SFINAE because of GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69681
124 // For some reason, GCC fails to consider f1==f2 as a constexpr if f1 and f2 are pointer to
125 // different function of the same type. Fortunately, when both are pointing to the same function
126 // it compiles fine, so we can use SFINAE for it.
127 template<int SigIdx>
128 static constexpr std::enable_if_t<getSignalIndexHelperCompare(binary::get<SigIdx>(signalState).func, property.notify) || true, int>
129 helper(int)
130 { return getSignalIndexHelperCompare(binary::get<SigIdx>(signalState).func, property.notify) ? SigIdx : -1; }
131 template<int SigIdx> static constexpr int helper(...) { return -1; }
132public:
133 static constexpr bool hasNotify = !std::is_same<decltype(property.notify), std::nullptr_t>::value;
134 static constexpr int signalIndex = !hasNotify ? -1 : std::max({-1, helper<I>(0)...});
135 static_assert(signalIndex >= 0 || !hasNotify, "NOTIFY signal not registered as a signal");
136};
137
138/** Add the notify signal index to the intermediate state, for each properties */
139template <typename T, typename State, std::size_t... I>
140static constexpr auto generateNotifySignals(State s, std::true_type, std::index_sequence<I...>)
141{ return s.template add<std::max(0, ResolveNotifySignal<T, I>::signalIndex)...>(); }
142template <typename T, typename State, std::size_t... I>
143static constexpr auto generateNotifySignals(State s, std::false_type, std::index_sequence<I...>)
144{ return s; }
145/** returns true if the object T has at least one property with a notify signal */
146template <typename T, std::size_t... I>
147static constexpr bool hasNotifySignal(std::index_sequence<I...>)
148{ return sums(ResolveNotifySignal<T, I>::hasNotify...); }
149
150
151/** Holds information about a class, including all the properties and methods */
152template<int NameLength, typename Methods, typename Constructors, typename Properties,
153 typename Enums, typename ClassInfos, typename Interfaces, int SignalCount>
154struct ObjectInfo {
155 StaticString<NameLength> name;
156 Methods methods;
157 Constructors constructors;
158 Properties properties;
159 Enums enums;
160 ClassInfos classInfos;
161 Interfaces interfaces;
162
163 static constexpr int methodCount = Methods::size;
164 static constexpr int constructorCount = Constructors::size;
165 static constexpr int propertyCount = Properties::size;
166 static constexpr int enumCount = Enums::size;
167 static constexpr int classInfoCount = ClassInfos::size;
168 static constexpr int interfaceCount = Interfaces::size;
169 static constexpr int signalCount = SignalCount;
170};
171
172/**
173 * Constructs a ObjectInfo for the object T.
174 * Pass the (qualified) name as a static string.
175 * Called from W_OBJECT_IMPL
176 */
177template<typename T, int N>
178static constexpr auto makeObjectInfo(StaticStringArray<N> &name) {
179 constexpr auto sigState = w_SignalState(w_number<>{}, static_cast<T**>(nullptr));
180 constexpr auto methodInfo = binary::tree_cat(sigState, w_SlotState(w_number<>{}, static_cast<T**>(nullptr)),
181 w_MethodState(w_number<>{}, static_cast<T**>(nullptr)));
182 constexpr auto constructorInfo = w_ConstructorState(w_number<>{}, static_cast<T**>(nullptr));
183 constexpr auto propertyInfo = w_PropertyState(w_number<>{}, static_cast<T**>(nullptr));
184 constexpr auto enumInfo = w_EnumState(w_number<>{}, static_cast<T**>(nullptr));
185 constexpr auto classInfo = w_ClassInfoState(w_number<>{}, static_cast<T**>(nullptr));
186 constexpr auto interfaceInfo = w_InterfaceState(w_number<>{}, static_cast<T**>(nullptr));
187 constexpr int sigCount = sigState.size;
188 return ObjectInfo<N, decltype(methodInfo), decltype(constructorInfo), decltype(propertyInfo),
189 decltype(enumInfo), decltype(classInfo), decltype(interfaceInfo), sigCount>
190 { {name}, methodInfo, constructorInfo, propertyInfo, enumInfo, classInfo, interfaceInfo };
191}
192
193// Generator for Q_CLASSINFO to be used in generate<>()
194struct ClassInfoGenerator {
195 template<typename> static constexpr int offset() { return 0; }
196 template<int, typename State, typename CI>
197 static constexpr auto generate(State s, CI ci) {
198 return s.addString(ci.first).addString(ci.second);
199 }
200};
201
202// Generator for methods to be used in generate<>()
203struct MethodGenerator {
204 template<typename Method> static constexpr int offset() { return 1 + Method::argCount * 2; }
205 template<int ParamIndex, typename State, typename Method>
206 static constexpr auto generate(State s, Method method) {
207 return s.addString(method.name). // name
208 template add<Method::argCount,
209 ParamIndex, //parameters
210 1, //tag, always \0
211 adjustFlags(Method::flags)>();
212 }
213 // because public and private are inverted
214 static constexpr uint adjustFlags(uint f) {
215 return (f & W_Access::Protected.value) ? f : (f ^ W_Access::Private.value);
216 }
217};
218
219/** Helper that computes if type T is a builtin QMetaType */
220template <typename T, typename = void> struct MetaTypeIdIsBuiltIn : std::false_type {};
221template <typename T> struct MetaTypeIdIsBuiltIn<T, typename std::enable_if<QMetaTypeId2<T>::IsBuiltIn>::type> : std::true_type{};
222
223/**
224 * Helper to generate the type information of type 'T':
225 * If T is a builtin QMetaType, its meta type id need to be added in the state.
226 * If it's not builtin, then it would be an reference to T's name in the string array.
227 */
228template<typename T, bool Builtin = MetaTypeIdIsBuiltIn<T>::value>
229struct HandleType {
230 template<typename S, typename TypeStr = int>
231 static constexpr auto result(const S&s, TypeStr = {})
232 { return s.template add<QMetaTypeId2<T>::MetaType>(); }
233};
234template<typename T>
235struct HandleType<T, false> {
236 template<typename Strings, typename TypeStr = int>
237 static constexpr auto result(const Strings &ss, TypeStr = {}) {
238 return ss.addTypeString(W_TypeRegistery<T>::name);
239 static_assert(W_TypeRegistery<T>::registered, "Please Register T with W_REGISTER_ARGTYPE");
240 }
241 template<typename Strings, int N>
242 static constexpr auto result(const Strings &ss, StaticString<N> typeStr,
243 typename std::enable_if<(N>1),int>::type=0) {
244 return ss.addTypeString(typeStr);
245 }
246};
247
248// Generator for properties to be used in generate<>()
249struct PropertyGenerator {
250 template<typename> static constexpr int offset() { return 0; }
251 template<int, typename State, typename Prop>
252 static constexpr auto generate(State s, Prop prop) {
253 auto s2 = s.addString(prop.name);
254 auto s3 = HandleType<typename Prop::PropertyType>::result(s2, prop.typeStr);
255 constexpr uint moreFlags = (QtPrivate::IsQEnumHelper<typename Prop::PropertyType>::Value
256 ? uint(PropertyFlags::EnumOrFlag) : 0);
257 constexpr uint defaultFlags = 0 | PropertyFlags::Stored | PropertyFlags::Scriptable
258 | PropertyFlags::Designable;
259 return s3.template add<Prop::flags | moreFlags | defaultFlags>();
260 }
261};
262
263// Generator for enums to be used in generate<>()
264struct EnumGenerator {
265 template<typename Enum> static constexpr int offset() { return Enum::count * 2; }
266 template<int DataIndex, typename State, typename Enum>
267 static constexpr auto generate(State s, Enum e) {
268 return s.addString(e.name).template add< //name
269 Enum::flags,
270 Enum::count,
271 DataIndex
272 >();
273 }
274};
275
276// Generator for enum values
277struct EnumValuesGenerator {
278 template<typename Strings>
279 static constexpr auto generateSingleEnumValues(const Strings &s, std::index_sequence<>, binary::tree<>)
280 { return s; }
281
282 template<typename Strings, std::size_t Value, std::size_t... I, typename Names>
283 static constexpr auto generateSingleEnumValues(const Strings &s, std::index_sequence<Value, I...>, Names names) {
284 auto s2 = s.addString(binary::tree_head(names)).template add<uint(Value)>();
285 return generateSingleEnumValues(s2, std::index_sequence<I...>{}, binary::tree_tail(names));
286 }
287
288 template<typename> static constexpr int offset() { return 0; }
289 template<int, typename State, typename Enum>
290 static constexpr auto generate(State s, Enum e) {
291 return generateSingleEnumValues(s, typename Enum::Values{}, e.names);
292 }
293};
294
295/**
296 * Helper classes for MethodParametersGenerator::generateSingleMethodParameter:
297 * generate the parameter array
298 */
299template<typename ...Args> struct HandleArgsHelper {
300 template<typename Strings, typename ParamTypes>
301 static constexpr auto result(const Strings &ss, const ParamTypes&)
302 { return ss; }
303};
304template<typename A, typename... Args>
305struct HandleArgsHelper<A, Args...> {
306 template<typename Strings, typename ParamTypes>
307 static constexpr auto result(const Strings &ss, const ParamTypes &paramTypes) {
308 using Type = typename QtPrivate::RemoveConstRef<A>::Type;
309 auto typeStr = binary::tree_head(paramTypes);
310 using ts_t = decltype(typeStr);
311 // This way, the overload of result will not pick the StaticString one if it is a tuple (because registered types have the priority)
312 auto typeStr2 = std::conditional_t<std::is_same<A, Type>::value, ts_t, std::tuple<ts_t>>{typeStr};
313 auto r1 = HandleType<Type>::result(ss, typeStr2);
314 return HandleArgsHelper<Args...>::result(r1, binary::tree_tail(paramTypes));
315 }
316};
317template<int N> struct HandleArgNames {
318 template<typename Strings, typename Str>
319 static constexpr auto result(const Strings &ss, StaticStringList<Str> pn)
320 {
321 auto s2 = ss.addString(binary::tree_head(pn));
322 auto tail = binary::tree_tail(pn);
323 return HandleArgNames<N-1>::result(s2, tail);
324 }
325 template<typename Strings> static constexpr auto result(const Strings &ss, StaticStringList<> pn)
326 { return HandleArgNames<N-1>::result(ss.template add<1>(), pn); }
327};
328template<> struct HandleArgNames<0> {
329 template<typename Strings, typename PN> static constexpr auto result(const Strings &ss, PN)
330 { return ss; }
331};
332
333// Generator for method parameters to be used in generate<>()
334struct MethodParametersGenerator {
335private:
336 // non-const function
337 template<typename Strings, typename ParamTypes, typename ParamNames, typename Obj, typename Ret, typename... Args>
338 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (Obj::*)(Args...),
339 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
340 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
341 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
342 }
343 template<typename Strings, typename ParamTypes, typename ParamNames, typename Obj, typename Ret, typename... Args>
344 // const function
345 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (Obj::*)(Args...) const,
346 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
347 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
348 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
349 }
350 // static member functions
351 template<typename Strings, typename ParamTypes, typename ParamNames, typename Ret, typename... Args>
352 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (*)(Args...),
353 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
354 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
355 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
356 }
357public:
358
359 template<typename> static constexpr int offset() { return 0; }
360 template<int, typename State, typename Method>
361 static constexpr auto generate(State s, Method method) {
362 // Dispatch either non const function, const function or static function
363 return generateSingleMethodParameter(s, method.func, method.paramTypes, method.paramNames);
364 }
365};
366
367// Generator for constructor parameter to be used in generate<>()
368struct ConstructorParametersGenerator {
369 template<typename> static constexpr int offset() { return 0; }
370 template<int, typename State, int N, typename... Args>
371 static constexpr auto generate(State s, MetaConstructorInfo<N,Args...>) {
372 auto s2 = s.template add<IsUnresolvedType | 1>();
373 auto s3 = HandleArgsHelper<Args...>::result(s2, binary::tree<>{});
374 return s3.template add<((void)sizeof(Args),1)...>(); // all the names are 1 (for "\0")
375 }
376};
377
378/** Given method, a binary::tree containing information about methods or constructor,
379 * return the amount of item it will add in the int array. */
380template<typename Methods, std::size_t... I>
381constexpr int paramOffset(std::index_sequence<I...>)
382{ return sums(int(1 + binary::tree_element_t<I, Methods>::argCount * 2)...); }
383
384/**
385 * Generate the integer array and the lists of string
386 */
387template<typename T, typename ObjI>
388constexpr auto generateDataArray(const ObjI &objectInfo) {
389
390 constexpr bool hasNotify = hasNotifySignal<T>(make_index_sequence<ObjI::propertyCount>{});
391 constexpr int classInfoOffstet = 14;
392 constexpr int methodOffset = classInfoOffstet + ObjI::classInfoCount * 2;
393 constexpr int propertyOffset = methodOffset + ObjI::methodCount * 5;
394 constexpr int enumOffset = propertyOffset + ObjI::propertyCount * (hasNotify ? 4: 3);
395 constexpr int constructorOffset = enumOffset + ObjI::enumCount* 4;
396 constexpr int paramIndex = constructorOffset + ObjI::constructorCount * 5 ;
397 constexpr int constructorParamIndex = paramIndex +
398 paramOffset<decltype(objectInfo.methods)>(make_index_sequence<ObjI::methodCount>{});
399 constexpr int enumValueOffset = constructorParamIndex +
400 paramOffset<decltype(objectInfo.constructors)>(make_index_sequence<ObjI::constructorCount>{});
401
402 auto stringData = binary::tree_append(binary::tree_append(binary::tree<>{} , objectInfo.name), StaticString<1>(""));
403 IntermediateState<decltype(stringData),
404 7, // revision
405 0, // classname
406 ObjI::classInfoCount, classInfoOffstet, // classinfo
407 ObjI::methodCount, methodOffset, // methods
408 ObjI::propertyCount, propertyOffset, // properties
409 ObjI::enumCount, enumOffset, // enums/sets
410 ObjI::constructorCount, constructorOffset, // constructors
411 0x4 /* PropertyAccessInStaticMetaCall */, // flags
412 ObjI::signalCount
413 > header = { stringData };
414
415 auto classInfos = generate<ClassInfoGenerator, paramIndex>(header , objectInfo.classInfos);
416 auto methods = generate<MethodGenerator, paramIndex>(classInfos , objectInfo.methods);
417 auto properties = generate<PropertyGenerator, 0>(methods, objectInfo.properties);
418 auto notify = generateNotifySignals<T>(properties, std::integral_constant<bool, hasNotify>{},
419 make_index_sequence<ObjI::propertyCount>{});
420 auto enums = generate<EnumGenerator, enumValueOffset>(notify, objectInfo.enums);
421 auto constructors = generate<MethodGenerator, constructorParamIndex>(enums, objectInfo.constructors);
422 auto parametters = generate<MethodParametersGenerator, 0>(constructors, objectInfo.methods);
423 auto parametters2 = generate<ConstructorParametersGenerator, 0>(parametters, objectInfo.constructors);
424 auto enumValues = generate<EnumValuesGenerator, 0>(parametters2, objectInfo.enums);
425 return std::make_pair(enumValues.strings, enumValues.sequence);
426}
427
428/**
429 * Holder for the string data. Just like in the moc generated code.
430 */
431template<int N, int L> struct qt_meta_stringdata_t {
432 QByteArrayData data[N];
433 char stringdata[L];
434};
435
436/** Builds the string data
437 * \param S: a index_sequence that goes from 0 to the full size of the strings
438 * \param I: a index_sequence that goes from 0 to the number of string
439 * \param O: a index_sequence of the offsets
440 * \param N: a index_sequence of the size of each strings
441 * \param T: the W_MetaObjectCreatorHelper
442 */
443template<typename S, typename I, typename O, typename N, typename T> struct BuildStringDataHelper;
444template<std::size_t... S, std::size_t... I, std::size_t... O, std::size_t...N, typename T>
445struct BuildStringDataHelper<std::index_sequence<S...>, std::index_sequence<I...>, std::index_sequence<O...>, std::index_sequence<N...>, T> {
446 using meta_stringdata_t = const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>;
447 static meta_stringdata_t qt_meta_stringdata;
448};
449template<std::size_t... S, std::size_t... I, std::size_t... O, std::size_t...N, typename T>
450const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>
451BuildStringDataHelper<std::index_sequence<S...>, std::index_sequence<I...>, std::index_sequence<O...>, std::index_sequence<N...>, T>::qt_meta_stringdata = {
452 {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(N-1,
453 qptrdiff(offsetof(meta_stringdata_t, stringdata) + O - I * sizeof(QByteArrayData)) )...},
454 { concatenate(T::string_data)[S]... }
455};
456
457/**
458 * Given N a list of string sizes, compute the list offsets to each of the strings.
459 */
460template<std::size_t... N> struct ComputeOffsets;
461template<> struct ComputeOffsets<> {
462 using Result = std::index_sequence<>;
463};
464template<std::size_t H, std::size_t... T> struct ComputeOffsets<H, T...> {
465 template<std::size_t ... I> static std::index_sequence<0, (I+H)...> func(std::index_sequence<I...>);
466 using Result = decltype(func(typename ComputeOffsets<T...>::Result()));
467};
468
469/**
470 * returns the string data suitable for the QMetaObject from a list of string
471 * T is W_MetaObjectCreatorHelper<ObjectType>
472 */
473// N... are all the sizes of the strings
474template<typename T, int... N>
475constexpr const QByteArrayData *build_string_data() {
476 return BuildStringDataHelper<make_index_sequence<sums(N...)>,
477 make_index_sequence<sizeof...(N)>,
478 typename ComputeOffsets<N...>::Result,
479 std::index_sequence<N...>,
480 T>
481 ::qt_meta_stringdata.data;
482}
483template<typename T, std::size_t... I>
484constexpr const QByteArrayData *build_string_data(std::index_sequence<I...>) {
485 return build_string_data<T, decltype(binary::get<I>(T::string_data))::size...>();
486}
487
488
489/**
490 * returns a pointer to an array of string built at compile time.
491 */
492template<typename I> struct build_int_data;
493template<std::size_t... I> struct build_int_data<std::index_sequence<I...>> {
494 static const uint data[sizeof...(I)];
495};
496template<std::size_t... I> const uint build_int_data<std::index_sequence<I...>>::data[sizeof...(I)] = { uint(I)... };
497
498/** Returns the QMetaObject* of the base type. Use SFINAE to only return it if it exists */
499template<typename T>
500static constexpr auto parentMetaObject(int) W_RETURN(&T::W_BaseType::staticMetaObject)
501template<typename T>
502static constexpr const QMetaObject *parentMetaObject(...) { return nullptr; }
503
504// Bunch of helpers for propertyOperation
505// this uses SFINAE of the return value to work either with F a pointer to member, or to member function
506// or nullptr.
507template <typename F, typename O, typename T>
508inline auto propSet(F f, O *o, const T &t) W_RETURN(((o->*f)(t),0))
509template <typename F, typename O, typename T>
510inline auto propSet(F f, O *o, const T &t) W_RETURN(o->*f = t)
511template <typename O, typename T>
512inline void propSet(std::nullptr_t, O *, const T &) {}
513
514template <typename F, typename O, typename T>
515inline auto propGet(F f, O *o, T &t) W_RETURN(t = (o->*f)())
516template <typename F, typename O, typename T>
517inline auto propGet(F f, O *o, T &t) W_RETURN(t = o->*f)
518template <typename O, typename T>
519inline void propGet(std::nullptr_t, O *, T &) {}
520
521template <typename F, typename M, typename O>
522inline auto propNotify(F f, M m, O *o) W_RETURN(((o->*f)(o->*m),0))
523template <typename F, typename M, typename O>
524inline auto propNotify(F f, M, O *o) W_RETURN(((o->*f)(),0))
525template <typename... T>
526inline void propNotify(T...) {}
527
528template <typename F, typename O>
529inline auto propReset(F f, O *o) W_RETURN(((o->*f)(),0))
530template <typename... T>
531inline void propReset(T...) {}
532
533struct FriendHelper {
534/** Instancies the QMetaObject for class T */
535template<typename T>
536static constexpr QMetaObject createMetaObject()
537{
538 using Creator = typename T::W_MetaObjectCreatorHelper;
539 auto string_data = build_string_data<Creator>(make_index_sequence<Creator::string_data.size>());
540 auto int_data = build_int_data<typename std::remove_const<decltype(Creator::int_data)>::type>::data;
541 return { { parentMetaObject<T>(0) , string_data , int_data, T::qt_static_metacall, {}, {} } };
542}
543
544/** Implementation of qt_metacall */
545template<typename T> static int qt_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a) {
546 using Creator = typename T::W_MetaObjectCreatorHelper;
547 _id = _o->T::W_BaseType::qt_metacall(_c, _id, _a);
548 if (_id < 0)
549 return _id;
550 if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
551 constexpr int methodCount = Creator::objectInfo.methodCount;
552 if (_id < methodCount)
553 T::qt_static_metacall(_o, _c, _id, _a);
554 _id -= methodCount;
555 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
556 || _c == QMetaObject::RegisterPropertyMetaType) {
557 constexpr int propertyCount = Creator::objectInfo.propertyCount;
558 if (_id < propertyCount)
559 T::qt_static_metacall(_o, _c, _id, _a);
560 _id -= propertyCount;
561 }
562 return _id;
563}
564
565/**
566 * Helper for implementation of qt_static_metacall for QMetaObject::IndexOfMethod
567 * T is the class, and I is the index of a method.
568 * Returns I if the argument is equal to the pointer to member function of the signal of index 'I'
569 */
570template<typename T, int I>
571static int indexOfMethod(void **func) {
572 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
573 using Ms = decltype(T::W_MetaObjectCreatorHelper::objectInfo.methods);
574 if ((binary::tree_element_t<I,Ms>::flags & 0xc) == W_MethodType::Signal.value
575 && f == *reinterpret_cast<decltype(f)*>(func))
576 return I;
577 return -1;
578}
579
580/**
581 * Helper for implementation of qt_static_metacall for QMetaObject::InvokeMetaMethod
582 * T is the class, and I is the index of a method.
583 * Invoke the method with index I if id == I.
584 */
585template <typename T, int I>
586static void invokeMethod(T *_o, int _id, void **_a) {
587 if (_id == I) {
588 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
589 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
590 P::template call<typename P::Arguments, typename P::ReturnType>(f, _o, _a);
591 }
592}
593
594/**
595 * Helper for implementation of qt_static_metacall for QMetaObject::RegisterMethodArgumentMetaType
596 * T is the class, and I is the index of a method.
597 */
598template <typename T, int I>
599static void registerMethodArgumentType(int _id, void **_a) {
600 if (_id == I) {
601 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
602 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
603 auto _t = QtPrivate::ConnectionTypes<typename P::Arguments>::types();
604 uint arg = *reinterpret_cast<int*>(_a[1]);
605 *reinterpret_cast<int*>(_a[0]) = _t && arg < P::ArgumentCount ?
606 _t[arg] : -1;
607 }
608}
609
610/**
611 * Helper for implementation of qt_static_metacall for any of the operations in a property
612 * T is the class, and I is the index of a property.
613 */
614template<typename T, int I>
615static void propertyOperation(T *_o, QMetaObject::Call _c, int _id, void **_a) {
616 if (_id != I)
617 return;
618 constexpr auto p = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.properties);
619 using Type = typename decltype(p)::PropertyType;
620 switch(+_c) {
621 case QMetaObject::ReadProperty:
622 if (p.getter != nullptr) {
623 propGet(p.getter, _o, *reinterpret_cast<Type*>(_a[0]));
624 } else if (p.member != nullptr) {
625 propGet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
626 }
627 break;
628 case QMetaObject::WriteProperty:
629 if (p.setter != nullptr) {
630 propSet(p.setter, _o, *reinterpret_cast<Type*>(_a[0]));
631 } else if (p.member != nullptr) {
632 propSet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
633 propNotify(p.notify, p.member, _o);
634 }
635 break;
636 case QMetaObject::ResetProperty:
637 if (p.reset != nullptr) {
638 propReset(p.reset, _o);
639 }
640 break;
641 case QMetaObject::RegisterPropertyMetaType:
642 *reinterpret_cast<int*>(_a[0]) = QtPrivate::QMetaTypeIdHelper<Type>::qt_metatype_id();
643 }
644}
645
646/**
647 * Helper for implementation of qt_static_metacall for QMetaObject::CreateInstance
648 * T is the class, and I is the index of a constructor.
649 */
650template<typename T, int I>
651static void createInstance(int _id, void** _a) {
652 if (_id == I) {
653 constexpr auto m = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.constructors);
654 m.template createInstance<T>(_a, make_index_sequence<decltype(m)::argCount>{});
655 }
656}
657
658/**
659 * Function that does nothing but helps to expand template packs.
660 */
661template<typename...Ts> static constexpr void nop(Ts...) {}
662
663/**
664 * Implementation of qt_static_metacall for W_OBJECT_IMPL which should be called with
665 * std::index_sequence for the amount of method, constructor, and properties.
666 */
667template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
668static void qt_static_metacall_impl(QObject *_o, QMetaObject::Call _c, int _id, void** _a,
669 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
670 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
671 if (_c == QMetaObject::InvokeMetaMethod) {
672 Q_ASSERT(T::staticMetaObject.cast(_o));
673 nop((invokeMethod<T, MethI>(static_cast<T*>(_o), _id, _a),0)...);
674 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
675 nop((registerMethodArgumentType<T,MethI>(_id, _a),0)...);
676 } else if (_c == QMetaObject::IndexOfMethod) {
677 *reinterpret_cast<int *>(_a[0]) = sums((1+indexOfMethod<T,MethI>(reinterpret_cast<void **>(_a[1])))...)-1;
678 } else if (_c == QMetaObject::CreateInstance) {
679 nop((createInstance<T, ConsI>(_id, _a),0)...);
680 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
681 || _c == QMetaObject::RegisterPropertyMetaType) {
682 nop((propertyOperation<T,PropI>(static_cast<T*>(_o), _c, _id, _a),0)...);
683 }
684}
685
686/** Same for W_GADGET */
687template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
688static void qt_static_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a,
689 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
690 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
691 if (_c == QMetaObject::InvokeMetaMethod) {
692 nop((invokeMethod<T, MethI>(_o, _id, _a),0)...);
693 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
694 nop((registerMethodArgumentType<T,MethI>(_id, _a),0)...);
695 } else if (_c == QMetaObject::IndexOfMethod) {
696 Q_ASSERT_X(false, "qt_static_metacall", "IndexOfMethod called on a Q_GADGET");
697 } else if (_c == QMetaObject::CreateInstance) {
698 nop((createInstance<T, ConsI>(_id, _a),0)...);
699 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
700 || _c == QMetaObject::RegisterPropertyMetaType) {
701 nop((propertyOperation<T,PropI>(_o, _c, _id, _a),0)...);
702 }
703}
704
705/** helper for the implementation of qt_metacast */
706template <typename Interface, typename T>
707static void interfaceMetaCast(void *&result, T *o, const char *clname) {
708 const char *iid = qobject_interface_iid<Interface>();
709 if (iid && !strcmp(clname, iid))
710 result = static_cast<Interface>(o);
711}
712
713/** implementation of qt_metacast */
714template<typename T, size_t... InterfaceI>
715static void *qt_metacast_impl(T *o, const char *_clname, std::index_sequence<InterfaceI...>) {
716 if (!_clname)
717 return nullptr;
718 const QByteArrayDataPtr sd = { const_cast<QByteArrayData*>(T::staticMetaObject.d.stringdata) };
719 if (_clname == QByteArray(sd))
720 return o;
721 void *result = nullptr;
722 nop((interfaceMetaCast<decltype(binary::get<InterfaceI>(T::W_MetaObjectCreatorHelper::objectInfo.interfaces))>(result, o, _clname),0)...);
723 return result ? result : o->T::W_BaseType::qt_metacast(_clname);
724}
725
726}; // FriendHelper
727
728// Forward to the FriendHelper
729template<typename T> constexpr auto createMetaObject() { return FriendHelper::createMetaObject<T>(); }
730template<typename T, typename... Ts> auto qt_metacall_impl(Ts &&...args)
731{ return FriendHelper::qt_metacall_impl<T>(std::forward<Ts>(args)...); }
732template<typename T> auto qt_metacast_impl(T *o, const char *_clname) {
733 using ObjI = decltype(T::W_MetaObjectCreatorHelper::objectInfo);
734 return FriendHelper::qt_metacast_impl<T>(o, _clname,
735 make_index_sequence<ObjI::interfaceCount>{});
736}
737template<typename T, typename... Ts> auto qt_static_metacall_impl(Ts &&... args) {
738 using ObjI = decltype(T::W_MetaObjectCreatorHelper::objectInfo);
739 return FriendHelper::qt_static_metacall_impl<T>(std::forward<Ts>(args)...,
740 make_index_sequence<ObjI::methodCount>{},
741 make_index_sequence<ObjI::constructorCount>{},
742 make_index_sequence<ObjI::propertyCount>{});
743}
744} // w_internal
745
746#ifdef Q_OS_WIN
747// On Windows, taking the address of exported symbols is not a constexpr. (At least with MinGW 5.3)
748// So the staticMetaObject can't be constexpr because of the pointer to the base class QMetaObject
749#define W_STATICMETAOBJECT_CONSTEXPR
750#else
751#define W_STATICMETAOBJECT_CONSTEXPR constexpr
752#endif
753
754#define W_OBJECT_IMPL_COMMON(TYPE, ...) \
755 __VA_ARGS__ struct W_MACRO_REMOVEPAREN(TYPE)::W_MetaObjectCreatorHelper { \
756 static constexpr auto objectInfo = \
757 w_internal::makeObjectInfo<W_MACRO_REMOVEPAREN(TYPE)>(W_MACRO_STRIGNIFY(W_MACRO_REMOVEPAREN(TYPE))); \
758 static constexpr auto data = w_internal::generateDataArray<W_MACRO_REMOVEPAREN(TYPE)>(objectInfo); \
759 static constexpr auto string_data = data.first; \
760 static constexpr auto int_data = data.second; \
761 }; \
762 __VA_ARGS__ W_STATICMETAOBJECT_CONSTEXPR const QMetaObject W_MACRO_REMOVEPAREN(TYPE)::staticMetaObject = \
763 w_internal::createMetaObject<W_MACRO_REMOVEPAREN(TYPE)>();
764
765#define W_OBJECT_IMPL(TYPE, ...) \
766 W_OBJECT_IMPL_COMMON(TYPE, __VA_ARGS__) \
767 __VA_ARGS__ void W_MACRO_REMOVEPAREN(TYPE)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
768 { w_internal::qt_static_metacall_impl<W_MACRO_REMOVEPAREN(TYPE)>(_o, _c, _id, _a); } \
769 __VA_ARGS__ const QMetaObject *W_MACRO_REMOVEPAREN(TYPE)::metaObject() const { return &staticMetaObject; } \
770 __VA_ARGS__ void *W_MACRO_REMOVEPAREN(TYPE)::qt_metacast(const char *_clname) \
771 { return w_internal::qt_metacast_impl<W_MACRO_REMOVEPAREN(TYPE)>(this, _clname); } \
772 __VA_ARGS__ int W_MACRO_REMOVEPAREN(TYPE)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \
773 { return w_internal::qt_metacall_impl<W_MACRO_REMOVEPAREN(TYPE)>(this, _c, _id, _a); }
774
775
776#define W_GADGET_IMPL(TYPE, ...) \
777 W_OBJECT_IMPL_COMMON(TYPE, __VA_ARGS__) \
778 __VA_ARGS__ void W_MACRO_REMOVEPAREN(TYPE)::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) \
779 { w_internal::qt_static_metacall_impl<W_MACRO_REMOVEPAREN(TYPE)>(reinterpret_cast<W_MACRO_REMOVEPAREN(TYPE)*>(_o), _c, _id, _a); }
780