/* Copyright (C) 2014 VATSIM Community / authors * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /*! \file Private implementation details used by tuple.h */ #ifndef BLACKMISC_TUPLE_PRIVATE_H #define BLACKMISC_TUPLE_PRIVATE_H #include #include #include #include #include #include #include #include #include #include #include namespace BlackMisc { class CValueObject; namespace Private { #ifdef Q_COMPILER_VARIADIC_TEMPLATES // Helper trait to detect whether a class is a tuple. //! \private //! @{ template struct IsTuple : public std::false_type {}; template struct IsTuple> : public std::true_type {}; //! @} #else // !Q_COMPILER_VARIADIC_TEMPLATES template struct IsTuple : public std::false_type {}; template <> struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; template struct IsTuple> : public std::true_type {}; #endif // !Q_COMPILER_VARIADIC_TEMPLATES // Using SFINAE to help detect missing BLACK_ENABLE_TUPLE_CONVERSION macro in static_assert //! \private std::false_type hasEnabledTupleConversionHelper(...); //! \private template typename T::EnabledTupleConversion hasEnabledTupleConversionHelper(T *); //! \private template struct HasEnabledTupleConversion { typedef decltype(hasEnabledTupleConversionHelper(static_cast(nullptr))) type; static const bool value = type::value; }; // Using tag dispatch to select which implementation of compare() to use //! \private //! @{ template int compareHelper(const T &a, const T &b, std::true_type isCValueObjectTag) { Q_UNUSED(isCValueObjectTag); return compare(a, b); } template int compareHelper(const T &a, const T &b, std::false_type isCValueObjectTag) { Q_UNUSED(isCValueObjectTag); if (a < b) { return -1; } if (a > b) { return 1; } return 0; } template int compareHelper(const Tu &a, const Tu &b) { typedef typename std::decay::type>::type Element; typedef std::integral_constant::value || IsTuple::value> isCValueObjectTag; return compareHelper(std::get(a), std::get(b), isCValueObjectTag()); } //! @} // Helper which returns a copy of its argument if it's a tuple, // otherwise returns a reference to its argument. //! \private //! @{ template auto tieHelper(T &obj, std::false_type isTupleTag) -> std::reference_wrapper { Q_UNUSED(isTupleTag); return obj; } template auto tieHelper(T &obj, std::true_type isTupleTag) -> T { Q_UNUSED(isTupleTag); return obj; } template auto tieHelper(T &obj) -> decltype(tieHelper(obj, IsTuple())) { return tieHelper(obj, IsTuple()); } //! @} // Helper which (de)serializes its argument to/from JSON, // whether it is a simple value or a nested tuple. // Defined later because it uses TupleHelper; // forward-declared because TupleHelper uses it. //! \private //! @{ template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index, std::false_type isNestedTag); template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index, std::true_type isNestedTag); template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index); template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index, std::false_type isNestedTag); template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index, std::true_type isNestedTag); template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index); //! @} // Applying operations to all elements in a tuple, using recursion //! \private template struct TupleHelper { template static int compare(const Tu &a, const Tu &b) { const int head = TupleHelper < N - 1 >::compare(a, b); if (head) { return head; } return compareHelper < N - 1 > (a, b); } template static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu) { return TupleHelper < N - 1 >::marshall(arg, tu) << std::get < N - 1 > (tu); } template static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu) { return TupleHelper < N - 1 >::unmarshall(arg, tu) >> std::get < N - 1 > (tu); } template static QDebug debug(QDebug dbg, Tu &tu) { return TupleHelper < N - 1 >::debug(dbg, tu) << std::get < N - 1 > (tu); } template static uint hash(const Tu &tu) { return TupleHelper < N - 1 >::hash(tu) ^ qHash(std::get < N - 1 > (tu)); } template static void serializeJson(QJsonObject &json, const QStringList &members, const Tu &tu) { TupleHelper < N - 1 >::serializeJson(json, members, tu); serializeJsonHelper(json, members, std::get < N - 1 > (tu), N - 1); } template static void deserializeJson(const QJsonObject &json, const QStringList &members, Tu &tu) { TupleHelper < N - 1 >::deserializeJson(json, members, tu); deserializeJsonHelper(json, members, std::get < N - 1 > (tu), N - 1); } }; //! \private template <> struct TupleHelper<0> { template static int compare(const Tu &, const Tu &) { return 0; } template static QDBusArgument &marshall(QDBusArgument &arg, const Tu &) { return arg; } template static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &) { return arg; } template static QDebug debug(QDebug dbg, Tu &) { return dbg; } template static uint hash(const Tu &) { return 0; } template static void serializeJson(QJsonObject &, const QStringList &, const Tu &) {} template static void deserializeJson(const QJsonObject &, const QStringList &, Tu &) {} }; // definitions of helpers declared earlier template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index, std::false_type isNestedTag) { Q_UNUSED(isNestedTag); json << std::make_pair(members.at(index), obj); } template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index, std::true_type isNestedTag) { Q_UNUSED(isNestedTag); TupleHelper::value>::serializeJson(json, members.mid(index), obj); } template static void serializeJsonHelper(QJsonObject &json, const QStringList &members, const T &obj, int index) { serializeJsonHelper(json, members, obj, index, IsTuple()); } template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index, std::false_type isNestedTag) { Q_UNUSED(isNestedTag); json.value(members.at(index)) >> obj; } template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index, std::true_type isNestedTag) { Q_UNUSED(isNestedTag); TupleHelper::value>::deserializeJson(json, members.mid(index), obj); } template static void deserializeJsonHelper(const QJsonObject &json, const QStringList &members, T &obj, int index) { deserializeJsonHelper(json, members, obj, index, IsTuple()); } } // namespace Private } // namespace BlackMisc #endif // guard