File indexing completed on 2024-12-29 04:49:56
0001 /* 0002 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "internal/instance_counter.h" 0010 #include "internal/parameter_type.h" 0011 #include "internal/strict_equal.h" 0012 #include "internal/strict_less.h" 0013 0014 namespace KItinerary { 0015 0016 ///@cond internal 0017 namespace detail { 0018 0019 // SFINAE helper to determine if we have a polymorphic or a simple value type 0020 template <typename T> 0021 struct base_type { 0022 template <typename U> static typename U::super_type test(typename U::super_type*); 0023 template <typename U> static T test(...); 0024 using type = decltype(test<T>(nullptr)); 0025 static constexpr const bool is_valid = !std::is_same<type, T>::value; 0026 }; 0027 } 0028 0029 #define KITINERARY_MAKE_CLASS_IMPL(Class) \ 0030 Q_GLOBAL_STATIC_WITH_ARGS(QExplicitlySharedDataPointer<Class ## Private>, s_ ## Class ## _shared_null, (new Class ## Private)) \ 0031 Class::Class() : Class(s_ ## Class ## _shared_null()->data()) {} \ 0032 Class::Class(const Class&) = default; \ 0033 Class::~Class() = default; \ 0034 Class& Class::operator=(const Class &other) { d = other.d; return *this; } \ 0035 QString Class::className() const { return QStringLiteral(#Class); } \ 0036 Class::operator QVariant() const { return QVariant::fromValue(*this); } \ 0037 const char* Class::typeName() { return #Class; } \ 0038 static_assert(sizeof(Class) == sizeof(void*), "dptr must be the only member!"); \ 0039 namespace detail { \ 0040 static constexpr int property_counter(KItinerary::detail::num<0>, KItinerary::detail::tag<Class>) \ 0041 { return 1; } \ 0042 static constexpr bool property_equals(KItinerary::detail::num<0>, KItinerary::detail::tag<Class ## Private>, const Class ## Private *, const Class ## Private *) \ 0043 { return true; } \ 0044 static constexpr bool property_less(KItinerary::detail::num<0>, KItinerary::detail::tag<Class ## Private>, const Class ## Private *, const Class ## Private *) \ 0045 { return true; } \ 0046 } 0047 ///@endcond 0048 0049 /** Macro to generate the value type and introspection implementation for a vocabulary type. 0050 * This provides the implementation of KITINERARY_GADGET. 0051 */ 0052 #define KITINERARY_MAKE_CLASS(Class) \ 0053 KITINERARY_MAKE_CLASS_IMPL(Class) \ 0054 Class::Class(Class ## Private *dd) : d(dd) {} 0055 0056 /** Macro to generate the value type and introspection implementation for a derived vocabulary type. 0057 * This provides the implementation of KITINERARY_GADGET. 0058 */ 0059 #define KITINERARY_MAKE_DERIVED_CLASS(Class, Base) \ 0060 KITINERARY_MAKE_CLASS_IMPL(Class) \ 0061 Class::Class(Class ## Private *dd) : Base(dd) {} 0062 0063 /** Macros to generate operator implementation details for a property. 0064 * This is not needed when using KITINERARY_MAKE_PROPERTY, but only when 0065 * implementing getters/setters manually. 0066 */ 0067 #define KITINERARY_MAKE_PROPERTY_OPERATOR(Class, Type, Name) \ 0068 namespace detail { \ 0069 static constexpr int property_counter(KItinerary::detail::num<property_counter(KItinerary::detail::num<>(), KItinerary::detail::tag<Class>())> n, KItinerary::detail::tag<Class>) \ 0070 { return decltype(n)::value + 1; } \ 0071 static inline bool property_equals(KItinerary::detail::num<property_counter(KItinerary::detail::num<>(), KItinerary::detail::tag<Class>())> n, KItinerary::detail::tag<Class ## Private>, const Class ## Private *lhs, const Class ## Private *rhs) \ 0072 { \ 0073 if (KItinerary::detail::strict_equal<Type>(lhs->Name, rhs->Name)) { \ 0074 return property_equals(n.prev(), KItinerary::detail::tag<Class ## Private>(), lhs, rhs); \ 0075 } \ 0076 return false; \ 0077 } \ 0078 static inline bool property_less(KItinerary::detail::num<property_counter(KItinerary::detail::num<>(), KItinerary::detail::tag<Class>())> n, KItinerary::detail::tag<Class ## Private>, const Class ## Private *lhs, const Class ## Private *rhs) \ 0079 { \ 0080 if (KItinerary::detail::strict_less<Type>(lhs->Name, rhs->Name)) { return true; } \ 0081 if (KItinerary::detail::strict_equal<Type>(lhs->Name, rhs->Name)) { \ 0082 return property_less(n.prev(), KItinerary::detail::tag<Class ## Private>(), lhs, rhs); \ 0083 } \ 0084 return false; \ 0085 } \ 0086 } 0087 0088 /** Macro to generate the implementation of a vocabulary property type. 0089 * This generates the definitions for the declaration the KITINERARY_PROPERTY macro 0090 * produces, as well as implementation details needed for the automatic comparison 0091 * operator. 0092 * @see KITINERARY_MAKE_OPERATOR 0093 */ 0094 #define KITINERARY_MAKE_PROPERTY(Class, Type, Name, SetName) \ 0095 Type Class::Name() const { return static_cast<const Class ## Private*>(d.data())->Name; } \ 0096 void Class::SetName(KItinerary::detail::parameter_type<Type>::type value) { \ 0097 if (KItinerary::detail::strict_equal<Type>(static_cast<Class ## Private*>(d.data())->Name, value)) { return; } \ 0098 d.detach(); \ 0099 static_cast<Class ## Private*>(d.data())->Name = value; \ 0100 } \ 0101 KITINERARY_MAKE_PROPERTY_OPERATOR(Class, Type, Name) 0102 0103 /** Generates the implementation of the comparison operator for vocabulary type @p Class. 0104 * The generated operator==() implementation will check all properties for strict equality, 0105 * as well as call operator==() of a base class if present. 0106 * This relies on KITINERARY_MAKE_PROPERTY to generate supporting code and thus has to be 0107 * called after all properties have been generated. 0108 */ 0109 #define KITINERARY_MAKE_OPERATOR(Class) \ 0110 namespace detail { \ 0111 static inline bool recursive_less(KItinerary::detail::tag<Class ## Private>, const Class ## Private *lhs, const Class ## Private *rhs) { \ 0112 if constexpr (KItinerary::detail::base_type<Class ## Private>::is_valid) { \ 0113 if (detail::property_equals(KItinerary::detail::num<>(), KItinerary::detail::tag<Class ## Private>(), lhs, rhs)) { \ 0114 typedef typename KItinerary::detail::base_type<Class ## Private>::type super_type; \ 0115 if (detail::property_less(KItinerary::detail::num<>(), KItinerary::detail::tag<super_type>(), static_cast<const super_type*>(lhs), static_cast<const super_type*>(rhs))) { return true; } \ 0116 return recursive_less(KItinerary::detail::tag<super_type>(), static_cast<const super_type*>(lhs), static_cast<const super_type*>(rhs)); \ 0117 } \ 0118 } \ 0119 return false; \ 0120 } \ 0121 static inline bool recursive_equal(KItinerary::detail::tag<Class ## Private>, const Class ## Private *lhs, const Class ## Private *rhs) { \ 0122 if constexpr (KItinerary::detail::base_type<Class ## Private>::is_valid) { \ 0123 typedef typename KItinerary::detail::base_type<Class ## Private>::type super_type; \ 0124 if (!detail::property_equals(KItinerary::detail::num<>(), KItinerary::detail::tag<super_type>(), static_cast<const super_type*>(lhs), static_cast<const super_type*>(rhs))) { return false; } \ 0125 return recursive_equal(KItinerary::detail::tag<super_type>(), static_cast<const super_type*>(lhs), static_cast<const super_type*>(rhs)); \ 0126 } \ 0127 return true; \ 0128 } \ 0129 } \ 0130 bool Class::operator<(const Class &other) const { \ 0131 static_assert(detail::property_counter(KItinerary::detail::num<0>(), KItinerary::detail::tag<Class>()) == 1, "silence unused function warnings"); \ 0132 typedef Class ## Private this_type; \ 0133 const auto lhs = static_cast<const this_type *>(d.data()); \ 0134 const auto rhs = static_cast<const this_type*>(other.d.data()); \ 0135 if (lhs == rhs) { \ 0136 return false; \ 0137 } \ 0138 if (detail::property_less(KItinerary::detail::num<>(), KItinerary::detail::tag<this_type>(), lhs, rhs)) { \ 0139 return true; \ 0140 } \ 0141 return detail::recursive_less(KItinerary::detail::tag<this_type>(), lhs, rhs); \ 0142 } \ 0143 bool Class::operator==(const Class &other) const \ 0144 { \ 0145 static_assert(detail::property_counter(KItinerary::detail::num<0>(), KItinerary::detail::tag<Class>()) == 1, "silence unused function warnings"); \ 0146 typedef Class ## Private this_type; \ 0147 const auto lhs = static_cast<const this_type *>(d.data()); \ 0148 const auto rhs = static_cast<const this_type*>(other.d.data()); \ 0149 if (lhs == rhs) { \ 0150 return true; \ 0151 } \ 0152 if (!detail::property_equals(KItinerary::detail::num<>(), KItinerary::detail::tag<this_type>(), lhs, rhs)) { \ 0153 return false; \ 0154 } \ 0155 return detail::recursive_equal(KItinerary::detail::tag<this_type>(), lhs, rhs); \ 0156 } 0157 0158 }