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/** concatenate()
30 * Returns a StaticString which is the concatenation of all the strings in a StaticStringList
31 * Note: keeps the \0 between the strings
32 */
33template<typename I1, typename I2> struct concatenate_helper;
34template<std::size_t... I1, std::size_t... I2> struct concatenate_helper<std::index_sequence<I1...>, std::index_sequence<I2...>> {
35 static constexpr int size = sizeof...(I1) + sizeof...(I2);
36 static constexpr auto concatenate(const StaticString<sizeof...(I1)> &s1, const StaticString<sizeof...(I2)> &s2) {
37 StaticStringArray<size> d = { s1[I1]... , s2[I2]... };
38 return StaticString<size>( d );
39 }
40};
41constexpr StaticString<1> concatenate(StaticStringList<>) { return {""}; }
42template<typename T> constexpr auto concatenate(StaticStringList<binary::Leaf<T>> s) { return s.root.data; }
43template<typename A, typename B> constexpr auto concatenate(StaticStringList<binary::Node<A,B>> s) {
44 auto a = concatenate(binary::tree<A>{s.root.a});
45 auto b = concatenate(binary::tree<B>{s.root.b});
46 return concatenate_helper<make_index_sequence<a.size>, make_index_sequence<b.size>>::concatenate(a, b);
47}
48
49enum { IsUnresolvedType = 0x80000000, IsUnresolvedNotifySignal = 0x70000000 };
50
51/*
52 * The QMetaObject is basically an array of int and an array of string.
53 * Some of the int in the array are index in the string array.
54 *
55 * The IntermediateState class helps building the QMetaObject.
56 * It contains the StaticStringList of strings within this meta object, and the array of int as
57 * template parameter.
58 *
59 * It has helper method that helps extending the state
60 */
61template<typename Strings, uint... Ints>
62struct IntermediateState {
63 Strings strings;
64 /// add a string to the strings state and add its index to the end of the int array
65 template<int L>
66 constexpr auto addString(const StaticString<L> & s) const {
67 auto s2 = binary::tree_append(strings, s);
68 return IntermediateState<decltype(s2), Ints..., Strings::size>{s2};
69 }
70
71 /// same as before but add the IsUnresolvedType flag
72 template<uint Flag = IsUnresolvedType, int L>
73 constexpr auto addTypeString(const StaticString<L> & s) const {
74 auto s2 = binary::tree_append(strings, s);
75 return IntermediateState<decltype(s2), Ints...,
76 Flag | Strings::size>{s2};
77 }
78
79
80 template<uint... Add>
81 constexpr IntermediateState<Strings, Ints..., Add...> add() const
82 { return { strings }; }
83
84 static constexpr std::index_sequence<Ints ...> sequence = {};
85};
86
87/**
88 * Iterate over all the items of a tree and call the Generator::generate function
89 *
90 * The first parameter of the function is the IntermediateState, and it returns a new
91 * InterMediateState with all the information from the tree added to it.
92 *
93 * The 'Ofst' template parameter is the offset in the integer array to which new data can be added.
94 *
95 * The Generator template type has a method generate which will be called for every element of the
96 * tree with the IntermediateState. It is called with the offset as a template parameter.
97 *
98 * The Generator also has an offset() method that returns how much things will be added later in
99 * the array for this element.
100 */
101template<typename Generator, int Ofst, typename State>
102constexpr auto generate(State s, binary::tree<>)
103{ return s; }
104template<typename Generator, int Ofst, typename State, typename Tree>
105constexpr auto generate(State s, Tree t) {
106 return generate<Generator, Ofst + Generator::template offset<binary::tree_element_t<0,Tree>>()>(
107 Generator::template generate<Ofst>(s, binary::tree_head(t)), binary::tree_tail(t));
108}
109
110/**
111 * Helper comparator that compare function pointers and return true if they are the same or
112 * false if they are different. If they are of different type, they are different */
113template <typename T1, typename T2> constexpr bool getSignalIndexHelperCompare(T1, T2) { return false; }
114template <typename T> constexpr bool getSignalIndexHelperCompare(T f1, T f2) { return f1 == f2; }
115
116/** Helper to get information bout the notify signal of the property with index Idx of the object T */
117template<typename T, int Idx, typename BaseT = T>
118struct ResolveNotifySignal {
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<BaseT**>(nullptr));
122
123private:
124 // We need to use SFINAE because of GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69681
125 // For some reason, GCC fails to consider f1==f2 as a constexpr if f1 and f2 are pointer to
126 // different function of the same type. Fortunately, when both are pointing to the same function
127 // it compiles fine, so we can use SFINAE for it.
128 template<int SigIdx>
129 static constexpr std::enable_if_t<getSignalIndexHelperCompare(binary::get<SigIdx>(signalState).func, property.notify) || true, int>
130 helper(int)
131 { return getSignalIndexHelperCompare(binary::get<SigIdx>(signalState).func, property.notify) ? SigIdx : -1; }
132 template<int SigIdx> static constexpr int helper(...) { return -1; }
133
134 template<size_t... I>
135 static constexpr int computeSignalIndex(index_sequence<I...>) {
136 return std::max({-1, helper<I>(0)...});
137 }
138public:
139 static constexpr int signalIndex = computeSignalIndex(make_index_sequence<signalState.size>());
140};
141
142/** returns true if the object T has at least one property with a notify signal */
143template <typename T, std::size_t... I>
144static constexpr bool hasNotifySignal(std::index_sequence<I...>)
145{
146 constexpr auto propertyInfo = w_PropertyState(w_number<>{},static_cast<T**>(nullptr));
147 Q_UNUSED(propertyInfo) // in case I is empty
148 return sums(!std::is_same<decltype(binary::get<I>(propertyInfo).notify), std::nullptr_t>::value ...);
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 notify signals to be used in generate
264template<typename T, bool hasNotify>
265struct NotifySignalGenerator {
266 template<typename> static constexpr int offset() { return 1; }
267 template<int Idx, typename State, typename Prop>
268 static constexpr auto generate(State s, Prop prop) {
269 return process<Idx>(s, prop.notify);
270 }
271private:
272
273 static constexpr auto propertyInfo = w_PropertyState(w_number<>{},static_cast<T**>(nullptr));
274
275 // No notify signal
276 template<int, typename State>
277 static constexpr auto process(State s, std::nullptr_t) {
278 return s.template add<0>();
279 }
280
281 // Signal in the same class
282 template<int Idx, typename State, typename Func>
283 static constexpr auto process(State s, Func, std::enable_if_t<
284 std::is_same<T, typename QtPrivate::FunctionPointer<Func>::Object>::value, int> = 0)
285 {
286 constexpr int signalIndex = ResolveNotifySignal<T, Idx>::signalIndex;
287 static_assert(signalIndex >= 0, "NOTIFY signal not registered as a signal");
288 return s.template add<signalIndex>();
289 }
290
291 // Signal in a parent class
292 template<int Idx, typename State, typename Func>
293 static constexpr auto process(State s, Func, std::enable_if_t<
294 !std::is_same<T, typename QtPrivate::FunctionPointer<Func>::Object>::value, int> = 0)
295 {
296 using Finder = ResolveNotifySignal<T, Idx, typename QtPrivate::FunctionPointer<Func>::Object>;
297 static_assert(Finder::signalIndex >= 0, "NOTIFY signal in parent class not registered as a W_SIGNAL");
298 static_assert(Finder::signalIndex < 0 || QT_VERSION >= QT_VERSION_CHECK(5, 10, 0),
299 "NOTIFY signal in parent class requires Qt 5.10");
300 constexpr auto sig = binary::get<Finder::signalIndex>(Finder::signalState);
301 return s.template addTypeString<IsUnresolvedNotifySignal>(sig.name);
302 }
303};
304template<typename T> struct NotifySignalGenerator<T,false> {
305 template<typename> static constexpr int offset() { return 0; }
306 template<int, typename State, typename Prop>
307 static constexpr auto generate(State s, Prop) { return s; }
308};
309
310// Generator for enums to be used in generate<>()
311struct EnumGenerator {
312 template<typename Enum> static constexpr int offset() { return Enum::count * 2; }
313 template<int DataIndex, typename State, typename Enum>
314 static constexpr auto generate(State s, Enum e) {
315 return s.addString(e.name).template add< //name
316 Enum::flags,
317 Enum::count,
318 DataIndex
319 >();
320 }
321};
322
323// Generator for enum values
324struct EnumValuesGenerator {
325 template<typename Strings>
326 static constexpr auto generateSingleEnumValues(const Strings &s, std::index_sequence<>, binary::tree<>)
327 { return s; }
328
329 template<typename Strings, std::size_t Value, std::size_t... I, typename Names>
330 static constexpr auto generateSingleEnumValues(const Strings &s, std::index_sequence<Value, I...>, Names names) {
331 auto s2 = s.addString(binary::tree_head(names)).template add<uint(Value)>();
332 return generateSingleEnumValues(s2, std::index_sequence<I...>{}, binary::tree_tail(names));
333 }
334
335 template<typename> static constexpr int offset() { return 0; }
336 template<int, typename State, typename Enum>
337 static constexpr auto generate(State s, Enum e) {
338 return generateSingleEnumValues(s, typename Enum::Values{}, e.names);
339 }
340};
341
342/**
343 * Helper classes for MethodParametersGenerator::generateSingleMethodParameter:
344 * generate the parameter array
345 */
346template<typename ...Args> struct HandleArgsHelper {
347 template<typename Strings, typename ParamTypes>
348 static constexpr auto result(const Strings &ss, const ParamTypes&)
349 { return ss; }
350};
351template<typename A, typename... Args>
352struct HandleArgsHelper<A, Args...> {
353 template<typename Strings, typename ParamTypes>
354 static constexpr auto result(const Strings &ss, const ParamTypes &paramTypes) {
355 using Type = typename QtPrivate::RemoveConstRef<A>::Type;
356 auto typeStr = binary::tree_head(paramTypes);
357 using ts_t = decltype(typeStr);
358 // This way, the overload of result will not pick the StaticString one if it is a tuple (because registered types have the priority)
359 auto typeStr2 = std::conditional_t<std::is_same<A, Type>::value, ts_t, std::tuple<ts_t>>{typeStr};
360 auto r1 = HandleType<Type>::result(ss, typeStr2);
361 return HandleArgsHelper<Args...>::result(r1, binary::tree_tail(paramTypes));
362 }
363};
364template<int N> struct HandleArgNames {
365 template<typename Strings, typename Str>
366 static constexpr auto result(const Strings &ss, StaticStringList<Str> pn)
367 {
368 auto s2 = ss.addString(binary::tree_head(pn));
369 auto tail = binary::tree_tail(pn);
370 return HandleArgNames<N-1>::result(s2, tail);
371 }
372 template<typename Strings> static constexpr auto result(const Strings &ss, StaticStringList<> pn)
373 { return HandleArgNames<N-1>::result(ss.template add<1>(), pn); }
374};
375template<> struct HandleArgNames<0> {
376 template<typename Strings, typename PN> static constexpr auto result(const Strings &ss, PN)
377 { return ss; }
378};
379
380// Generator for method parameters to be used in generate<>()
381struct MethodParametersGenerator {
382private:
383 // non-const function
384 template<typename Strings, typename ParamTypes, typename ParamNames, typename Obj, typename Ret, typename... Args>
385 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (Obj::*)(Args...),
386 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
387 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
388 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
389 }
390 template<typename Strings, typename ParamTypes, typename ParamNames, typename Obj, typename Ret, typename... Args>
391 // const function
392 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (Obj::*)(Args...) const,
393 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
394 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
395 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
396 }
397 // static member functions
398 template<typename Strings, typename ParamTypes, typename ParamNames, typename Ret, typename... Args>
399 static constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (*)(Args...),
400 const ParamTypes &paramTypes, const ParamNames &paramNames ) {
401 auto types = HandleArgsHelper<Ret, Args...>::result(ss, binary::tree_prepend(paramTypes, 0));
402 return HandleArgNames<sizeof...(Args)>::result(types, paramNames);
403 }
404public:
405
406 template<typename> static constexpr int offset() { return 0; }
407 template<int, typename State, typename Method>
408 static constexpr auto generate(State s, Method method) {
409 // Dispatch either non const function, const function or static function
410 return generateSingleMethodParameter(s, method.func, method.paramTypes, method.paramNames);
411 }
412};
413
414// Generator for constructor parameter to be used in generate<>()
415struct ConstructorParametersGenerator {
416 template<typename> static constexpr int offset() { return 0; }
417 template<int, typename State, int N, typename... Args>
418 static constexpr auto generate(State s, MetaConstructorInfo<N,Args...>) {
419 auto s2 = s.template add<IsUnresolvedType | 1>();
420 auto s3 = HandleArgsHelper<Args...>::result(s2, binary::tree<>{});
421 return s3.template add<((void)sizeof(Args),1)...>(); // all the names are 1 (for "\0")
422 }
423};
424
425/** Given method, a binary::tree containing information about methods or constructor,
426 * return the amount of item it will add in the int array. */
427template<typename Methods, std::size_t... I>
428constexpr int paramOffset(std::index_sequence<I...>)
429{ return sums(int(1 + binary::tree_element_t<I, Methods>::argCount * 2)...); }
430
431/**
432 * Generate the integer array and the lists of string
433 */
434template<typename T, typename ObjI>
435constexpr auto generateDataArray(const ObjI &objectInfo) {
436
437 constexpr bool hasNotify = hasNotifySignal<T>(make_index_sequence<ObjI::propertyCount>{});
438 constexpr int classInfoOffstet = 14;
439 constexpr int methodOffset = classInfoOffstet + ObjI::classInfoCount * 2;
440 constexpr int propertyOffset = methodOffset + ObjI::methodCount * 5;
441 constexpr int enumOffset = propertyOffset + ObjI::propertyCount * (hasNotify ? 4: 3);
442 constexpr int constructorOffset = enumOffset + ObjI::enumCount* 4;
443 constexpr int paramIndex = constructorOffset + ObjI::constructorCount * 5 ;
444 constexpr int constructorParamIndex = paramIndex +
445 paramOffset<decltype(objectInfo.methods)>(make_index_sequence<ObjI::methodCount>{});
446 constexpr int enumValueOffset = constructorParamIndex +
447 paramOffset<decltype(objectInfo.constructors)>(make_index_sequence<ObjI::constructorCount>{});
448
449 auto stringData = binary::tree_append(binary::tree_append(binary::tree<>{} , objectInfo.name), StaticString<1>(""));
450 IntermediateState<decltype(stringData),
451 7, // revision
452 0, // classname
453 ObjI::classInfoCount, classInfoOffstet, // classinfo
454 ObjI::methodCount, methodOffset, // methods
455 ObjI::propertyCount, propertyOffset, // properties
456 ObjI::enumCount, enumOffset, // enums/sets
457 ObjI::constructorCount, constructorOffset, // constructors
458 0x4 /* PropertyAccessInStaticMetaCall */, // flags
459 ObjI::signalCount
460 > header = { stringData };
461
462 auto classInfos = generate<ClassInfoGenerator, paramIndex>(header , objectInfo.classInfos);
463 auto methods = generate<MethodGenerator, paramIndex>(classInfos , objectInfo.methods);
464 auto properties = generate<PropertyGenerator, 0>(methods, objectInfo.properties);
465 auto notify = generate<NotifySignalGenerator<T, hasNotify>, 0>(properties, objectInfo.properties);
466 auto enums = generate<EnumGenerator, enumValueOffset>(notify, objectInfo.enums);
467 auto constructors = generate<MethodGenerator, constructorParamIndex>(enums, objectInfo.constructors);
468 auto parametters = generate<MethodParametersGenerator, 0>(constructors, objectInfo.methods);
469 auto parametters2 = generate<ConstructorParametersGenerator, 0>(parametters, objectInfo.constructors);
470 auto enumValues = generate<EnumValuesGenerator, 0>(parametters2, objectInfo.enums);
471 return std::make_pair(enumValues.strings, enumValues.sequence);
472}
473
474/**
475 * Holder for the string data. Just like in the moc generated code.
476 */
477template<int N, int L> struct qt_meta_stringdata_t {
478 QByteArrayData data[N];
479 char stringdata[L];
480};
481
482/** Builds the string data
483 * \param S: a index_sequence that goes from 0 to the full size of the strings
484 * \param I: a index_sequence that goes from 0 to the number of string
485 * \param O: a index_sequence of the offsets
486 * \param N: a index_sequence of the size of each strings
487 * \param T: the W_MetaObjectCreatorHelper
488 */
489template<typename S, typename I, typename O, typename N, typename T> struct BuildStringDataHelper;
490template<std::size_t... S, std::size_t... I, std::size_t... O, std::size_t...N, typename T>
491struct BuildStringDataHelper<std::index_sequence<S...>, std::index_sequence<I...>, std::index_sequence<O...>, std::index_sequence<N...>, T> {
492 using meta_stringdata_t = const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>;
493 static meta_stringdata_t qt_meta_stringdata;
494#ifndef Q_CC_MSVC
495 static constexpr qptrdiff stringdata_offset = offsetof(meta_stringdata_t, stringdata);
496#else // offsetof does not work with MSVC
497 static constexpr qptrdiff stringdata_offset = sizeof(meta_stringdata_t::data);
498#endif
499 static constexpr auto concatenated = concatenate(T::string_data);
500};
501template<std::size_t... S, std::size_t... I, std::size_t... O, std::size_t...N, typename T>
502const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>
503BuildStringDataHelper<std::index_sequence<S...>, std::index_sequence<I...>, std::index_sequence<O...>, std::index_sequence<N...>, T>::qt_meta_stringdata = {
504 {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(N-1,
505 stringdata_offset + O - I * sizeof(QByteArrayData))...},
506 { concatenated[S]... }
507};
508
509/**
510 * Given N a list of string sizes, compute the list offsets to each of the strings.
511 */
512template<std::size_t... N> struct ComputeOffsets;
513template<> struct ComputeOffsets<> {
514 using Result = std::index_sequence<>;
515};
516template<std::size_t H, std::size_t... T> struct ComputeOffsets<H, T...> {
517 template<std::size_t ... I> static std::index_sequence<0, (I+H)...> func(std::index_sequence<I...>);
518 using Result = decltype(func(typename ComputeOffsets<T...>::Result()));
519};
520
521/**
522 * returns the string data suitable for the QMetaObject from a list of string
523 * T is W_MetaObjectCreatorHelper<ObjectType>
524 */
525// N... are all the sizes of the strings
526template<typename T, int... N>
527constexpr const QByteArrayData *build_string_data() {
528 return BuildStringDataHelper<make_index_sequence<sums(N...)>,
529 make_index_sequence<sizeof...(N)>,
530 typename ComputeOffsets<N...>::Result,
531 std::index_sequence<N...>,
532 T>
533 ::qt_meta_stringdata.data;
534}
535template<typename T, std::size_t... I>
536constexpr const QByteArrayData *build_string_data(std::index_sequence<I...>) {
537 return build_string_data<T, decltype(binary::get<I>(T::string_data))::size...>();
538}
539
540
541/**
542 * returns a pointer to an array of string built at compile time.
543 */
544template<typename I> struct build_int_data;
545template<std::size_t... I> struct build_int_data<std::index_sequence<I...>> {
546 static const uint data[sizeof...(I)];
547};
548template<std::size_t... I> const uint build_int_data<std::index_sequence<I...>>::data[sizeof...(I)] = { uint(I)... };
549
550/** Returns the QMetaObject* of the base type. Use SFINAE to only return it if it exists */
551template<typename T>
552static constexpr auto parentMetaObject(int) W_RETURN(&T::W_BaseType::staticMetaObject)
553template<typename T>
554static constexpr const QMetaObject *parentMetaObject(...) { return nullptr; }
555
556// Bunch of helpers for propertyOperation
557// this uses SFINAE of the return value to work either with F a pointer to member, or to member function
558// or nullptr.
559template <typename F, typename O, typename T>
560inline auto propSet(F f, O *o, const T &t) W_RETURN(((o->*f)(t),0))
561template <typename F, typename O, typename T>
562inline auto propSet(F f, O *o, const T &t) W_RETURN(o->*f = t)
563template <typename O, typename T>
564inline void propSet(std::nullptr_t, O *, const T &) {}
565
566template <typename F, typename O, typename T>
567inline auto propGet(F f, O *o, T &t) W_RETURN(t = (o->*f)())
568template <typename F, typename O, typename T>
569inline auto propGet(F f, O *o, T &t) W_RETURN(t = o->*f)
570template <typename O, typename T>
571inline void propGet(std::nullptr_t, O *, T &) {}
572
573template <typename F, typename M, typename O>
574inline auto propNotify(F f, M m, O *o) W_RETURN(((o->*f)(o->*m),0))
575template <typename F, typename M, typename O>
576inline auto propNotify(F f, M, O *o) W_RETURN(((o->*f)(),0))
577template <typename... T>
578inline void propNotify(T...) {}
579
580template <typename F, typename O>
581inline auto propReset(F f, O *o) W_RETURN(((o->*f)(),0))
582template <typename... T>
583inline void propReset(T...) {}
584
585struct FriendHelper {
586/** Instancies the QMetaObject for class T */
587template<typename T>
588static constexpr QMetaObject createMetaObject()
589{
590 using Creator = typename T::W_MetaObjectCreatorHelper;
591 auto string_data = build_string_data<Creator>(make_index_sequence<Creator::string_data.size>());
592 auto int_data = build_int_data<typename std::remove_const<decltype(Creator::int_data)>::type>::data;
593 return { { parentMetaObject<T>(0) , string_data , int_data, T::qt_static_metacall, {}, {} } };
594}
595
596/** Implementation of qt_metacall */
597template<typename T> static int qt_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a) {
598 using Creator = typename T::W_MetaObjectCreatorHelper;
599 _id = _o->T::W_BaseType::qt_metacall(_c, _id, _a);
600 if (_id < 0)
601 return _id;
602 if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
603 constexpr int methodCount = Creator::objectInfo.methodCount;
604 if (_id < methodCount)
605 T::qt_static_metacall(_o, _c, _id, _a);
606 _id -= methodCount;
607 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
608 || _c == QMetaObject::RegisterPropertyMetaType) {
609 constexpr int propertyCount = Creator::objectInfo.propertyCount;
610 if (_id < propertyCount)
611 T::qt_static_metacall(_o, _c, _id, _a);
612 _id -= propertyCount;
613 }
614 return _id;
615}
616
617/**
618 * Helper for implementation of qt_static_metacall for QMetaObject::IndexOfMethod
619 * T is the class, and I is the index of a method.
620 * Returns I if the argument is equal to the pointer to member function of the signal of index 'I'
621 */
622template<typename T, int I>
623static int indexOfMethod(void **func) {
624 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
625 using Ms = decltype(T::W_MetaObjectCreatorHelper::objectInfo.methods);
626 if ((binary::tree_element_t<I,Ms>::flags & 0xc) == W_MethodType::Signal.value
627 && f == *reinterpret_cast<decltype(f)*>(func))
628 return I;
629 return -1;
630}
631
632/**
633 * Helper for implementation of qt_static_metacall for QMetaObject::InvokeMetaMethod
634 * T is the class, and I is the index of a method.
635 * Invoke the method with index I if id == I.
636 */
637template <typename T, int I>
638static void invokeMethod(T *_o, int _id, void **_a) {
639 if (_id == I) {
640 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
641 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
642 P::template call<typename P::Arguments, typename P::ReturnType>(f, _o, _a);
643 }
644}
645
646/**
647 * Helper for implementation of qt_static_metacall for QMetaObject::RegisterMethodArgumentMetaType
648 * T is the class, and I is the index of a method.
649 */
650template <typename T, int I>
651static void registerMethodArgumentType(int _id, void **_a) {
652 if (_id == I) {
653 constexpr auto f = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.methods).func;
654 using P = QtPrivate::FunctionPointer<std::remove_const_t<decltype(f)>>;
655 auto _t = QtPrivate::ConnectionTypes<typename P::Arguments>::types();
656 uint arg = *reinterpret_cast<int*>(_a[1]);
657 *reinterpret_cast<int*>(_a[0]) = _t && arg < P::ArgumentCount ?
658 _t[arg] : -1;
659 }
660}
661
662/**
663 * Helper for implementation of qt_static_metacall for any of the operations in a property
664 * T is the class, and I is the index of a property.
665 */
666template<typename T, int I>
667static void propertyOperation(T *_o, QMetaObject::Call _c, int _id, void **_a) {
668 if (_id != I)
669 return;
670 constexpr auto p = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.properties);
671 using Type = typename decltype(p)::PropertyType;
672 switch(+_c) {
673 case QMetaObject::ReadProperty:
674 if (p.getter != nullptr) {
675 propGet(p.getter, _o, *reinterpret_cast<Type*>(_a[0]));
676 } else if (p.member != nullptr) {
677 propGet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
678 }
679 break;
680 case QMetaObject::WriteProperty:
681 if (p.setter != nullptr) {
682 propSet(p.setter, _o, *reinterpret_cast<Type*>(_a[0]));
683 } else if (p.member != nullptr) {
684 propSet(p.member, _o, *reinterpret_cast<Type*>(_a[0]));
685 propNotify(p.notify, p.member, _o);
686 }
687 break;
688 case QMetaObject::ResetProperty:
689 if (p.reset != nullptr) {
690 propReset(p.reset, _o);
691 }
692 break;
693 case QMetaObject::RegisterPropertyMetaType:
694 *reinterpret_cast<int*>(_a[0]) = QtPrivate::QMetaTypeIdHelper<Type>::qt_metatype_id();
695 }
696}
697
698/**
699 * Helper for implementation of qt_static_metacall for QMetaObject::CreateInstance
700 * T is the class, and I is the index of a constructor.
701 */
702template<typename T, int I>
703static void createInstance(int _id, void** _a) {
704 if (_id == I) {
705 constexpr auto m = binary::get<I>(T::W_MetaObjectCreatorHelper::objectInfo.constructors);
706 m.template createInstance<T>(_a, make_index_sequence<decltype(m)::argCount>{});
707 }
708}
709
710/**
711 * Function that does nothing but helps to expand template packs.
712 */
713template<typename...Ts> static constexpr void nop(Ts...) {}
714
715/**
716 * Implementation of qt_static_metacall for W_OBJECT_IMPL which should be called with
717 * std::index_sequence for the amount of method, constructor, and properties.
718 */
719template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
720static void qt_static_metacall_impl(QObject *_o, QMetaObject::Call _c, int _id, void** _a,
721 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
722 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
723 if (_c == QMetaObject::InvokeMetaMethod) {
724 Q_ASSERT(T::staticMetaObject.cast(_o));
725 nop((invokeMethod<T, MethI>(static_cast<T*>(_o), _id, _a),0)...);
726 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
727 nop((registerMethodArgumentType<T,MethI>(_id, _a),0)...);
728 } else if (_c == QMetaObject::IndexOfMethod) {
729 *reinterpret_cast<int *>(_a[0]) = sums((1+indexOfMethod<T,MethI>(reinterpret_cast<void **>(_a[1])))...)-1;
730 } else if (_c == QMetaObject::CreateInstance) {
731 nop((createInstance<T, ConsI>(_id, _a),0)...);
732 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
733 || _c == QMetaObject::RegisterPropertyMetaType) {
734 nop((propertyOperation<T,PropI>(static_cast<T*>(_o), _c, _id, _a),0)...);
735 }
736}
737
738/** Same for W_GADGET */
739template<typename T, size_t...MethI, size_t ...ConsI, size_t...PropI>
740static void qt_static_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a,
741 std::index_sequence<MethI...>, std::index_sequence<ConsI...>, std::index_sequence<PropI...>) {
742 Q_UNUSED(_id) Q_UNUSED(_o) Q_UNUSED(_a)
743 if (_c == QMetaObject::InvokeMetaMethod) {
744 nop((invokeMethod<T, MethI>(_o, _id, _a),0)...);
745 } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
746 nop((registerMethodArgumentType<T,MethI>(_id, _a),0)...);
747 } else if (_c == QMetaObject::IndexOfMethod) {
748 Q_ASSERT_X(false, "qt_static_metacall", "IndexOfMethod called on a Q_GADGET");
749 } else if (_c == QMetaObject::CreateInstance) {
750 nop((createInstance<T, ConsI>(_id, _a),0)...);
751 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
752 || _c == QMetaObject::RegisterPropertyMetaType) {
753 nop((propertyOperation<T,PropI>(_o, _c, _id, _a),0)...);
754 }
755}
756
757/** helper for the implementation of qt_metacast */
758template <typename Interface, typename T>
759static void interfaceMetaCast(void *&result, T *o, const char *clname) {
760 const char *iid = qobject_interface_iid<Interface>();
761 if (iid && !strcmp(clname, iid))
762 result = static_cast<Interface>(o);
763}
764
765/** implementation of qt_metacast */
766template<typename T, size_t... InterfaceI>
767static void *qt_metacast_impl(T *o, const char *_clname, std::index_sequence<InterfaceI...>) {
768 if (!_clname)
769 return nullptr;
770 const QByteArrayDataPtr sd = { const_cast<QByteArrayData*>(T::staticMetaObject.d.stringdata) };
771 if (_clname == QByteArray(sd))
772 return o;
773 void *result = nullptr;
774 nop((interfaceMetaCast<decltype(binary::get<InterfaceI>(T::W_MetaObjectCreatorHelper::objectInfo.interfaces))>(result, o, _clname),0)...);
775 return result ? result : o->T::W_BaseType::qt_metacast(_clname);
776}
777
778}; // FriendHelper
779
780// Forward to the FriendHelper
781template<typename T> constexpr auto createMetaObject() { return FriendHelper::createMetaObject<T>(); }
782template<typename T, typename... Ts> auto qt_metacall_impl(Ts &&...args)
783{ return FriendHelper::qt_metacall_impl<T>(std::forward<Ts>(args)...); }
784template<typename T> auto qt_metacast_impl(T *o, const char *_clname) {
785 using ObjI = decltype(T::W_MetaObjectCreatorHelper::objectInfo);
786 return FriendHelper::qt_metacast_impl<T>(o, _clname,
787 make_index_sequence<ObjI::interfaceCount>{});
788}
789template<typename T, typename... Ts> auto qt_static_metacall_impl(Ts &&... args) {
790 using ObjI = decltype(T::W_MetaObjectCreatorHelper::objectInfo);
791 return FriendHelper::qt_static_metacall_impl<T>(std::forward<Ts>(args)...,
792 make_index_sequence<ObjI::methodCount>{},
793 make_index_sequence<ObjI::constructorCount>{},
794 make_index_sequence<ObjI::propertyCount>{});
795}
796} // w_internal
797
798#ifdef Q_OS_WIN
799// On Windows, taking the address of exported symbols is not a constexpr. (At least with MinGW 5.3)
800// So the staticMetaObject can't be constexpr because of the pointer to the base class QMetaObject
801#define W_STATICMETAOBJECT_CONSTEXPR
802#else
803#define W_STATICMETAOBJECT_CONSTEXPR constexpr
804#endif
805
806// W_OBJECT_IMPL was designed to take advantage of the GNU extension that ... can have zero arguments.
807// So we need to work around that to extract the template stuff which may not exist or be composed
808// of several macro arguments: If the first argument has parentheses, there must be at least two
809// arguments, so just do a tail. Otherwise, there should be only one or two argument, so take the second.
810#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__)
811#define W_MACRO_TEMPLATE_STUFF_QUERY(...) W_MACRO_DELAY2(W_MACRO_FIRST, W_MACRO_TEMPLATE_STUFF_HELPER_ ## __VA_ARGS__)
812#define W_MACRO_TEMPLATE_STUFF_HELPER(...) YES
813#define W_MACRO_TEMPLATE_STUFF_HELPER_YES TAIL,
814#define W_MACRO_TEMPLATE_STUFF_HELPER_W_MACRO_TEMPLATE_STUFF_HELPER SECOND,
815#define W_MACRO_TEMPLATE_STUFF_HELPER_TAIL(...) W_MACRO_MSVC_EXPAND(W_MACRO_TAIL(__VA_ARGS__))
816#define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND(...) W_MACRO_MSVC_EXPAND(W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(__VA_ARGS__,,))
817#define W_MACRO_TEMPLATE_STUFF_HELPER_SECOND2(A,B,...) B
818#define W_MACRO_FIRST_REMOVEPAREN(...) W_MACRO_REMOVEPAREN(W_MACRO_FIRST(__VA_ARGS__))
819
820#define W_OBJECT_IMPL_COMMON(...) \
821 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) struct W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_MetaObjectCreatorHelper { \
822 static constexpr auto objectInfo = \
823 w_internal::makeObjectInfo<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_ThisType>(W_MACRO_STRIGNIFY(W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__))); \
824 static constexpr auto data = w_internal::generateDataArray<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_ThisType>(objectInfo); \
825 static constexpr auto string_data = data.first; \
826 static constexpr auto int_data = data.second; \
827 }; \
828 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) W_STATICMETAOBJECT_CONSTEXPR const QMetaObject W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::staticMetaObject = \
829 w_internal::createMetaObject<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::W_ThisType>();
830
831#define W_OBJECT_IMPL(...) \
832 W_OBJECT_IMPL_COMMON(__VA_ARGS__) \
833 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) \
834 { w_internal::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(_o, _c, _id, _a); } \
835 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) const QMetaObject *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::metaObject() const { return &staticMetaObject; } \
836 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) void *W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacast(const char *_clname) \
837 { return w_internal::qt_metacast_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _clname); } \
838 W_MACRO_TEMPLATE_STUFF(__VA_ARGS__) int W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)::qt_metacall(QMetaObject::Call _c, int _id, void** _a) \
839 { return w_internal::qt_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(this, _c, _id, _a); }
840
841
842#define W_GADGET_IMPL(...) \
843 W_OBJECT_IMPL_COMMON(__VA_ARGS__) \
844 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) \
845 { w_internal::qt_static_metacall_impl<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)>(reinterpret_cast<W_MACRO_FIRST_REMOVEPAREN(__VA_ARGS__)*>(_o), _c, _id, _a); }
846
847
848#define W_NAMESPACE_IMPL(...) \
849 W_OBJECT_IMPL_COMMON(__VA_ARGS__)
850
851