File indexing completed on 2025-10-29 08:53:06
0001
0002
0003
0004 #ifndef QTMOCHELPERS_H
0005 #define QTMOCHELPERS_H
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include <QtCore/qmetatype.h>
0019 #include <QtCore/qtmocconstants.h>
0020
0021 #include <QtCore/q20algorithm.h> // std::min, std::copy_n
0022 #include <QtCore/q23type_traits.h> // std::is_scoped_enum
0023 #include <limits>
0024
0025 #if 0
0026 #pragma qt_no_master_include
0027 #endif
0028
0029 QT_BEGIN_NAMESPACE
0030 namespace QtMocHelpers {
0031
0032
0033 static constexpr size_t MaxStringSize =
0034 (std::min)(size_t((std::numeric_limits<uint>::max)()),
0035 size_t((std::numeric_limits<qsizetype>::max)()));
0036
0037 template <uint UCount, uint SCount, size_t SSize, uint MCount> struct MetaObjectContents
0038 {
0039 struct StaticContent {
0040 uint data[UCount];
0041 uint stringdata[SCount];
0042 char strings[SSize];
0043 } staticData = {};
0044 struct RelocatingContent {
0045 const QtPrivate::QMetaTypeInterface *metaTypes[MCount];
0046 } relocatingData = {};
0047 };
0048
0049 template <int Count, size_t StringSize> struct StringData
0050 {
0051 static_assert(StringSize <= MaxStringSize, "Meta Object data is too big");
0052 uint offsetsAndSizes[Count] = {};
0053 char stringdata0[StringSize] = {};
0054 constexpr StringData() = default;
0055 };
0056
0057 template <typename... Strings> struct StringRefStorage
0058 {
0059 static constexpr size_t stringSizeHelper() noexcept
0060 {
0061
0062
0063
0064 size_t total = 0;
0065 int sizes[] = { std::extent_v<Strings>... };
0066 for (int n : sizes)
0067 total += n;
0068 return size_t(total);
0069 }
0070
0071 static constexpr int StringCount = sizeof...(Strings);
0072 static constexpr size_t StringSize = stringSizeHelper();
0073 static_assert(StringSize <= MaxStringSize, "Meta Object data is too big");
0074 const char *inputs[StringCount];
0075
0076 constexpr StringRefStorage(const Strings &... strings) noexcept
0077 : inputs{ strings... }
0078 { }
0079
0080 constexpr void
0081 writeTo(uint (&offsets)[2 * StringCount], char (&data)[StringSize]) const noexcept
0082 {
0083 int sizes[] = { std::extent_v<Strings>... };
0084
0085 uint offset = 0;
0086 char *output = data;
0087 for (size_t i = 0; i < sizeof...(Strings); ++i) {
0088
0089 int len = sizes[i];
0090 for (int j = 0; j < len; ++j)
0091 output[offset + j] = inputs[i][j];
0092 offsets[2 * i] = offset + sizeof(offsets);
0093 offsets[2 * i + 1] = len - 1;
0094 offset += len;
0095 }
0096 }
0097
0098 constexpr auto create() const noexcept
0099 {
0100 StringData<2 * StringCount, StringSize> result;
0101 writeTo(result.offsetsAndSizes, result.stringdata0);
0102 return result;
0103 }
0104 };
0105
0106 template <uint... Nx> constexpr auto stringData(const char (&...strings)[Nx])
0107 {
0108 return StringRefStorage(strings...).create();
0109 }
0110
0111 template <typename FuncType> inline bool indexOfMethod(void **_a, FuncType f, int index) noexcept
0112 {
0113 int *result = static_cast<int *>(_a[0]);
0114 auto candidate = reinterpret_cast<FuncType *>(_a[1]);
0115 if (*candidate != f)
0116 return false;
0117 *result = index;
0118 return true;
0119 }
0120
0121 template <typename Prop, typename Value> inline bool setProperty(Prop &property, Value &&value)
0122 {
0123 if (property == value)
0124 return false;
0125 property = std::forward<Value>(value);
0126 return true;
0127 }
0128
0129 struct NoType {};
0130
0131 namespace detail {
0132 template<typename Enum> constexpr int payloadSizeForEnum()
0133 {
0134
0135
0136
0137
0138 int n = int(sizeof(Enum) + sizeof(uint)) - 1;
0139 return 1 + n / sizeof(uint);
0140 }
0141
0142 template <uint H, uint P> struct UintDataBlock
0143 {
0144 static constexpr uint headerSize() { return H; }
0145 static constexpr uint payloadSize() { return P; }
0146 uint header[H ? H : 1] = {};
0147 uint payload[P ? P : 1] = {};
0148 };
0149
0150
0151
0152
0153
0154
0155 enum TypeCompletenessForMetaType : bool {
0156 TypeMayBeIncomplete = false,
0157 TypeMustBeComplete = true,
0158 };
0159
0160 template <bool TypeMustBeComplete, typename... T> struct MetaTypeList
0161 {
0162 static constexpr int count() { return sizeof...(T); }
0163 template <typename Unique, typename Result> static constexpr void
0164 copyTo(Result &result, uint &metatypeoffset)
0165 {
0166 if constexpr (count()) {
0167 using namespace QtPrivate;
0168 using U = std::conditional_t<TypeMustBeComplete, void, Unique>;
0169 const QMetaTypeInterface *metaTypes[] = {
0170 qTryMetaTypeInterfaceForType<U, T>()...
0171 };
0172 for (const QMetaTypeInterface *mt : metaTypes)
0173 result.relocatingData.metaTypes[metatypeoffset++] = mt;
0174 }
0175 }
0176 };
0177
0178 template <int Idx, typename T> struct UintDataEntry
0179 {
0180 T entry;
0181 constexpr UintDataEntry(T &&entry_) : entry(std::move(entry_)) {}
0182 };
0183
0184
0185
0186
0187
0188
0189
0190
0191 template <typename Idx, typename... T> struct UintDataStorage;
0192 template <int... Idx, typename... T> struct UintDataStorage<std::integer_sequence<int, Idx...>, T...>
0193 : UintDataEntry<Idx, T>...
0194 {
0195 constexpr UintDataStorage(T &&... data)
0196 : UintDataEntry<Idx, T>(std::move(data))...
0197 {}
0198
0199 template <typename F> constexpr void forEach(F &&f) const
0200 {
0201 [[maybe_unused]] auto invoke = [&f](const auto &entry) { f(entry.entry); return 0; };
0202 int dummy[] = {
0203 0,
0204 invoke(static_cast<const UintDataEntry<Idx, T> &>(*this))...
0205 };
0206 (void) dummy;
0207 }
0208 };
0209 }
0210
0211 template <typename... Block> struct UintData
0212 {
0213 constexpr UintData(Block &&... data_)
0214 : data(std::move(data_)...)
0215 {}
0216
0217 static constexpr uint count() { return sizeof...(Block); }
0218 static constexpr uint headerSize()
0219 {
0220
0221
0222
0223
0224 int total = 0;
0225 int sizes[] = { 0, Block::headerSize()... };
0226 for (int n : sizes)
0227 total += n;
0228 return total;
0229 }
0230 static constexpr uint payloadSize()
0231 {
0232
0233 int total = 0;
0234 int sizes[] = { 0, Block::payloadSize()... };
0235 for (int n : sizes)
0236 total += n;
0237 return total;
0238 }
0239 static constexpr uint dataSize() { return headerSize() + payloadSize(); }
0240 static constexpr int metaTypeCount()
0241 {
0242
0243 int total = 0;
0244 int sizes[] = { 0, decltype(Block::metaTypes())::count()... };
0245 for (int n : sizes)
0246 total += n;
0247 return total;
0248 }
0249
0250 template <typename Unique, typename Result> constexpr void
0251 copyTo(Result &result, size_t dataoffset, uint &metatypeoffset) const
0252 {
0253 uint *ptr = result.staticData.data;
0254 size_t payloadoffset = dataoffset + headerSize();
0255 data.forEach([&](const auto &input) {
0256
0257 q20::copy_n(input.header, input.headerSize(), ptr + dataoffset);
0258 q20::copy_n(input.payload, input.payloadSize(), ptr + payloadoffset);
0259 input.adjustOffsets(ptr, uint(dataoffset), uint(payloadoffset), metatypeoffset);
0260
0261
0262 decltype(input.metaTypes())::template copyTo<Unique>(result, metatypeoffset);
0263
0264 dataoffset += input.headerSize();
0265 payloadoffset += input.payloadSize();
0266 });
0267 }
0268
0269 template <typename F> constexpr void forEach(F &&f) const
0270 {
0271 data.forEach(std::forward<F>(f));
0272 }
0273
0274 private:
0275 detail::UintDataStorage<std::make_integer_sequence<int, count()>, Block...> data;
0276 };
0277
0278 template <int N> struct ClassInfos : detail::UintDataBlock<2 * N, 0>
0279 {
0280 constexpr ClassInfos() = default;
0281 constexpr ClassInfos(const std::array<uint, 2> (&infos)[N])
0282 {
0283 uint *out = this->header;
0284 for (int i = 0; i < N; ++i) {
0285 *out++ = infos[i][0];
0286 *out++ = infos[i][1];
0287 }
0288 }
0289 };
0290
0291 template <typename PropertyType> struct PropertyData : detail::UintDataBlock<5, 0>
0292 {
0293 constexpr PropertyData(uint nameIndex, uint typeIndex, uint flags, uint notifyId = uint(-1), uint revision = 0)
0294 {
0295 this->header[0] = nameIndex;
0296 this->header[1] = typeIndex;
0297 this->header[2] = flags;
0298 this->header[3] = notifyId;
0299 this->header[4] = revision;
0300 }
0301
0302 static constexpr auto metaTypes()
0303 { return detail::MetaTypeList<detail::TypeMustBeComplete, PropertyType>{}; }
0304
0305 static constexpr void adjustOffsets(uint *, uint, uint, uint) noexcept {}
0306 };
0307
0308 template <typename Enum, int N = 0>
0309 struct EnumData : detail::UintDataBlock<5, N * detail::payloadSizeForEnum<Enum>()>
0310 {
0311 private:
0312 static_assert(sizeof(Enum) <= 2 * sizeof(uint), "Cannot store enumeration of this size");
0313 template <typename T> struct RealEnum { using Type = T; };
0314 template <typename T> struct RealEnum<QFlags<T>> { using Type = T; };
0315 public:
0316 struct EnumEntry {
0317 int nameIndex;
0318 typename RealEnum<Enum>::Type value;
0319 };
0320
0321 constexpr EnumData(uint nameOffset, uint aliasOffset, uint flags)
0322 {
0323 this->header[0] = nameOffset;
0324 this->header[1] = aliasOffset;
0325 this->header[2] = flags;
0326 this->header[3] = N;
0327 this->header[4] = 0;
0328
0329 if (nameOffset != aliasOffset || QtPrivate::IsQFlags<Enum>::value)
0330 this->header[2] |= QtMocConstants::EnumIsFlag;
0331 if constexpr (q23::is_scoped_enum_v<Enum>)
0332 this->header[2] |= QtMocConstants::EnumIsScoped;
0333 }
0334
0335 template <int Added> constexpr auto add(const EnumEntry (&entries)[Added]) const
0336 {
0337 EnumData<Enum, N + Added> result(this->header[0], this->header[1], this->header[2]);
0338
0339 q20::copy_n(this->payload, this->payloadSize(), result.payload);
0340 uint o = this->payloadSize();
0341 for (auto entry : entries) {
0342 result.payload[o++] = uint(entry.nameIndex);
0343 auto value = qToUnderlying(entry.value);
0344 result.payload[o++] = uint(value);
0345 }
0346
0347 if constexpr (sizeof(Enum) > sizeof(uint)) {
0348 static_assert(N == 0, "Unimplemented: merging with non-empty EnumData");
0349 result.header[2] |= QtMocConstants::EnumIs64Bit;
0350 for (auto entry : entries) {
0351 auto value = qToUnderlying(entry.value);
0352 result.payload[o++] = uint(value >> 32);
0353 }
0354 }
0355 return result;
0356 }
0357
0358 static constexpr auto metaTypes()
0359 { return detail::MetaTypeList<detail::TypeMustBeComplete, Enum>{}; }
0360
0361 static constexpr void
0362 adjustOffsets(uint *ptr, uint dataoffset, uint payloadoffset, uint metatypeoffset) noexcept
0363 {
0364 ptr[dataoffset + 4] += uint(payloadoffset);
0365 (void) metatypeoffset;
0366 }
0367 };
0368
0369 template <typename F, uint ExtraFlags> struct FunctionData;
0370 template <typename Ret, typename... Args, uint ExtraFlags>
0371 struct FunctionData<Ret (Args...), ExtraFlags>
0372 : detail::UintDataBlock<6, 2 * sizeof...(Args) + 1 + (ExtraFlags & QtMocConstants::MethodRevisioned ? 1 : 0)>
0373 {
0374 static constexpr bool IsRevisioned = (ExtraFlags & QtMocConstants::MethodRevisioned) != 0;
0375 struct FunctionParameter {
0376 uint typeIdx;
0377 uint nameIdx;
0378 };
0379 using ParametersArray = std::array<FunctionParameter, sizeof...(Args)>;
0380
0381 static auto metaTypes()
0382 {
0383 using namespace QtMocConstants;
0384 if constexpr (std::is_same_v<Ret, NoType>) {
0385
0386 static_assert((ExtraFlags & MethodConstructor) == MethodConstructor,
0387 "NoType return type used on a non-constructor");
0388 static_assert((ExtraFlags & MethodIsConst) == 0,
0389 "Constructors cannot be const");
0390 return detail::MetaTypeList<detail::TypeMayBeIncomplete, Args...>{};
0391 } else {
0392 static_assert((ExtraFlags & MethodConstructor) != MethodConstructor,
0393 "Constructors must use NoType as return type");
0394 return detail::MetaTypeList<detail::TypeMayBeIncomplete, Ret, Args...>{};
0395 }
0396 }
0397
0398 static constexpr void
0399 adjustOffsets(uint *ptr, uint dataoffset, uint payloadoffset, uint metatypeoffset) noexcept
0400 {
0401 if constexpr (IsRevisioned)
0402 ++payloadoffset;
0403 ptr[dataoffset + 2] += uint(payloadoffset);
0404 ptr[dataoffset + 5] = metatypeoffset;
0405 }
0406
0407 constexpr
0408 FunctionData(uint nameIndex, uint tagIndex, uint flags,
0409 uint returnType, ParametersArray params = {})
0410 {
0411 this->header[0] = nameIndex;
0412 this->header[1] = sizeof...(Args);
0413 this->header[2] = 0;
0414 this->header[3] = tagIndex;
0415 this->header[4] = flags | ExtraFlags;
0416 this->header[5] = 0;
0417
0418 uint *p = this->payload;
0419 if constexpr (ExtraFlags & QtMocConstants::MethodRevisioned)
0420 ++p;
0421 *p++ = returnType;
0422 if constexpr (sizeof...(Args)) {
0423 for (uint i = 0; i < sizeof...(Args); ++i)
0424 *p++ = params[i].typeIdx;
0425 for (uint i = 0; i < sizeof...(Args); ++i)
0426 *p++ = params[i].nameIdx;
0427 } else {
0428 Q_UNUSED(params);
0429 }
0430 }
0431
0432 constexpr
0433 FunctionData(uint nameIndex, uint tagIndex, uint flags, uint revision,
0434 uint returnType, ParametersArray params = {})
0435 #ifdef __cpp_concepts
0436 requires(IsRevisioned)
0437 #endif
0438 : FunctionData(nameIndex, tagIndex, flags, returnType, params)
0439 {
0440
0441 this->payload[0] = revision;
0442 }
0443 };
0444
0445 template <typename Ret, typename... Args, uint ExtraFlags>
0446 struct FunctionData<Ret (Args...) const, ExtraFlags>
0447 : FunctionData<Ret (Args...), ExtraFlags | QtMocConstants::MethodIsConst>
0448 {
0449 using FunctionData<Ret (Args...), ExtraFlags | QtMocConstants::MethodIsConst>::FunctionData;
0450 };
0451
0452 template <typename F> struct MethodData : FunctionData<F, QtMocConstants::MethodMethod>
0453 {
0454 using FunctionData<F, QtMocConstants::MethodMethod>::FunctionData;
0455 };
0456
0457 template <typename F> struct SignalData : FunctionData<F, QtMocConstants::MethodSignal>
0458 {
0459 using FunctionData<F, QtMocConstants::MethodSignal>::FunctionData;
0460 };
0461
0462 template <typename F> struct SlotData : FunctionData<F, QtMocConstants::MethodSlot>
0463 {
0464 using FunctionData<F, QtMocConstants::MethodSlot>::FunctionData;
0465 };
0466
0467 template <typename F> struct ConstructorData : FunctionData<F, QtMocConstants::MethodConstructor>
0468 {
0469 using Base = FunctionData<F, QtMocConstants::MethodConstructor>;
0470
0471
0472
0473 constexpr ConstructorData(uint tagIndex, uint flags, typename Base::ParametersArray params = {})
0474 : Base(0, tagIndex, flags, QMetaType::UnknownType, params)
0475 {}
0476 };
0477
0478 template <typename F> struct RevisionedMethodData :
0479 FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodMethod>
0480 {
0481 using FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodMethod>::FunctionData;
0482 };
0483
0484 template <typename F> struct RevisionedSignalData :
0485 FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodSignal>
0486 {
0487 using FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodSignal>::FunctionData;
0488 };
0489
0490 template <typename F> struct RevisionedSlotData :
0491 FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodSlot>
0492 {
0493 using FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodSlot>::FunctionData;
0494 };
0495
0496 template <typename F> struct RevisionedConstructorData :
0497 FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodConstructor>
0498 {
0499 using Base = FunctionData<F, QtMocConstants::MethodRevisioned | QtMocConstants::MethodConstructor>;
0500
0501
0502
0503 constexpr RevisionedConstructorData(uint tagIndex, uint flags, uint revision,
0504 typename Base::ParametersArray params = {})
0505 : Base(0, tagIndex, flags, revision, QMetaType::UnknownType, params)
0506 {}
0507 };
0508
0509 template <typename ObjectType, typename Unique, typename Strings,
0510 typename Methods, typename Properties, typename Enums,
0511 typename Constructors = UintData<>, typename ClassInfo = detail::UintDataBlock<0, 0>>
0512 constexpr auto metaObjectData(uint flags, const Strings &strings,
0513 const Methods &methods, const Properties &properties,
0514 const Enums &enums, const Constructors &constructors = {},
0515 const ClassInfo &classInfo = {})
0516 {
0517 constexpr uint MetaTypeCount = Properties::metaTypeCount()
0518 + Enums::metaTypeCount()
0519 + 1
0520 + Methods::metaTypeCount()
0521 + Constructors::metaTypeCount();
0522
0523 constexpr uint HeaderSize = 14;
0524 constexpr uint TotalSize = HeaderSize
0525 + Properties::dataSize()
0526 + Enums::dataSize()
0527 + Methods::dataSize()
0528 + Constructors::dataSize()
0529 + ClassInfo::headerSize()
0530 + 1;
0531
0532 MetaObjectContents<TotalSize, 2 * Strings::StringCount, Strings::StringSize,
0533 MetaTypeCount> result = {};
0534 strings.writeTo(result.staticData.stringdata, result.staticData.strings);
0535
0536 uint dataoffset = HeaderSize;
0537 uint metatypeoffset = 0;
0538 uint *data = result.staticData.data;
0539
0540 data[0] = QtMocConstants::OutputRevision;
0541 data[1] = 0;
0542
0543 data[2] = ClassInfo::headerSize() / 2;
0544 data[3] = ClassInfo::headerSize() ? dataoffset : 0;
0545 q20::copy_n(classInfo.header, classInfo.headerSize(), data + dataoffset);
0546 dataoffset += ClassInfo::headerSize();
0547
0548 data[6] = properties.count();
0549 data[7] = properties.count() ? dataoffset : 0;
0550 properties.template copyTo<Unique>(result, dataoffset, metatypeoffset);
0551 dataoffset += properties.dataSize();
0552
0553 data[8] = enums.count();
0554 data[9] = enums.count() ? dataoffset : 0;
0555 enums.template copyTo<Unique>(result, dataoffset, metatypeoffset);
0556 dataoffset += enums.dataSize();
0557
0558
0559 result.relocatingData.metaTypes[metatypeoffset++] = QMetaType::fromType<ObjectType>().iface();
0560
0561 data[4] = methods.count();
0562 data[5] = methods.count() ? dataoffset : 0;
0563 methods.template copyTo<Unique>(result, dataoffset, metatypeoffset);
0564 dataoffset += methods.dataSize();
0565
0566 data[10] = constructors.count();
0567 data[11] = constructors.count() ? dataoffset : 0;
0568 constructors.template copyTo<Unique>(result, dataoffset, metatypeoffset);
0569 dataoffset += constructors.dataSize();
0570
0571 data[12] = flags;
0572
0573
0574 if constexpr (Methods::count()) {
0575 constexpr uint MethodHeaderSize = Methods::headerSize() / Methods::count();
0576 const uint *ptr = &data[data[5]];
0577 const uint *end = &data[data[5] + MethodHeaderSize * Methods::count()];
0578 for ( ; ptr < end; ptr += MethodHeaderSize) {
0579 if ((ptr[4] & QtMocConstants::MethodSignal) == 0)
0580 break;
0581 ++data[13];
0582 }
0583 }
0584
0585 return result;
0586 }
0587
0588 template <typename T> inline std::enable_if_t<std::is_enum_v<T>> assignFlags(void *v, T t) noexcept
0589 {
0590 *static_cast<T *>(v) = t;
0591 }
0592
0593 template <typename T> inline std::enable_if_t<QtPrivate::IsQFlags<T>::value> assignFlags(void *v, T t) noexcept
0594 {
0595 *static_cast<T *>(v) = t;
0596 }
0597
0598 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0599 template <typename T>
0600 Q_DECL_DEPRECATED_X("Returning int/uint from a Q_PROPERTY that is a Q_FLAG is deprecated; "
0601 "please update to return the actual property's type")
0602 inline void assignFlagsFromInteger(QFlags<T> &f, int i) noexcept
0603 {
0604 f = QFlag(i);
0605 }
0606
0607 template <typename T, typename I>
0608 inline std::enable_if_t<QtPrivate::IsQFlags<T>::value && sizeof(T) == sizeof(int) && std::is_integral_v<I>>
0609 assignFlags(void *v, I i) noexcept
0610 {
0611 assignFlagsFromInteger(*static_cast<T *>(v), i);
0612 }
0613 #endif
0614
0615 }
0616 QT_END_NAMESPACE
0617
0618 QT_USE_NAMESPACE
0619
0620 #endif