refs #876 All metaclass mixins now directly access the metamembers.

This avoids bloating CMetaClassIntrospector with inconvenient convenience methods.
This commit is contained in:
Mathew Sutcliffe
2017-02-10 02:18:25 +00:00
parent 0e0f068471
commit 7b8d88876f
6 changed files with 30 additions and 79 deletions

View File

@@ -57,7 +57,7 @@ namespace BlackMisc
{
auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
bool result = baseEquals(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
meta.forEachMemberPair(a, b, [ & ](auto &&... args) { result = result && EqualsByMetaClass::membersEqual(std::forward<decltype(args)>(args)...); });
meta.forEachMember([ & ](auto member) { 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; }
@@ -122,7 +122,7 @@ namespace BlackMisc
auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
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));
meta.forEachMemberPair(a, b, [ & ](auto &&... args) { result = result || LessThanByMetaClass::membersLess(gt, std::forward<decltype(args)>(args)...); });
meta.forEachMember([ & ](auto member) { 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; }
@@ -158,7 +158,7 @@ namespace BlackMisc
{
auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
int result = baseCompare(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
meta.forEachMemberPair(a, b, [ & ](auto &&... args) { result = result ? result : CompareByMetaClass::membersCompare(std::forward<decltype(args)>(args)...); });
meta.forEachMember([ & ](auto member) { 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); }

View File

@@ -84,7 +84,7 @@ namespace BlackMisc
{
baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg);
auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember(*derived(), [ & ](const auto &member) { Private::marshallMember(arg, member); });
meta.forEachMember([ &, this ](auto member) { Private::marshallMember(arg, member.in(*derived())); });
}
//! Unmarshall without begin/endStructure, for when composed within another object
@@ -92,7 +92,7 @@ namespace BlackMisc
{
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember(*derived(), [ & ](auto &member) { Private::unmarshallMember(arg, member); });
meta.forEachMember([ &, this ](auto member) { Private::unmarshallMember(arg, member.in(*derived())); });
}
private:

View File

@@ -72,10 +72,12 @@ namespace BlackMisc
};
// Work around MSVC2015 bug affecting generic lambda
template <typename T>
struct Hasher
{
template <typename T>
void operator()(const T &object) { m_hash ^= qHash(object); }
template <typename U>
void operator()(const U &member) { m_hash ^= qHash(member.in(m_object)); }
const T &m_object;
uint &m_hash;
};
@@ -496,7 +498,7 @@ namespace BlackMisc
{
uint hash = baseHash(static_cast<const TBaseOfT<Derived> *>(&value));
auto meta = introspect<Derived>().without(MetaFlags<DisabledForHashing>());
meta.forEachMember(value, Private::Hasher { hash });
meta.forEachMember(Private::Hasher<Derived> { value, hash });
return hash;
}

View File

@@ -355,9 +355,9 @@ namespace BlackMisc
{
QJsonObject json;
auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>());
meta.forEachMemberName(*derived(), [ & ](const auto & member, CExplicitLatin1String name)
meta.forEachMember([ &, this ](auto member)
{
json << std::make_pair(name.toJsonKey(), std::cref(member));
json << std::make_pair(CExplicitLatin1String(member.latin1Name()).toJsonKey(), std::cref(member.in(*derived())));
});
return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived())));
}
@@ -374,18 +374,18 @@ namespace BlackMisc
{
baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json);
auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>());
meta.forEachMemberName(*derived(), [ & ](auto & member, CExplicitLatin1String name)
meta.forEachMember([ &, this ](auto member)
{
const auto value = json.value(name);
const auto value = json.value(CExplicitLatin1String(member.latin1Name()));
if (value.isUndefined())
{
constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system
if (required) { throw CJsonException(QStringLiteral("Missing required member '%1'").arg(name.m_latin1)); }
if (required) { throw CJsonException(QStringLiteral("Missing required member '%1'").arg(member.latin1Name())); }
}
else
{
CJsonScope scope(name.m_latin1);
value >> member;
CJsonScope scope(member.latin1Name());
value >> member.in(*derived());
}
});
}

View File

@@ -223,57 +223,16 @@ namespace BlackMisc
template <typename Flags>
static auto without(Flags) { return filter(MaskSequence<(! members().at(index<Is>()).has(Flags()))...>()); }
//! For each member in object, pass member as argument to visitor function.
//! @{
//! For each metamember in metaclass, pass metamember as argument to visitor function.
template <typename F>
static void forEachMember(T &object, F &&visitor)
static void forEachMember(F &&visitor)
{
forEachImpl([ & ](auto &&member, auto) { std::forward<F>(visitor)(member.in(object)); });
// parameter pack swallow idiom
static_cast<void>(std::initializer_list<int>
{
(static_cast<void>(std::forward<F>(visitor)(members().at(index<Is>()))), 0)...
});
}
template <typename F>
static void forEachMember(const T &object, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto) { std::forward<F>(visitor)(member.in(object)); });
}
//! @}
//! For each member in object pair, pass member pair as arguments to visitor function.
//! @{
template <typename F>
static void forEachMemberPair(T &left, T &right, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto flags) { std::forward<F>(visitor)(member.in(left), member.in(right), flags); });
}
template <typename F>
static void forEachMemberPair(const T &left, T &right, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto flags) { std::forward<F>(visitor)(member.in(left), member.in(right), flags); });
}
template <typename F>
static void forEachMemberPair(T &left, const T &right, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto flags) { std::forward<F>(visitor)(member.in(left), member.in(right), flags); });
}
template <typename F>
static void forEachMemberPair(const T &left, const T &right, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto flags) { std::forward<F>(visitor)(member.in(left), member.in(right), flags); });
}
//! @}
//! For each member in object, pass member and its name as arguments to visitor function.
//! @{
template <typename F>
static void forEachMemberName(T &object, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto) { std::forward<F>(visitor)(member.in(object), member.latin1Name()); });
}
template <typename F>
static void forEachMemberName(const T &object, F &&visitor)
{
forEachImpl([ & ](auto &&member, auto) { std::forward<F>(visitor)(member.in(object), member.latin1Name()); });
}
//! @}
private:
template <bool... Mask>
@@ -286,16 +245,6 @@ namespace BlackMisc
using index = std::integral_constant<size_t, I>;
constexpr static auto members() BLACK_TRAILING_RETURN(MetaClass::getMemberList()) { return MetaClass::getMemberList(); }
template <typename F>
static void forEachImpl(F &&visitor)
{
// parameter pack swallow idiom
static_cast<void>(std::initializer_list<int>
{
(static_cast<void>(std::forward<F>(visitor)(members().at(index<Is>()), MetaFlags<members().at(index<Is>()).m_flags>())), 0)...
});
}
};
namespace Private

View File

@@ -106,10 +106,10 @@ namespace BlackMisc
{
QJsonObject json;
auto meta = introspect<CAircraftModel>().without(MetaFlags<DisabledForJson>());
meta.forEachMemberName(*this, [ & ](const auto & member, CExplicitLatin1String name)
meta.forEachMember([ &, this ](auto member)
{
auto &&maybeMemo = helper.maybeMemoize(member);
json << std::make_pair(name.toJsonKey(), std::cref(maybeMemo));
auto &&maybeMemo = helper.maybeMemoize(member.in(*this));
json << std::make_pair(CExplicitLatin1String(member.latin1Name()).toJsonKey(), std::cref(maybeMemo));
});
return json;
}
@@ -117,10 +117,10 @@ namespace BlackMisc
void CAircraftModel::convertFromMemoizedJson(const QJsonObject &json, const MemoHelper::CUnmemoizer &helper)
{
auto meta = introspect<CAircraftModel>().without(MetaFlags<DisabledForJson>());
meta.forEachMemberName(*this, [ & ](auto & member, CExplicitLatin1String name)
meta.forEachMember([ &, this ](auto member)
{
auto it = json.find(name);
if (it != json.end()) { it.value() >> helper.maybeUnmemoize(member).get(); }
auto it = json.find(CExplicitLatin1String(member.latin1Name()));
if (it != json.end()) { it.value() >> helper.maybeUnmemoize(member.in(*this)).get(); }
});
}