From 2eb16ce9daf2fcf86056e9b7c7bb2b73f1de8f74 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Sat, 7 Jun 2014 21:39:25 +0100 Subject: [PATCH] refs #245 & #210 with proper variadic templates we can use index_sequence to simplify some of the recursion in the tuple system --- src/blackmisc/tuple.h | 14 +-- src/blackmisc/tuple_private.h | 156 ++++++++++++++++++++++++---------- 2 files changed, 116 insertions(+), 54 deletions(-) diff --git a/src/blackmisc/tuple.h b/src/blackmisc/tuple.h index 28e5d2349..f1ab2d34a 100644 --- a/src/blackmisc/tuple.h +++ b/src/blackmisc/tuple.h @@ -181,7 +181,7 @@ namespace BlackMisc template int compare(std::tuple a, std::tuple b) { - return Private::TupleHelper::compare(a, b); + return Private::TupleHelper::compare(a, b, Private::make_index_sequence()); } /*! @@ -191,7 +191,7 @@ namespace BlackMisc template QDBusArgument &operator <<(QDBusArgument &arg, std::tuple tu) { - return Private::TupleHelper::marshall(arg, tu); + return Private::TupleHelper::marshall(arg, tu, Private::make_index_sequence()); } /*! @@ -201,7 +201,7 @@ namespace BlackMisc template const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple tu) { - return Private::TupleHelper::unmarshall(arg, tu); + return Private::TupleHelper::unmarshall(arg, tu, Private::make_index_sequence()); } /*! @@ -211,7 +211,7 @@ namespace BlackMisc template QDebug operator <<(QDebug debug, std::tuple tu) { - return Private::TupleHelper::debug(debug, tu); + return Private::TupleHelper::debug(debug, tu, Private::make_index_sequence()); } /*! @@ -232,7 +232,7 @@ namespace BlackMisc template uint qHash(std::tuple tu) { - return Private::TupleHelper::hash(tu); + return Private::TupleHelper::hash(tu, Private::make_index_sequence()); } /*! @@ -243,7 +243,7 @@ namespace BlackMisc QJsonObject serializeJson(const QStringList &members, std::tuple tu) { QJsonObject json; - Private::TupleHelper::serializeJson(json, members, tu); + Private::TupleHelper::serializeJson(json, members, tu, Private::make_index_sequence()); return json; } @@ -254,7 +254,7 @@ namespace BlackMisc template void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple tu) { - Private::TupleHelper::deserializeJson(json, members, tu); + Private::TupleHelper::deserializeJson(json, members, tu, Private::make_index_sequence()); } } // namespace BlackMisc diff --git a/src/blackmisc/tuple_private.h b/src/blackmisc/tuple_private.h index f5b78ed0f..8e2befe2e 100644 --- a/src/blackmisc/tuple_private.h +++ b/src/blackmisc/tuple_private.h @@ -73,6 +73,29 @@ namespace BlackMisc } //! @} + // Our own implementation of std::index_sequence (because not implemented by MSVC2013) + //! \private + //! @{ + template + struct index_sequence + { + static const size_t size = sizeof...(Is); + typedef std::tuple...> tuple_type; + }; + template + struct GenSequence + { + typedef typename GenSequence::type type; + }; + template + struct GenSequence + { + typedef index_sequence type; + }; + template + using make_index_sequence = typename GenSequence<0, C>::type; + //! @} + // Helper which will allow us to hook in our own customizations into BlackMisc::tie //! \private //! @{ @@ -83,76 +106,115 @@ namespace BlackMisc } //! @} - // Applying operations to all elements in a tuple, using recursion + // Applying operations to all elements in a tuple, using index_sequence instead of recursion //! \private - template - struct TupleHelper + class TupleHelper { - template - static int compare(const Tu &a, const Tu &b) + public: + template + static int compare(const Tu &a, const Tu &b, index_sequence) { - const int head = TupleHelper < N - 1 >::compare(a, b); - if (head) { return head; } - return compareHelper < N - 1 > (a, b); + return compareImpl(std::make_pair(get_ref(a), get_ref(b))...); } - template - static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu) + template + static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu, index_sequence) { - return TupleHelper < N - 1 >::marshall(arg, tu) << std::get < N - 1 > (tu); + marshallImpl(arg, std::get(tu)...); + return arg; } - template - static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu) + template + static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu, index_sequence) { - return TupleHelper < N - 1 >::unmarshall(arg, tu) >> std::get < N - 1 > (tu); + unmarshallImpl(arg, std::get(tu)...); + return arg; } - template - static QDebug debug(QDebug dbg, Tu &tu) + template + static QDebug debug(QDebug dbg, const Tu &tu, index_sequence) { - return TupleHelper < N - 1 >::debug(dbg, tu) << std::get < N - 1 > (tu); + debugImpl(dbg, std::get(tu)...); + return dbg; } - template - static uint hash(const Tu &tu) + template + static uint hash(const Tu &tu, index_sequence) { - return TupleHelper < N - 1 >::hash(tu) ^ qHash(std::get < N - 1 > (tu)); + return hashImpl(qHash(std::get(tu))...); } - template - static void serializeJson(QJsonObject &json, const QStringList &members, const Tu &tu) + template + static void serializeJson(QJsonObject &json, const QStringList &names, const Tu &tu, index_sequence) { - TupleHelper < N - 1 >::serializeJson(json, members, tu); - json << std::make_pair(members.at(N - 1), std::get < N - 1 >(tu)); + serializeJsonImpl(json, std::make_pair(names[Is], std::get(tu))...); } - template - static void deserializeJson(const QJsonObject &json, const QStringList &members, Tu &tu) + template + static void deserializeJson(const QJsonObject &json, const QStringList &names, Tu &tu, index_sequence) { - TupleHelper < N - 1 >::deserializeJson(json, members, tu); - json.value(members.at(N - 1)) >> std::get < N - 1 >(tu); + deserializeJsonImpl(json, std::make_pair(names[Is], get_ref(tu))...); } - }; - //! \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 &) {} + private: + template + static auto get_ref(T &&tu) -> decltype(std::ref(std::get(std::forward(tu)))) + { + return std::ref(std::get(std::forward(tu))); + } + + static int compareImpl() { return 0; } + template + static int compareImpl(const std::pair &head, const Ts &... tail) + { + int result = compareHelper(head.first, head.second, typename std::is_base_of::type>::type()); + if (result) return result; + return compareImpl(tail...); + } + + static void marshallImpl(QDBusArgument &) {} + template + static void marshallImpl(QDBusArgument &arg, const T &head, const Ts &... tail) + { + arg << head; + marshallImpl(arg, tail...); + } + + static void unmarshallImpl(const QDBusArgument &) {} + template + static void unmarshallImpl(const QDBusArgument &arg, T &head, Ts &... tail) + { + arg >> head; + unmarshallImpl(arg, tail...); + } + + static void debugImpl(QDebug) {} + template + static void debugImpl(QDebug dbg, const T &head, const Ts &... tail) + { + dbg << head; + debugImpl(dbg, tail...); + } + + static void serializeJsonImpl(QJsonObject &) {} + template + static void serializeJsonImpl(QJsonObject &json, std::pair head, Ts... tail) + { + json << head; + serializeJsonImpl(json, tail...); + } + + static void deserializeJsonImpl(const QJsonObject &) {} + template + static void deserializeJsonImpl(const QJsonObject &json, std::pair head, Ts... tail) + { + json.value(head.first) >> head.second; + deserializeJsonImpl(json, tail...); + } + + static uint hashImpl() { return 0; } + template + static uint hashImpl(uint head, Ts... tail) { return head ^ hashImpl(tail...); } }; } // namespace Private