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 }