mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-30 20:15:35 +08:00
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:
@@ -36,6 +36,12 @@ namespace BlackMisc
|
||||
};
|
||||
//! \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.
|
||||
*/
|
||||
@@ -43,7 +49,7 @@ namespace BlackMisc
|
||||
struct TMetaBaseOf
|
||||
{
|
||||
//! 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>;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -56,30 +56,46 @@ namespace BlackMisc
|
||||
friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); }
|
||||
|
||||
private:
|
||||
static bool equals(const Derived &a, const Derived &b)
|
||||
{
|
||||
bool result = baseEquals(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result && EqualsByMetaClass::membersEqual(member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
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; }
|
||||
|
||||
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)
|
||||
{
|
||||
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison)) { return a.compare(b, Qt::CaseInsensitive) == 0; }
|
||||
else { return a == b; }
|
||||
}
|
||||
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));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result && EqualsByMetaClass::membersEqual(member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
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>
|
||||
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; }
|
||||
else { return a == b; }
|
||||
}
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented using its compare function.
|
||||
*
|
||||
@@ -122,36 +138,52 @@ namespace BlackMisc
|
||||
friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); }
|
||||
|
||||
private:
|
||||
static bool less(const Derived &a, const 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));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result || LessThanByMetaClass::membersLess(gt, member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
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; }
|
||||
|
||||
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)
|
||||
{
|
||||
if (io_greaterThan) { return false; }
|
||||
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison))
|
||||
{
|
||||
io_greaterThan = b.compare(a, Qt::CaseInsensitive) < 0;
|
||||
return a.compare(b, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
else { io_greaterThan = b < a; return a < b; }
|
||||
}
|
||||
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 gt = baseLess(static_cast<const TBaseOfT<Derived> *>(&b), static_cast<const TBaseOfT<Derived> *>(&a));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result || LessThanByMetaClass::membersLess(gt, member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
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>
|
||||
bool LessThanByMetaClass<Derived>::membersLess(bool &io_greaterThan, const T &a, const T &b, Flags)
|
||||
{
|
||||
if (io_greaterThan) { return false; }
|
||||
if constexpr (static_cast<bool>(Flags::value & CaseInsensitiveComparison))
|
||||
{
|
||||
io_greaterThan = b.compare(a, Qt::CaseInsensitive) < 0;
|
||||
return a.compare(b, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
else { io_greaterThan = b < a; return a < b; }
|
||||
}
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass.
|
||||
*/
|
||||
@@ -163,31 +195,47 @@ namespace BlackMisc
|
||||
friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); }
|
||||
|
||||
private:
|
||||
static int compareImpl(const Derived &a, const Derived &b)
|
||||
{
|
||||
int result = baseCompare(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result ? result : CompareByMetaClass::membersCompare(member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
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; }
|
||||
|
||||
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)
|
||||
{
|
||||
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 { return a < b ? -1 : b < a ? 1 : 0; }
|
||||
}
|
||||
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));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForComparison>()))
|
||||
{
|
||||
result = result ? result : CompareByMetaClass::membersCompare(member.in(a), member.in(b), member.m_flags);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
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>
|
||||
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); }
|
||||
else if constexpr (THasCompare<T, T>::value) { return compare(a, b); }
|
||||
else { return a < b ? -1 : b < a ? 1 : 0; }
|
||||
}
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
|
||||
@@ -55,43 +55,75 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! Marshal a value to a QDataStream.
|
||||
void marshalToDataStream(QDataStream &stream) const
|
||||
{
|
||||
baseMarshal(static_cast<const TBaseOfT<Derived> *>(derived()), stream);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
stream << member.in(*this->derived());
|
||||
}
|
||||
});
|
||||
}
|
||||
void marshalToDataStream(QDataStream &stream) const;
|
||||
|
||||
//! Unmarshal a value from a QDataStream.
|
||||
void unmarshalFromDataStream(QDataStream &stream)
|
||||
{
|
||||
baseUnmarshal(static_cast<TBaseOfT<Derived> *>(derived()), stream);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
stream >> member.in(*this->derived());
|
||||
}
|
||||
});
|
||||
}
|
||||
void unmarshalFromDataStream(QDataStream &stream);
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
Derived *derived();
|
||||
|
||||
template <typename T> static void baseMarshal(const T *base, QDataStream &stream) { base->marshalToDataStream(stream); }
|
||||
template <typename T> static void baseUnmarshal(T *base, QDataStream &stream) { base->unmarshalFromDataStream(stream); }
|
||||
static void baseMarshal(const void *, QDataStream &) {}
|
||||
static void baseUnmarshal(void *, QDataStream &) {}
|
||||
static void baseMarshal(const CEmpty *, QDataStream &) {}
|
||||
static void baseUnmarshal(CEmpty *, QDataStream &) {}
|
||||
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);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
stream << member.in(*this->derived());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void DataStreamByMetaClass<Derived>::unmarshalFromDataStream(QDataStream &stream)
|
||||
{
|
||||
baseUnmarshal(static_cast<TBaseOfT<Derived> *>(derived()), stream);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
stream >> member.in(*this->derived());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
const Derived *DataStreamByMetaClass<Derived>::derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
template <class Derived>
|
||||
Derived *DataStreamByMetaClass<Derived>::derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <class Derived>
|
||||
template <typename T>
|
||||
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,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
|
||||
@@ -68,61 +68,93 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! Marshall without begin/endStructure, for when composed within another object
|
||||
void marshallToDbus(QDBusArgument &arg, Tags...) const
|
||||
{
|
||||
baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
const auto &value = member.in(*this->derived());
|
||||
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
|
||||
{
|
||||
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
|
||||
{
|
||||
value.marshallToDbus(arg, LosslessTag());
|
||||
}
|
||||
else { value.marshallToDbus(arg); }
|
||||
}
|
||||
else { arg << value; }
|
||||
}
|
||||
});
|
||||
}
|
||||
void marshallToDbus(QDBusArgument &arg, Tags...) const;
|
||||
|
||||
//! Unmarshall without begin/endStructure, for when composed within another object
|
||||
void unmarshallFromDbus(const QDBusArgument &arg, Tags...)
|
||||
{
|
||||
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
auto &value = member.in(*this->derived());
|
||||
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
|
||||
{
|
||||
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
|
||||
{
|
||||
value.unmarshallFromDbus(arg, LosslessTag());
|
||||
}
|
||||
else { value.unmarshallFromDbus(arg); }
|
||||
}
|
||||
else { arg >> value; }
|
||||
}
|
||||
});
|
||||
}
|
||||
void unmarshallFromDbus(const QDBusArgument &arg, Tags...);
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
Derived *derived();
|
||||
|
||||
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg, Tags()...); }
|
||||
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg, Tags()...); }
|
||||
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 <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);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
const auto &value = member.in(*this->derived());
|
||||
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
|
||||
{
|
||||
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
|
||||
{
|
||||
value.marshallToDbus(arg, LosslessTag());
|
||||
}
|
||||
else { value.marshallToDbus(arg); }
|
||||
}
|
||||
else { arg << value; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class Derived, class... Tags>
|
||||
void DBusByMetaClass<Derived, Tags...>::unmarshallFromDbus(const QDBusArgument &arg, Tags...)
|
||||
{
|
||||
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForMarshalling>()))
|
||||
{
|
||||
auto &value = member.in(*this->derived());
|
||||
if constexpr (THasMarshallMethods<std::decay_t<decltype(value)>>::value)
|
||||
{
|
||||
if constexpr (member.has(MetaFlags<LosslessMarshalling>()))
|
||||
{
|
||||
value.unmarshallFromDbus(arg, LosslessTag());
|
||||
}
|
||||
else { value.unmarshallFromDbus(arg); }
|
||||
}
|
||||
else { arg >> value; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class Derived, class... Tags>
|
||||
const Derived *DBusByMetaClass<Derived, Tags...>::derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
template <class Derived, class... Tags>
|
||||
Derived *DBusByMetaClass<Derived, Tags...>::derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <class Derived, class... Tags>
|
||||
template <typename T>
|
||||
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*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::DBusByTuple,
|
||||
|
||||
@@ -57,23 +57,32 @@ namespace BlackMisc
|
||||
}
|
||||
|
||||
private:
|
||||
static uint hashImpl(const Derived &value)
|
||||
{
|
||||
uint hash = baseHash(static_cast<const TBaseOfT<Derived> *>(&value));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForHashing>()))
|
||||
{
|
||||
hash ^= qHash(member.in(value));
|
||||
}
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
static uint hashImpl(const Derived &value);
|
||||
|
||||
template <typename T> static uint baseHash(const T *base) { return qHash(*base); }
|
||||
static uint baseHash(const void *) { return 0; }
|
||||
static uint baseHash(const CEmpty *) { return 0; }
|
||||
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));
|
||||
introspect<Derived>().forEachMember([ & ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForHashing>()))
|
||||
{
|
||||
hash ^= qHash(member.in(value));
|
||||
}
|
||||
});
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
uint HashByMetaClass<Derived>::baseHash(const void *) { return 0; }
|
||||
|
||||
template <class Derived>
|
||||
uint HashByMetaClass<Derived>::baseHash(const CEmpty *) { return 0; }
|
||||
}
|
||||
} // namespace BlackMisc
|
||||
|
||||
|
||||
@@ -31,13 +31,22 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! As icon, not implemented by all classes
|
||||
CIcons::IconIndex toIcon() const { return IconIndex; }
|
||||
CIcons::IconIndex toIcon() const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
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,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
|
||||
@@ -67,40 +67,67 @@ namespace BlackMisc
|
||||
bool equalsPropertyByIndex(const QVariant &compareValue, CPropertyIndexRef index) const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
Derived *derived();
|
||||
|
||||
template <typename T>
|
||||
QVariant myself() const
|
||||
{
|
||||
if constexpr (std::is_default_constructible_v<T>) { return QVariant::fromValue(*derived()); }
|
||||
else { qFatal("isMyself should have been handled before reaching here"); return {}; }
|
||||
}
|
||||
QVariant myself() const;
|
||||
template <typename T>
|
||||
void myself(const QVariant &variant)
|
||||
{
|
||||
if constexpr (std::is_default_constructible_v<T>) { *derived() = variant.value<T>(); }
|
||||
else { qFatal("isMyself should have been handled before reaching here"); }
|
||||
}
|
||||
void myself(const QVariant &variant);
|
||||
|
||||
template <typename T>
|
||||
QVariant basePropertyByIndex(const T *base, CPropertyIndexRef index) const { return base->propertyByIndex(index); }
|
||||
QVariant basePropertyByIndex(const T *base, CPropertyIndexRef index) const;
|
||||
template <typename T>
|
||||
void baseSetPropertyByIndex(T *base, const QVariant &var, CPropertyIndexRef index) { base->setPropertyByIndex(index, var); }
|
||||
void baseSetPropertyByIndex(T *base, const QVariant &var, CPropertyIndexRef index);
|
||||
|
||||
QVariant basePropertyByIndex(const void *, CPropertyIndexRef) const
|
||||
{
|
||||
//qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {};
|
||||
qFatal("Property by index not found"); return {};
|
||||
}
|
||||
|
||||
void baseSetPropertyByIndex(void *, const QVariant &, CPropertyIndexRef)
|
||||
{
|
||||
//qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString()));
|
||||
qFatal("Property by index not found");
|
||||
}
|
||||
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()); }
|
||||
else { qFatal("isMyself should have been handled before reaching here"); return {}; }
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
template <typename T>
|
||||
void Index<Derived>::myself(const QVariant &variant)
|
||||
{
|
||||
if constexpr (std::is_default_constructible_v<T>) { *derived() = variant.value<T>(); }
|
||||
else { qFatal("isMyself should have been handled before reaching here"); }
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
template <typename T>
|
||||
QVariant Index<Derived>::basePropertyByIndex(const T *base, CPropertyIndexRef index) const { return base->propertyByIndex(index); }
|
||||
|
||||
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("Property by index not found"); return {};
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void Index<Derived>::baseSetPropertyByIndex(void *, const QVariant &, CPropertyIndexRef)
|
||||
{
|
||||
//qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString()));
|
||||
qFatal("Property by index not found");
|
||||
}
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::Index,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
|
||||
@@ -93,111 +93,161 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! Cast to JSON object
|
||||
QJsonObject toJson() const
|
||||
{
|
||||
QJsonObject json;
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
|
||||
{
|
||||
json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(member.in(*this->derived())));
|
||||
}
|
||||
});
|
||||
return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived())));
|
||||
}
|
||||
QJsonObject toJson() const;
|
||||
|
||||
//! Convenience function JSON as string
|
||||
QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const
|
||||
{
|
||||
QJsonDocument jsonDoc(toJson());
|
||||
return jsonDoc.toJson(format);
|
||||
}
|
||||
QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const;
|
||||
|
||||
//! Assign from JSON object
|
||||
void convertFromJson(const QJsonObject &json)
|
||||
{
|
||||
baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
|
||||
{
|
||||
const auto value = json.value(CExplicitLatin1String(member.latin1Name()));
|
||||
if (value.isUndefined())
|
||||
{
|
||||
constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
// QLatin1String used instead of QStringLiteral below since the latter causes an internal compiler bug
|
||||
// in GCC 8 and higher
|
||||
if (required) { throw CJsonException(QLatin1String("Missing required member '%1'").arg(member.latin1Name())); }
|
||||
}
|
||||
else
|
||||
{
|
||||
CJsonScope scope(member.latin1Name());
|
||||
Q_UNUSED(scope);
|
||||
value >> member.in(*this->derived());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
void convertFromJson(const QJsonObject &json);
|
||||
|
||||
//! Assign from JSON object string
|
||||
void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false)
|
||||
{
|
||||
const QJsonObject jsonObject = BlackMisc::Json::jsonObjectFromString(jsonString, acceptCacheFormat);
|
||||
convertFromJson(jsonObject);
|
||||
}
|
||||
void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false);
|
||||
|
||||
//! Get object from QJsonObject
|
||||
template<class DerivedObj = Derived>
|
||||
static DerivedObj fromJson(const QJsonObject &json)
|
||||
{
|
||||
DerivedObj obj;
|
||||
obj.convertFromJson(json);
|
||||
return obj;
|
||||
}
|
||||
static DerivedObj fromJson(const QJsonObject &json);
|
||||
|
||||
//! Get object from JSON string
|
||||
template<class DerivedObj = Derived>
|
||||
static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson = false)
|
||||
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;
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
|
||||
{
|
||||
json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(member.in(*this->derived())));
|
||||
}
|
||||
});
|
||||
return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived())));
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
QString JsonByMetaClass<Derived>::toJsonString(QJsonDocument::JsonFormat format) const
|
||||
{
|
||||
QJsonDocument jsonDoc(toJson());
|
||||
return jsonDoc.toJson(format);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void JsonByMetaClass<Derived>::convertFromJson(const QJsonObject &json)
|
||||
{
|
||||
baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json);
|
||||
introspect<Derived>().forEachMember([ &, this ](auto member)
|
||||
{
|
||||
if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
|
||||
{
|
||||
const auto value = json.value(CExplicitLatin1String(member.latin1Name()));
|
||||
if (value.isUndefined())
|
||||
{
|
||||
constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
// QLatin1String used instead of QStringLiteral below since the latter causes an internal compiler bug
|
||||
// in GCC 8 and higher
|
||||
if (required) { throw CJsonException(QLatin1String("Missing required member '%1'").arg(member.latin1Name())); }
|
||||
}
|
||||
else
|
||||
{
|
||||
CJsonScope scope(member.latin1Name());
|
||||
Q_UNUSED(scope);
|
||||
value >> member.in(*this->derived());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void JsonByMetaClass<Derived>::convertFromJson(const QString &jsonString, bool acceptCacheFormat)
|
||||
{
|
||||
const QJsonObject jsonObject = BlackMisc::Json::jsonObjectFromString(jsonString, acceptCacheFormat);
|
||||
convertFromJson(jsonObject);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
template <class DerivedObj>
|
||||
DerivedObj JsonByMetaClass<Derived>::fromJson(const QJsonObject &json)
|
||||
{
|
||||
DerivedObj obj;
|
||||
obj.convertFromJson(json);
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
template <class DerivedObj>
|
||||
DerivedObj JsonByMetaClass<Derived>::fromJson(const QString &jsonString, bool acceptCacheJson)
|
||||
{
|
||||
DerivedObj obj;
|
||||
if (jsonString.isEmpty()) { return obj; }
|
||||
const QJsonObject jsonObj = acceptCacheJson ? Json::swiftDataObjectValue(jsonString) : Json::jsonObjectFromString(jsonString);
|
||||
obj.convertFromJson(jsonObj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
template <class DerivedObj>
|
||||
Derived JsonByMetaClass<Derived>::fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg)
|
||||
{
|
||||
success = false;
|
||||
Derived obj;
|
||||
try
|
||||
{
|
||||
DerivedObj obj;
|
||||
if (jsonString.isEmpty()) { return obj; }
|
||||
const QJsonObject jsonObj = acceptCacheJson ? Json::swiftDataObjectValue(jsonString) : Json::jsonObjectFromString(jsonString);
|
||||
obj.convertFromJson(jsonObj);
|
||||
return obj;
|
||||
success = true;
|
||||
}
|
||||
|
||||
//! Get object from JSON string
|
||||
template<class DerivedObj = Derived>
|
||||
static Derived fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg)
|
||||
catch (const CJsonException &ex)
|
||||
{
|
||||
success = false;
|
||||
Derived obj;
|
||||
try
|
||||
{
|
||||
if (jsonString.isEmpty()) { return obj; }
|
||||
const QJsonObject jsonObj = acceptCacheJson ? Json::swiftDataObjectValue(jsonString) : Json::jsonObjectFromString(jsonString);
|
||||
obj.convertFromJson(jsonObj);
|
||||
success = true;
|
||||
}
|
||||
catch (const CJsonException &ex)
|
||||
{
|
||||
errMsg = ex.toString("JSON conversion");
|
||||
}
|
||||
return obj;
|
||||
errMsg = ex.toString("JSON conversion");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
template <class Derived>
|
||||
const Derived *JsonByMetaClass<Derived>::derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
template <typename T> static QJsonObject baseToJson(const T *base) { return base->toJson(); }
|
||||
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); }
|
||||
static QJsonObject baseToJson(const void *) { return {}; }
|
||||
static void baseConvertFromJson(void *, const QJsonObject &) {}
|
||||
static QJsonObject baseToJson(const CEmpty *) { return {}; }
|
||||
static void baseConvertFromJson(CEmpty *, const QJsonObject &) {}
|
||||
};
|
||||
template <class Derived>
|
||||
Derived *JsonByMetaClass<Derived>::derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <class Derived>
|
||||
template <typename T>
|
||||
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,
|
||||
|
||||
@@ -32,40 +32,65 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! Register metadata
|
||||
static void registerMetadata()
|
||||
{
|
||||
Private::MetaTypeHelper<Derived>::maybeRegisterMetaType();
|
||||
}
|
||||
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
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
|
||||
}
|
||||
int getMetaTypeId() const;
|
||||
|
||||
//! Class name
|
||||
QString getClassName() const
|
||||
{
|
||||
return QMetaType::typeName(getMetaTypeId());
|
||||
}
|
||||
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
|
||||
{
|
||||
if (metaTypeId == QMetaType::UnknownType) { return false; }
|
||||
if (metaTypeId == getMetaTypeId()) { return true; }
|
||||
return baseIsA(static_cast<const TMetaBaseOfT<Derived> *>(derived()), metaTypeId);
|
||||
}
|
||||
bool isA(int metaTypeId) const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
Derived *derived();
|
||||
|
||||
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); }
|
||||
static bool baseIsA(const void *, int) { return false; }
|
||||
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();
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
int MetaType<Derived>::getMetaTypeId() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
QString MetaType<Derived>::getClassName() const
|
||||
{
|
||||
return QMetaType::typeName(getMetaTypeId());
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
bool MetaType<Derived>::isA(int metaTypeId) const
|
||||
{
|
||||
if (metaTypeId == QMetaType::UnknownType) { return false; }
|
||||
if (metaTypeId == getMetaTypeId()) { return true; }
|
||||
return baseIsA(static_cast<const TMetaBaseOfT<Derived> *>(derived()), metaTypeId);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
const Derived *MetaType<Derived>::derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
template <class Derived>
|
||||
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*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
|
||||
@@ -62,23 +62,41 @@ namespace BlackMisc::Mixin
|
||||
}
|
||||
|
||||
//! Cast as QString
|
||||
QString toQString(bool i18n = false) const { return derived()->convertToQString(i18n); }
|
||||
QString toQString(bool i18n = false) const;
|
||||
|
||||
//! Cast to pretty-printed QString
|
||||
//! \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
|
||||
std::string toStdString(bool i18n = false) const { return derived()->convertToQString(i18n).toStdString(); }
|
||||
std::string toStdString(bool i18n = false) const;
|
||||
|
||||
//! String for streaming operators
|
||||
QString stringForStreaming() const { return derived()->convertToQString(); }
|
||||
QString stringForStreaming() const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
const Derived *derived() const;
|
||||
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*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::String,
|
||||
|
||||
@@ -50,8 +50,7 @@ namespace BlackMisc
|
||||
void registerMetaValueType()
|
||||
{
|
||||
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 *>(converter);
|
||||
bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(Private::CValueObjectMetaInfo<T>::instance);
|
||||
Q_ASSERT(ok);
|
||||
Q_UNUSED(ok);
|
||||
}
|
||||
|
||||
@@ -142,81 +142,115 @@ namespace BlackMisc
|
||||
template <typename T>
|
||||
struct CValueObjectMetaInfo : public IValueObjectMetaInfo
|
||||
{
|
||||
virtual QString toQString(const void *object, bool i18n) const override
|
||||
{
|
||||
return cast(object).toQString(i18n);
|
||||
}
|
||||
virtual QJsonObject toJson(const void *object) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toJson(cast(object), 0);
|
||||
}
|
||||
virtual void convertFromJson(const QJsonObject &json, void *object) const override
|
||||
{
|
||||
CValueObjectMetaInfoHelper::convertFromJson(json, cast(object), 0);
|
||||
}
|
||||
virtual QJsonObject toMemoizedJson(const void *object) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toMemoizedJson(cast(object), 0);
|
||||
}
|
||||
virtual void convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const override
|
||||
{
|
||||
CValueObjectMetaInfoHelper::convertFromMemoizedJson(json, cast(object), allowFallbackToJson, 0);
|
||||
}
|
||||
virtual void unmarshall(const QDBusArgument &arg, void *object) const override
|
||||
{
|
||||
arg >> cast(object);
|
||||
}
|
||||
virtual uint getValueHash(const void *object) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::getValueHash(cast(object), 0);
|
||||
}
|
||||
virtual int getMetaTypeId() const override
|
||||
{
|
||||
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } else { return QMetaType::UnknownType; }
|
||||
}
|
||||
virtual const void *upCastTo(const void *object, int metaTypeId) 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);
|
||||
}
|
||||
template <typename T> QJsonObject CValueObjectMetaInfo<T>::toJson(const void *object) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toJson(cast(object), 0);
|
||||
}
|
||||
template <typename T> void CValueObjectMetaInfo<T>::convertFromJson(const QJsonObject &json, void *object) const
|
||||
{
|
||||
CValueObjectMetaInfoHelper::convertFromJson(json, cast(object), 0);
|
||||
}
|
||||
template <typename T> QJsonObject CValueObjectMetaInfo<T>::toMemoizedJson(const void *object) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toMemoizedJson(cast(object), 0);
|
||||
}
|
||||
template <typename T> void CValueObjectMetaInfo<T>::convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const
|
||||
{
|
||||
CValueObjectMetaInfoHelper::convertFromMemoizedJson(json, cast(object), allowFallbackToJson, 0);
|
||||
}
|
||||
template <typename T> void CValueObjectMetaInfo<T>::unmarshall(const QDBusArgument &arg, void *object) const
|
||||
{
|
||||
arg >> cast(object);
|
||||
}
|
||||
template <typename T> uint CValueObjectMetaInfo<T>::getValueHash(const void *object) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::getValueHash(cast(object), 0);
|
||||
}
|
||||
template <typename T> int CValueObjectMetaInfo<T>::getMetaTypeId() const
|
||||
{
|
||||
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); } else { return QMetaType::UnknownType; }
|
||||
}
|
||||
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)));
|
||||
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
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::compareImpl(cast(lhs), cast(rhs), 0);
|
||||
}
|
||||
virtual void setPropertyByIndex(void *object, const QVariant &variant, CPropertyIndexRef index) const override
|
||||
{
|
||||
CValueObjectMetaInfoHelper::setPropertyByIndex(cast(object), variant, index, 0);
|
||||
}
|
||||
virtual void propertyByIndex(const void *object, QVariant &o_variant, BlackMisc::CPropertyIndexRef index) const override
|
||||
{
|
||||
CValueObjectMetaInfoHelper::propertyByIndex(o_variant, cast(object), index, 0);
|
||||
}
|
||||
virtual bool equalsPropertyByIndex(const void *object, const QVariant &compareValue, CPropertyIndexRef index) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::equalsPropertyByIndex(cast(object), compareValue, index, 0);
|
||||
}
|
||||
virtual int toIcon(const void *object) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toIcon(cast(object), 0);
|
||||
}
|
||||
virtual bool matches(const void *object, const CVariant &value) const override
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::matches(cast(object), value, 0);
|
||||
}
|
||||
|
||||
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>
|
||||
else { Q_UNUSED(metaTypeId); return object; }
|
||||
}
|
||||
template <typename T> int CValueObjectMetaInfo<T>::compareImpl(const void *lhs, const void *rhs) const
|
||||
{
|
||||
const void *upCastTo(const void *, int) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
return CValueObjectMetaInfoHelper::compareImpl(cast(lhs), cast(rhs), 0);
|
||||
}
|
||||
template <typename T> void CValueObjectMetaInfo<T>::setPropertyByIndex(void *object, const QVariant &variant, CPropertyIndexRef index) const
|
||||
{
|
||||
CValueObjectMetaInfoHelper::setPropertyByIndex(cast(object), variant, index, 0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
template <typename T> bool CValueObjectMetaInfo<T>::equalsPropertyByIndex(const void *object, const QVariant &compareValue, CPropertyIndexRef index) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::equalsPropertyByIndex(cast(object), compareValue, index, 0);
|
||||
}
|
||||
template <typename T> int CValueObjectMetaInfo<T>::toIcon(const void *object) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::toIcon(cast(object), 0);
|
||||
}
|
||||
template <typename T> bool CValueObjectMetaInfo<T>::matches(const void *object, const CVariant &value) const
|
||||
{
|
||||
return CValueObjectMetaInfoHelper::matches(cast(object), value, 0);
|
||||
}
|
||||
template <typename T> const T &CValueObjectMetaInfo<T>::cast(const void *object)
|
||||
{
|
||||
return *static_cast<const T *>(object);
|
||||
}
|
||||
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.
|
||||
IValueObjectMetaInfo *getValueObjectMetaInfo(int typeId);
|
||||
@@ -242,19 +276,22 @@ namespace BlackMisc
|
||||
if constexpr (QMetaTypeId<T>::Defined) { return qMetaTypeId<T>(); }
|
||||
else { return QMetaType::UnknownType; }
|
||||
}
|
||||
static void maybeRegisterMetaType()
|
||||
{
|
||||
if constexpr (QMetaTypeId<T>::Defined)
|
||||
{
|
||||
qRegisterMetaType<T>();
|
||||
qDBusRegisterMetaType<T>();
|
||||
qRegisterMetaTypeStreamOperators<T>();
|
||||
registerMetaValueType<T>();
|
||||
maybeRegisterMetaList();
|
||||
}
|
||||
}
|
||||
static void maybeRegisterMetaType();
|
||||
static void maybeRegisterMetaList();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void MetaTypeHelper<T>::maybeRegisterMetaType()
|
||||
{
|
||||
if constexpr (QMetaTypeId<T>::Defined)
|
||||
{
|
||||
qRegisterMetaType<T>();
|
||||
qDBusRegisterMetaType<T>();
|
||||
qRegisterMetaTypeStreamOperators<T>();
|
||||
registerMetaValueType<T>();
|
||||
maybeRegisterMetaList();
|
||||
}
|
||||
};
|
||||
//! \endcond
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user