Member functions of mixins should be defined out of line

Per [temp.explicit]/10, explicit instantiation declarations
do not affect inline member functions
This commit is contained in:
Mat Sutcliffe
2021-10-07 23:57:57 +01:00
parent 5a1f3e8dd1
commit 9fdeb466fa
12 changed files with 679 additions and 387 deletions

View File

@@ -36,6 +36,12 @@ namespace BlackMisc
}; };
//! \endcond //! \endcond
/*!
* True if T has a member typedef base_type which is a registered metatype.
*/
template <typename T>
inline constexpr bool THasMetaBaseV = QMetaTypeId<typename TBaseOf<T>::type>::Defined;
/*! /*!
* It T has a member typedef base_type which is a registered metatype, this trait will obtain it, otherwise void. * It T has a member typedef base_type which is a registered metatype, this trait will obtain it, otherwise void.
*/ */
@@ -43,7 +49,7 @@ namespace BlackMisc
struct TMetaBaseOf struct TMetaBaseOf
{ {
//! Type of T::base_type, or void if not declared. //! Type of T::base_type, or void if not declared.
using type = std::conditional_t<QMetaTypeId<typename TBaseOf<T>::type>::Defined, typename TBaseOf<T>::type, void>; using type = std::conditional_t<THasMetaBaseV<T>, typename TBaseOf<T>::type, void>;
}; };
/*! /*!

View File

@@ -56,7 +56,16 @@ namespace BlackMisc
friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); } friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); }
private: private:
static bool equals(const Derived &a, const Derived &b) static bool equals(const Derived &a, const Derived &b);
template <typename T> static bool baseEquals(const T *a, const T *b);
static bool baseEquals(const void *, const void *);
static bool baseEquals(const CEmpty *, const CEmpty *);
template <typename T, typename Flags>
static bool membersEqual(const T &a, const T &b, Flags);
};
template <class Derived>
bool EqualsByMetaClass<Derived>::equals(const Derived &a, const Derived &b)
{ {
bool result = baseEquals(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b)); bool result = baseEquals(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
introspect<Derived>().forEachMember([ & ](auto member) introspect<Derived>().forEachMember([ & ](auto member)
@@ -68,17 +77,24 @@ namespace BlackMisc
}); });
return result; return result;
} }
template <typename T> static bool baseEquals(const T *a, const T *b) { return *a == *b; }
static bool baseEquals(const void *, const void *) { return true; }
static bool baseEquals(const CEmpty *, const CEmpty *) { return true; }
template <class Derived>
template <typename T>
bool EqualsByMetaClass<Derived>::baseEquals(const T *a, const T *b) { return *a == *b; }
template <class Derived>
bool EqualsByMetaClass<Derived>::baseEquals(const void *, const void *) { return true; }
template <class Derived>
bool EqualsByMetaClass<Derived>::baseEquals(const CEmpty *, const CEmpty *) { return true; }
template <class Derived>
template <typename T, typename Flags> template <typename T, typename Flags>
static bool membersEqual(const T &a, const T &b, Flags) bool EqualsByMetaClass<Derived>::membersEqual(const T &a, const T &b, Flags)
{ {
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive) == 0; } if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive) == 0; }
else { return a == b; } else { return a == b; }
} }
};
/*! /*!
* CRTP class template from which a derived class can inherit operator< implemented using its compare function. * CRTP class template from which a derived class can inherit operator< implemented using its compare function.
@@ -122,7 +138,16 @@ namespace BlackMisc
friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); } friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); }
private: private:
static bool less(const Derived &a, const Derived &b) static bool less(const Derived &a, const Derived &b);
template <typename T> static bool baseLess(const T *a, const T *b);
static bool baseLess(const void *, const void *);
static bool baseLess(const CEmpty *, const CEmpty *);
template <typename T, typename Flags>
static bool membersLess(bool &io_greaterThan, const T &a, const T &b, Flags);
};
template <class Derived>
bool LessThanByMetaClass<Derived>::less(const Derived &a, const Derived &b)
{ {
bool result = baseLess(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b)); bool result = baseLess(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
bool gt = baseLess(static_cast<const TBaseOfT<Derived> *>(&b), static_cast<const TBaseOfT<Derived> *>(&a)); bool gt = baseLess(static_cast<const TBaseOfT<Derived> *>(&b), static_cast<const TBaseOfT<Derived> *>(&a));
@@ -135,12 +160,20 @@ namespace BlackMisc
}); });
return result; return result;
} }
template <typename T> static bool baseLess(const T *a, const T *b) { return *a < *b; }
static bool baseLess(const void *, const void *) { return false; }
static bool baseLess(const CEmpty *, const CEmpty *) { return false; }
template <class Derived>
template <typename T>
bool LessThanByMetaClass<Derived>::baseLess(const T *a, const T *b) { return *a < *b; }
template <class Derived>
bool LessThanByMetaClass<Derived>::baseLess(const void *, const void *) { return false; }
template <class Derived>
bool LessThanByMetaClass<Derived>::baseLess(const CEmpty *, const CEmpty *) { return false; }
template <class Derived>
template <typename T, typename Flags> template <typename T, typename Flags>
static bool membersLess(bool &io_greaterThan, const T &a, const T &b, Flags) bool LessThanByMetaClass<Derived>::membersLess(bool &io_greaterThan, const T &a, const T &b, Flags)
{ {
if (io_greaterThan) { return false; } if (io_greaterThan) { return false; }
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison))
@@ -150,7 +183,6 @@ namespace BlackMisc
} }
else { io_greaterThan = b < a; return a < b; } else { io_greaterThan = b < a; return a < b; }
} }
};
/*! /*!
* CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass. * CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass.
@@ -163,7 +195,16 @@ namespace BlackMisc
friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); } friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); }
private: private:
static int compareImpl(const Derived &a, const Derived &b) static int compareImpl(const Derived &a, const Derived &b);
template <typename T> static int baseCompare(const T *a, const T *b);
static int baseCompare(const void *, const void *);
static int baseCompare(const CEmpty *, const CEmpty *);
template <typename T, typename Flags>
static int membersCompare(const T &a, const T &b, Flags);
};
template <class Derived>
int CompareByMetaClass<Derived>::compareImpl(const Derived &a, const Derived &b)
{ {
int result = baseCompare(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b)); int result = baseCompare(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
introspect<Derived>().forEachMember([ & ](auto member) introspect<Derived>().forEachMember([ & ](auto member)
@@ -175,18 +216,25 @@ namespace BlackMisc
}); });
return result; return result;
} }
template <typename T> static int baseCompare(const T *a, const T *b) { return compare(*a, *b); }
static int baseCompare(const void *, const void *) { return 0; }
static int baseCompare(const CEmpty *, const CEmpty *) { return 0; }
template <class Derived>
template <typename T>
int CompareByMetaClass<Derived>::baseCompare(const T *a, const T *b) { return compare(*a, *b); }
template <class Derived>
int CompareByMetaClass<Derived>::baseCompare(const void *, const void *) { return 0; }
template <class Derived>
int CompareByMetaClass<Derived>::baseCompare(const CEmpty *, const CEmpty *) { return 0; }
template <class Derived>
template <typename T, typename Flags> template <typename T, typename Flags>
static int membersCompare(const T &a, const T &b, Flags) int CompareByMetaClass<Derived>::membersCompare(const T &a, const T &b, Flags)
{ {
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive); } if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive); }
else if constexpr (THasCompare<T, T>::value) { return compare(a, b); } else if constexpr (THasCompare<T, T>::value) { return compare(a, b); }
else { return a < b ? -1 : b < a ? 1 : 0; } else { return a < b ? -1 : b < a ? 1 : 0; }
} }
};
} // Mixin } // Mixin
} // BlackMisc } // BlackMisc

View File

@@ -55,7 +55,25 @@ namespace BlackMisc
{ {
public: public:
//! Marshal a value to a QDataStream. //! Marshal a value to a QDataStream.
void marshalToDataStream(QDataStream &stream) const void marshalToDataStream(QDataStream &stream) const;
//! Unmarshal a value from a QDataStream.
void unmarshalFromDataStream(QDataStream &stream);
private:
const Derived *derived() const;
Derived *derived();
template <typename T> static void baseMarshal(const T *base, QDataStream &stream);
template <typename T> static void baseUnmarshal(T *base, QDataStream &stream);
static void baseMarshal(const void *, QDataStream &);
static void baseUnmarshal(void *, QDataStream &);
static void baseMarshal(const CEmpty *, QDataStream &);
static void baseUnmarshal(CEmpty *, QDataStream &);
};
template <class Derived>
void DataStreamByMetaClass<Derived>::marshalToDataStream(QDataStream &stream) const
{ {
baseMarshal(static_cast<const TBaseOfT<Derived> *>(derived()), stream); baseMarshal(static_cast<const TBaseOfT<Derived> *>(derived()), stream);
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -67,8 +85,8 @@ namespace BlackMisc
}); });
} }
//! Unmarshal a value from a QDataStream. template <class Derived>
void unmarshalFromDataStream(QDataStream &stream) void DataStreamByMetaClass<Derived>::unmarshalFromDataStream(QDataStream &stream)
{ {
baseUnmarshal(static_cast<TBaseOfT<Derived> *>(derived()), stream); baseUnmarshal(static_cast<TBaseOfT<Derived> *>(derived()), stream);
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -80,17 +98,31 @@ namespace BlackMisc
}); });
} }
private: template <class Derived>
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *DataStreamByMetaClass<Derived>::derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static void baseMarshal(const T *base, QDataStream &stream) { base->marshalToDataStream(stream); } template <class Derived>
template <typename T> static void baseUnmarshal(T *base, QDataStream &stream) { base->unmarshalFromDataStream(stream); } Derived *DataStreamByMetaClass<Derived>::derived() { return static_cast<Derived *>(this); }
static void baseMarshal(const void *, QDataStream &) {}
static void baseUnmarshal(void *, QDataStream &) {} template <class Derived>
static void baseMarshal(const CEmpty *, QDataStream &) {} template <typename T>
static void baseUnmarshal(CEmpty *, QDataStream &) {} void DataStreamByMetaClass<Derived>::baseMarshal(const T *base, QDataStream &stream) { base->marshalToDataStream(stream); }
};
template <class Derived>
template <typename T>
void DataStreamByMetaClass<Derived>::baseUnmarshal(T *base, QDataStream &stream) { base->unmarshalFromDataStream(stream); }
template <class Derived>
void DataStreamByMetaClass<Derived>::baseMarshal(const void *, QDataStream &) {}
template <class Derived>
void DataStreamByMetaClass<Derived>::baseUnmarshal(void *, QDataStream &) {}
template <class Derived>
void DataStreamByMetaClass<Derived>::baseMarshal(const CEmpty *, QDataStream &) {}
template <class Derived>
void DataStreamByMetaClass<Derived>::baseUnmarshal(CEmpty *, QDataStream &) {}
/*! /*!
* When a derived class and a base class both inherit from Mixin::DataStreamByMetaClass, * When a derived class and a base class both inherit from Mixin::DataStreamByMetaClass,

View File

@@ -68,7 +68,25 @@ namespace BlackMisc
{ {
public: public:
//! Marshall without begin/endStructure, for when composed within another object //! Marshall without begin/endStructure, for when composed within another object
void marshallToDbus(QDBusArgument &arg, Tags...) const void marshallToDbus(QDBusArgument &arg, Tags...) const;
//! Unmarshall without begin/endStructure, for when composed within another object
void unmarshallFromDbus(const QDBusArgument &arg, Tags...);
private:
const Derived *derived() const;
Derived *derived();
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg);
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg);
static void baseMarshall(const void *, QDBusArgument &);
static void baseUnmarshall(void *, const QDBusArgument &);
static void baseMarshall(const CEmpty *, QDBusArgument &);
static void baseUnmarshall(CEmpty *, const QDBusArgument &);
};
template <class Derived, class... Tags>
void DBusByMetaClass<Derived, Tags...>::marshallToDbus(QDBusArgument &arg, Tags...) const
{ {
baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg); baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg);
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -89,8 +107,8 @@ namespace BlackMisc
}); });
} }
//! Unmarshall without begin/endStructure, for when composed within another object template <class Derived, class... Tags>
void unmarshallFromDbus(const QDBusArgument &arg, Tags...) void DBusByMetaClass<Derived, Tags...>::unmarshallFromDbus(const QDBusArgument &arg, Tags...)
{ {
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg); baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -111,17 +129,31 @@ namespace BlackMisc
}); });
} }
private: template <class Derived, class... Tags>
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *DBusByMetaClass<Derived, Tags...>::derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg, Tags()...); } template <class Derived, class... Tags>
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg, Tags()...); } Derived *DBusByMetaClass<Derived, Tags...>::derived() { return static_cast<Derived *>(this); }
static void baseMarshall(const void *, QDBusArgument &) {}
static void baseUnmarshall(void *, const QDBusArgument &) {} template <class Derived, class... Tags>
static void baseMarshall(const CEmpty *, QDBusArgument &) {} template <typename T>
static void baseUnmarshall(CEmpty *, const QDBusArgument &) {} void DBusByMetaClass<Derived, Tags...>::baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg, Tags()...); }
};
template <class Derived, class... Tags>
template <typename T>
void DBusByMetaClass<Derived, Tags...>::baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg, Tags()...); }
template <class Derived, class... Tags>
void DBusByMetaClass<Derived, Tags...>::baseMarshall(const void *, QDBusArgument &) {}
template <class Derived, class... Tags>
void DBusByMetaClass<Derived, Tags...>::baseUnmarshall(void *, const QDBusArgument &) {}
template <class Derived, class... Tags>
void DBusByMetaClass<Derived, Tags...>::baseMarshall(const CEmpty *, QDBusArgument &) {}
template <class Derived, class... Tags>
void DBusByMetaClass<Derived, Tags...>::baseUnmarshall(CEmpty *, const QDBusArgument &) {}
// *INDENT-OFF* // *INDENT-OFF*
/*! /*!

View File

@@ -57,7 +57,15 @@ namespace BlackMisc
} }
private: private:
static uint hashImpl(const Derived &value) static uint hashImpl(const Derived &value);
template <typename T> static uint baseHash(const T *base) { return qHash(*base); }
static uint baseHash(const void *);
static uint baseHash(const CEmpty *);
};
template <class Derived>
uint HashByMetaClass<Derived>::hashImpl(const Derived &value)
{ {
uint hash = baseHash(static_cast<const TBaseOfT<Derived> *>(&value)); uint hash = baseHash(static_cast<const TBaseOfT<Derived> *>(&value));
introspect<Derived>().forEachMember([ & ](auto member) introspect<Derived>().forEachMember([ & ](auto member)
@@ -70,10 +78,11 @@ namespace BlackMisc
return hash; return hash;
} }
template <typename T> static uint baseHash(const T *base) { return qHash(*base); } template <class Derived>
static uint baseHash(const void *) { return 0; } uint HashByMetaClass<Derived>::baseHash(const void *) { return 0; }
static uint baseHash(const CEmpty *) { return 0; }
}; template <class Derived>
uint HashByMetaClass<Derived>::baseHash(const CEmpty *) { return 0; }
} }
} // namespace BlackMisc } // namespace BlackMisc

View File

@@ -31,13 +31,22 @@ namespace BlackMisc
{ {
public: public:
//! As icon, not implemented by all classes //! As icon, not implemented by all classes
CIcons::IconIndex toIcon() const { return IconIndex; } CIcons::IconIndex toIcon() const;
private: private:
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *derived() const;
Derived *derived() { return static_cast<Derived *>(this); } Derived *derived();
}; };
template <class Derived, CIcons::IconIndex IconIndex>
CIcons::IconIndex Icon<Derived, IconIndex>::toIcon() const { return IconIndex; }
template <class Derived, CIcons::IconIndex IconIndex>
const Derived *Icon<Derived, IconIndex>::derived() const { return static_cast<const Derived *>(this); }
template <class Derived, CIcons::IconIndex IconIndex>
Derived *Icon<Derived, IconIndex>::derived() { return static_cast<Derived *>(this); }
/*! /*!
* When a derived class and a base class both inherit from Mixin::Icon, * When a derived class and a base class both inherit from Mixin::Icon,
* the derived class uses this macro to disambiguate the inherited members. * the derived class uses this macro to disambiguate the inherited members.

View File

@@ -67,39 +67,66 @@ namespace BlackMisc
bool equalsPropertyByIndex(const QVariant &compareValue, CPropertyIndexRef index) const; bool equalsPropertyByIndex(const QVariant &compareValue, CPropertyIndexRef index) const;
private: private:
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *derived() const;
Derived *derived() { return static_cast<Derived *>(this); } Derived *derived();
template <typename T> template <typename T>
QVariant myself() const QVariant myself() const;
template <typename T>
void myself(const QVariant &variant);
template <typename T>
QVariant basePropertyByIndex(const T *base, CPropertyIndexRef index) const;
template <typename T>
void baseSetPropertyByIndex(T *base, const QVariant &var, CPropertyIndexRef index);
QVariant basePropertyByIndex(const void *, CPropertyIndexRef) const;
void baseSetPropertyByIndex(void *, const QVariant &, CPropertyIndexRef);
};
template <class Derived>
const Derived *Index<Derived>::derived() const { return static_cast<const Derived *>(this); }
template <class Derived>
Derived *Index<Derived>::derived() { return static_cast<Derived *>(this); }
template <class Derived>
template <typename T>
QVariant Index<Derived>::myself() const
{ {
if constexpr (std::is_default_constructible_v<T>) { return QVariant::fromValue(*derived()); } if constexpr (std::is_default_constructible_v<T>) { return QVariant::fromValue(*derived()); }
else { qFatal("isMyself should have been handled before reaching here"); return {}; } else { qFatal("isMyself should have been handled before reaching here"); return {}; }
} }
template <class Derived>
template <typename T> template <typename T>
void myself(const QVariant &variant) void Index<Derived>::myself(const QVariant &variant)
{ {
if constexpr (std::is_default_constructible_v<T>) { *derived() = variant.value<T>(); } if constexpr (std::is_default_constructible_v<T>) { *derived() = variant.value<T>(); }
else { qFatal("isMyself should have been handled before reaching here"); } else { qFatal("isMyself should have been handled before reaching here"); }
} }
template <class Derived>
template <typename T> template <typename T>
QVariant basePropertyByIndex(const T *base, CPropertyIndexRef index) const { return base->propertyByIndex(index); } QVariant Index<Derived>::basePropertyByIndex(const T *base, CPropertyIndexRef index) const { return base->propertyByIndex(index); }
template <typename T>
void baseSetPropertyByIndex(T *base, const QVariant &var, CPropertyIndexRef index) { base->setPropertyByIndex(index, var); }
QVariant basePropertyByIndex(const void *, CPropertyIndexRef) const template <class Derived>
template <typename T>
void Index<Derived>::baseSetPropertyByIndex(T *base, const QVariant &var, CPropertyIndexRef index) { base->setPropertyByIndex(index, var); }
template <class Derived>
QVariant Index<Derived>::basePropertyByIndex(const void *, CPropertyIndexRef) const
{ {
//qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {}; //qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {};
qFatal("Property by index not found"); return {}; qFatal("Property by index not found"); return {};
} }
void baseSetPropertyByIndex(void *, const QVariant &, CPropertyIndexRef) template <class Derived>
void Index<Derived>::baseSetPropertyByIndex(void *, const QVariant &, CPropertyIndexRef)
{ {
//qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString())); //qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString()));
qFatal("Property by index not found"); qFatal("Property by index not found");
} }
};
/*! /*!
* When a derived class and a base class both inherit from Mixin::Index, * When a derived class and a base class both inherit from Mixin::Index,

View File

@@ -93,7 +93,43 @@ namespace BlackMisc
{ {
public: public:
//! Cast to JSON object //! Cast to JSON object
QJsonObject toJson() const QJsonObject toJson() const;
//! Convenience function JSON as string
QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const;
//! Assign from JSON object
void convertFromJson(const QJsonObject &json);
//! Assign from JSON object string
void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false);
//! Get object from QJsonObject
template<class DerivedObj = Derived>
static DerivedObj fromJson(const QJsonObject &json);
//! Get object from JSON string
template<class DerivedObj = Derived>
static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson = false);
//! Get object from JSON string
template<class DerivedObj = Derived>
static Derived fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg);
private:
const Derived *derived() const;
Derived *derived();
template <typename T> static QJsonObject baseToJson(const T *base);
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json);
static QJsonObject baseToJson(const void *);
static void baseConvertFromJson(void *, const QJsonObject &);
static QJsonObject baseToJson(const CEmpty *);
static void baseConvertFromJson(CEmpty *, const QJsonObject &);
};
template <class Derived>
QJsonObject JsonByMetaClass<Derived>::toJson() const
{ {
QJsonObject json; QJsonObject json;
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -106,15 +142,15 @@ namespace BlackMisc
return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived()))); return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived())));
} }
//! Convenience function JSON as string template <class Derived>
QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const QString JsonByMetaClass<Derived>::toJsonString(QJsonDocument::JsonFormat format) const
{ {
QJsonDocument jsonDoc(toJson()); QJsonDocument jsonDoc(toJson());
return jsonDoc.toJson(format); return jsonDoc.toJson(format);
} }
//! Assign from JSON object template <class Derived>
void convertFromJson(const QJsonObject &json) void JsonByMetaClass<Derived>::convertFromJson(const QJsonObject &json)
{ {
baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json); baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json);
introspect<Derived>().forEachMember([ &, this ](auto member) introspect<Derived>().forEachMember([ &, this ](auto member)
@@ -140,25 +176,25 @@ namespace BlackMisc
}); });
} }
//! Assign from JSON object string template <class Derived>
void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false) void JsonByMetaClass<Derived>::convertFromJson(const QString &jsonString, bool acceptCacheFormat)
{ {
const QJsonObject jsonObject = BlackMisc::Json::jsonObjectFromString(jsonString, acceptCacheFormat); const QJsonObject jsonObject = BlackMisc::Json::jsonObjectFromString(jsonString, acceptCacheFormat);
convertFromJson(jsonObject); convertFromJson(jsonObject);
} }
//! Get object from QJsonObject template <class Derived>
template<class DerivedObj = Derived> template <class DerivedObj>
static DerivedObj fromJson(const QJsonObject &json) DerivedObj JsonByMetaClass<Derived>::fromJson(const QJsonObject &json)
{ {
DerivedObj obj; DerivedObj obj;
obj.convertFromJson(json); obj.convertFromJson(json);
return obj; return obj;
} }
//! Get object from JSON string template <class Derived>
template<class DerivedObj = Derived> template <class DerivedObj>
static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson = false) DerivedObj JsonByMetaClass<Derived>::fromJson(const QString &jsonString, bool acceptCacheJson)
{ {
DerivedObj obj; DerivedObj obj;
if (jsonString.isEmpty()) { return obj; } if (jsonString.isEmpty()) { return obj; }
@@ -167,9 +203,9 @@ namespace BlackMisc
return obj; return obj;
} }
//! Get object from JSON string template <class Derived>
template<class DerivedObj = Derived> template <class DerivedObj>
static Derived fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg) Derived JsonByMetaClass<Derived>::fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg)
{ {
success = false; success = false;
Derived obj; Derived obj;
@@ -187,17 +223,31 @@ namespace BlackMisc
return obj; return obj;
} }
private: template <class Derived>
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *JsonByMetaClass<Derived>::derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static QJsonObject baseToJson(const T *base) { return base->toJson(); } template <class Derived>
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); } Derived *JsonByMetaClass<Derived>::derived() { return static_cast<Derived *>(this); }
static QJsonObject baseToJson(const void *) { return {}; }
static void baseConvertFromJson(void *, const QJsonObject &) {} template <class Derived>
static QJsonObject baseToJson(const CEmpty *) { return {}; } template <typename T>
static void baseConvertFromJson(CEmpty *, const QJsonObject &) {} QJsonObject JsonByMetaClass<Derived>::baseToJson(const T *base) { return base->toJson(); }
};
template <class Derived>
template <typename T>
void JsonByMetaClass<Derived>::baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); }
template <class Derived>
QJsonObject JsonByMetaClass<Derived>::baseToJson(const void *) { return {}; }
template <class Derived>
void JsonByMetaClass<Derived>::baseConvertFromJson(void *, const QJsonObject &) {}
template <class Derived>
QJsonObject JsonByMetaClass<Derived>::baseToJson(const CEmpty *) { return {}; }
template <class Derived>
void JsonByMetaClass<Derived>::baseConvertFromJson(CEmpty *, const QJsonObject &) {}
/*! /*!
* When a derived class and a base class both inherit from Mixin::JsonByTuple, * When a derived class and a base class both inherit from Mixin::JsonByTuple,

View File

@@ -32,39 +32,64 @@ namespace BlackMisc
{ {
public: public:
//! Register metadata //! Register metadata
static void registerMetadata() static void registerMetadata();
//! Returns the Qt meta type ID of this object
//! \remark for CVariant this returns the id of CVariant, not of the encapsulated object. valueVariant.userType()` returns metatype of the contained object
int getMetaTypeId() const;
//! Class name
QString getClassName() const;
//! Returns true if this object is an instance of the class with the given meta type ID, or one of its subclasses.
bool isA(int metaTypeId) const;
private:
const Derived *derived() const;
Derived *derived();
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId);
static bool baseIsA(const void *, int);
};
template <class Derived>
void MetaType<Derived>::registerMetadata()
{ {
Private::MetaTypeHelper<Derived>::maybeRegisterMetaType(); Private::MetaTypeHelper<Derived>::maybeRegisterMetaType();
} }
//! Returns the Qt meta type ID of this object template <class Derived>
//! \remark for CVariant this returns the id of CVariant, not of the encapsulated object. valueVariant.userType()` returns metatype of the contained object int MetaType<Derived>::getMetaTypeId() const
int getMetaTypeId() const
{ {
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId(); return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
} }
//! Class name template <class Derived>
QString getClassName() const QString MetaType<Derived>::getClassName() const
{ {
return QMetaType::typeName(getMetaTypeId()); return QMetaType::typeName(getMetaTypeId());
} }
//! Returns true if this object is an instance of the class with the given meta type ID, or one of its subclasses. template <class Derived>
bool isA(int metaTypeId) const bool MetaType<Derived>::isA(int metaTypeId) const
{ {
if (metaTypeId == QMetaType::UnknownType) { return false; } if (metaTypeId == QMetaType::UnknownType) { return false; }
if (metaTypeId == getMetaTypeId()) { return true; } if (metaTypeId == getMetaTypeId()) { return true; }
return baseIsA(static_cast<const TMetaBaseOfT<Derived> *>(derived()), metaTypeId); return baseIsA(static_cast<const TMetaBaseOfT<Derived> *>(derived()), metaTypeId);
} }
private: template <class Derived>
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *MetaType<Derived>::derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); } template <class Derived>
static bool baseIsA(const void *, int) { return false; } Derived *MetaType<Derived>::derived() { return static_cast<Derived *>(this); }
};
template <class Derived>
template <typename Base2>
bool MetaType<Derived>::baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); }
template <class Derived>
bool MetaType<Derived>::baseIsA(const void *, int) { return false; }
// *INDENT-OFF* // *INDENT-OFF*
/*! /*!

View File

@@ -62,23 +62,41 @@ namespace BlackMisc::Mixin
} }
//! Cast as QString //! Cast as QString
QString toQString(bool i18n = false) const { return derived()->convertToQString(i18n); } QString toQString(bool i18n = false) const;
//! Cast to pretty-printed QString //! Cast to pretty-printed QString
//! \deprecated not really used and just using toQString //! \deprecated not really used and just using toQString
QString toFormattedQString(bool i18n = false) const { return derived()->toQString(i18n); } QString toFormattedQString(bool i18n = false) const;
//! To std string //! To std string
std::string toStdString(bool i18n = false) const { return derived()->convertToQString(i18n).toStdString(); } std::string toStdString(bool i18n = false) const;
//! String for streaming operators //! String for streaming operators
QString stringForStreaming() const { return derived()->convertToQString(); } QString stringForStreaming() const;
private: private:
const Derived *derived() const { return static_cast<const Derived *>(this); } const Derived *derived() const;
Derived *derived() { return static_cast<Derived *>(this); } Derived *derived();
}; };
template <class Derived>
QString String<Derived>::toQString(bool i18n) const { return derived()->convertToQString(i18n); }
template <class Derived>
QString String<Derived>::toFormattedQString(bool i18n) const { return derived()->toQString(i18n); }
template <class Derived>
std::string String<Derived>::toStdString(bool i18n) const { return derived()->convertToQString(i18n).toStdString(); }
template <class Derived>
QString String<Derived>::stringForStreaming() const { return derived()->convertToQString(); }
template <class Derived>
const Derived *String<Derived>::derived() const { return static_cast<const Derived *>(this); }
template <class Derived>
Derived *String<Derived>::derived() { return static_cast<Derived *>(this); }
// *INDENT-OFF* // *INDENT-OFF*
/*! /*!
* When a derived class and a base class both inherit from Mixin::String, * When a derived class and a base class both inherit from Mixin::String,

View File

@@ -50,8 +50,7 @@ namespace BlackMisc
void registerMetaValueType() void registerMetaValueType()
{ {
if (QMetaType::hasRegisteredConverterFunction<T, Private::IValueObjectMetaInfo *>()) { return; } if (QMetaType::hasRegisteredConverterFunction<T, Private::IValueObjectMetaInfo *>()) { return; }
auto converter = [](const T &) { static Private::CValueObjectMetaInfo<T> info; return &info; }; bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(Private::CValueObjectMetaInfo<T>::instance);
bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(converter);
Q_ASSERT(ok); Q_ASSERT(ok);
Q_UNUSED(ok); Q_UNUSED(ok);
} }

View File

@@ -142,81 +142,115 @@ namespace BlackMisc
template <typename T> template <typename T>
struct CValueObjectMetaInfo : public IValueObjectMetaInfo struct CValueObjectMetaInfo : public IValueObjectMetaInfo
{ {
virtual QString toQString(const void *object, bool i18n) const override CValueObjectMetaInfo();
virtual ~CValueObjectMetaInfo() override;
static CValueObjectMetaInfo *instance(const T &);
CValueObjectMetaInfo(const CValueObjectMetaInfo &) = delete;
CValueObjectMetaInfo &operator =(const CValueObjectMetaInfo &) = delete;
virtual QString toQString(const void *object, bool i18n) const override;
virtual QJsonObject toJson(const void *object) const override;
virtual void convertFromJson(const QJsonObject &json, void *object) const override;
virtual QJsonObject toMemoizedJson(const void *object) const override;
virtual void convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const override;
virtual void unmarshall(const QDBusArgument &arg, void *object) const override;
virtual uint getValueHash(const void *object) const override;
virtual int getMetaTypeId() const override;
virtual const void *upCastTo(const void *object, int metaTypeId) const override;
virtual int compareImpl(const void *lhs, const void *rhs) const override;
virtual void setPropertyByIndex(void *object, const QVariant &variant, CPropertyIndexRef index) const override;
virtual void propertyByIndex(const void *object, QVariant &o_variant, BlackMisc::CPropertyIndexRef index) const override;
virtual bool equalsPropertyByIndex(const void *object, const QVariant &compareValue, CPropertyIndexRef index) const override;
virtual int toIcon(const void *object) const override;
virtual bool matches(const void *object, const CVariant &value) const override;
static const T &cast(const void *object);
static T &cast(void *object);
};
template <typename T> CValueObjectMetaInfo<T>::CValueObjectMetaInfo()
{}
template <typename T> CValueObjectMetaInfo<T>::~CValueObjectMetaInfo()
{}
template <typename T> CValueObjectMetaInfo<T> *CValueObjectMetaInfo<T>::instance(const T &)
{
static CValueObjectMetaInfo mi;
return &mi;
}
template <typename T> QString CValueObjectMetaInfo<T>::toQString(const void *object, bool i18n) const
{ {
return cast(object).toQString(i18n); return cast(object).toQString(i18n);
} }
virtual QJsonObject toJson(const void *object) const override template <typename T> QJsonObject CValueObjectMetaInfo<T>::toJson(const void *object) const
{ {
return CValueObjectMetaInfoHelper::toJson(cast(object), 0); return CValueObjectMetaInfoHelper::toJson(cast(object), 0);
} }
virtual void convertFromJson(const QJsonObject &json, void *object) const override template <typename T> void CValueObjectMetaInfo<T>::convertFromJson(const QJsonObject &json, void *object) const
{ {
CValueObjectMetaInfoHelper::convertFromJson(json, cast(object), 0); CValueObjectMetaInfoHelper::convertFromJson(json, cast(object), 0);
} }
virtual QJsonObject toMemoizedJson(const void *object) const override template <typename T> QJsonObject CValueObjectMetaInfo<T>::toMemoizedJson(const void *object) const
{ {
return CValueObjectMetaInfoHelper::toMemoizedJson(cast(object), 0); return CValueObjectMetaInfoHelper::toMemoizedJson(cast(object), 0);
} }
virtual void convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const override template <typename T> void CValueObjectMetaInfo<T>::convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const
{ {
CValueObjectMetaInfoHelper::convertFromMemoizedJson(json, cast(object), allowFallbackToJson, 0); CValueObjectMetaInfoHelper::convertFromMemoizedJson(json, cast(object), allowFallbackToJson, 0);
} }
virtual void unmarshall(const QDBusArgument &arg, void *object) const override template <typename T> void CValueObjectMetaInfo<T>::unmarshall(const QDBusArgument &arg, void *object) const
{ {
arg >> cast(object); arg >> cast(object);
} }
virtual uint getValueHash(const void *object) const override template <typename T> uint CValueObjectMetaInfo<T>::getValueHash(const void *object) const
{ {
return CValueObjectMetaInfoHelper::getValueHash(cast(object), 0); return CValueObjectMetaInfoHelper::getValueHash(cast(object), 0);
} }
virtual int getMetaTypeId() const override template <typename T> int CValueObjectMetaInfo<T>::getMetaTypeId() const
{ {
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } else { return QMetaType::UnknownType; } if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } else { return QMetaType::UnknownType; }
} }
virtual const void *upCastTo(const void *object, int metaTypeId) const override template <typename T> const void *CValueObjectMetaInfo<T>::upCastTo(const void *object, int metaTypeId) const
{
if constexpr (THasMetaBaseV<T>)
{ {
const auto base = static_cast<const void *>(static_cast<const TMetaBaseOfT<T> *>(&cast(object))); const auto base = static_cast<const void *>(static_cast<const TMetaBaseOfT<T> *>(&cast(object)));
return metaTypeId == getMetaTypeId() ? object : CValueObjectMetaInfo<TMetaBaseOfT<T>> {} .upCastTo(base, metaTypeId); return metaTypeId == getMetaTypeId() ? object : CValueObjectMetaInfo<TMetaBaseOfT<T>>::instance(cast(object))->upCastTo(base, metaTypeId);
} }
virtual int compareImpl(const void *lhs, const void *rhs) const override else { Q_UNUSED(metaTypeId); return object; }
}
template <typename T> int CValueObjectMetaInfo<T>::compareImpl(const void *lhs, const void *rhs) const
{ {
return CValueObjectMetaInfoHelper::compareImpl(cast(lhs), cast(rhs), 0); return CValueObjectMetaInfoHelper::compareImpl(cast(lhs), cast(rhs), 0);
} }
virtual void setPropertyByIndex(void *object, const QVariant &variant, CPropertyIndexRef index) const override template <typename T> void CValueObjectMetaInfo<T>::setPropertyByIndex(void *object, const QVariant &variant, CPropertyIndexRef index) const
{ {
CValueObjectMetaInfoHelper::setPropertyByIndex(cast(object), variant, index, 0); CValueObjectMetaInfoHelper::setPropertyByIndex(cast(object), variant, index, 0);
} }
virtual void propertyByIndex(const void *object, QVariant &o_variant, BlackMisc::CPropertyIndexRef index) const override template <typename T> void CValueObjectMetaInfo<T>::propertyByIndex(const void *object, QVariant &o_variant, BlackMisc::CPropertyIndexRef index) const
{ {
CValueObjectMetaInfoHelper::propertyByIndex(o_variant, cast(object), index, 0); CValueObjectMetaInfoHelper::propertyByIndex(o_variant, cast(object), index, 0);
} }
virtual bool equalsPropertyByIndex(const void *object, const QVariant &compareValue, CPropertyIndexRef index) const override template <typename T> bool CValueObjectMetaInfo<T>::equalsPropertyByIndex(const void *object, const QVariant &compareValue, CPropertyIndexRef index) const
{ {
return CValueObjectMetaInfoHelper::equalsPropertyByIndex(cast(object), compareValue, index, 0); return CValueObjectMetaInfoHelper::equalsPropertyByIndex(cast(object), compareValue, index, 0);
} }
virtual int toIcon(const void *object) const override template <typename T> int CValueObjectMetaInfo<T>::toIcon(const void *object) const
{ {
return CValueObjectMetaInfoHelper::toIcon(cast(object), 0); return CValueObjectMetaInfoHelper::toIcon(cast(object), 0);
} }
virtual bool matches(const void *object, const CVariant &value) const override template <typename T> bool CValueObjectMetaInfo<T>::matches(const void *object, const CVariant &value) const
{ {
return CValueObjectMetaInfoHelper::matches(cast(object), value, 0); return CValueObjectMetaInfoHelper::matches(cast(object), value, 0);
} }
template <typename T> const T &CValueObjectMetaInfo<T>::cast(const void *object)
static const T &cast(const void *object) { return *static_cast<const T *>(object); }
static T &cast(void *object) { return *static_cast<T *>(object); }
};
//! \private Explicit specialization for the terminating case of the recursive CValueObjectMetaInfo::upCastTo.
template <>
struct CValueObjectMetaInfo<void>
{ {
const void *upCastTo(const void *, int) const return *static_cast<const T *>(object);
{ }
return nullptr; template <typename T> T &CValueObjectMetaInfo<T>::cast(void *object)
{
return *static_cast<T *>(object);
} }
};
//! \private Getter to obtain the IValueObjectMetaInfo which was stored by BlackMisc::registerMetaValueType. //! \private Getter to obtain the IValueObjectMetaInfo which was stored by BlackMisc::registerMetaValueType.
IValueObjectMetaInfo *getValueObjectMetaInfo(int typeId); IValueObjectMetaInfo *getValueObjectMetaInfo(int typeId);
@@ -242,7 +276,12 @@ namespace BlackMisc
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); }
else { return QMetaType::UnknownType; } else { return QMetaType::UnknownType; }
} }
static void maybeRegisterMetaType() static void maybeRegisterMetaType();
static void maybeRegisterMetaList();
};
template <typename T>
void MetaTypeHelper<T>::maybeRegisterMetaType()
{ {
if constexpr (QMetaTypeId<T>::Defined) if constexpr (QMetaTypeId<T>::Defined)
{ {
@@ -252,8 +291,6 @@ namespace BlackMisc
registerMetaValueType<T>(); registerMetaValueType<T>();
maybeRegisterMetaList(); maybeRegisterMetaList();
} }
}
static void maybeRegisterMetaList();
}; };
//! \endcond //! \endcond
} }