refs #245 & #210 with proper variadic templates we can use index_sequence to simplify some of the recursion in the tuple system

This commit is contained in:
Mathew Sutcliffe
2014-06-07 21:39:25 +01:00
parent 5d38812482
commit 2eb16ce9da
2 changed files with 116 additions and 54 deletions

View File

@@ -181,7 +181,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b) int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
{ {
return Private::TupleHelper<sizeof...(Ts)>::compare(a, b); return Private::TupleHelper::compare(a, b, Private::make_index_sequence<sizeof...(Ts)>());
} }
/*! /*!
@@ -191,7 +191,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
QDBusArgument &operator <<(QDBusArgument &arg, std::tuple<Ts...> tu) QDBusArgument &operator <<(QDBusArgument &arg, std::tuple<Ts...> tu)
{ {
return Private::TupleHelper<sizeof...(Ts)>::marshall(arg, tu); return Private::TupleHelper::marshall(arg, tu, Private::make_index_sequence<sizeof...(Ts)>());
} }
/*! /*!
@@ -201,7 +201,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple<Ts...> tu) const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple<Ts...> tu)
{ {
return Private::TupleHelper<sizeof...(Ts)>::unmarshall(arg, tu); return Private::TupleHelper::unmarshall(arg, tu, Private::make_index_sequence<sizeof...(Ts)>());
} }
/*! /*!
@@ -211,7 +211,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
QDebug operator <<(QDebug debug, std::tuple<Ts &...> tu) QDebug operator <<(QDebug debug, std::tuple<Ts &...> tu)
{ {
return Private::TupleHelper<sizeof...(Ts)>::debug(debug, tu); return Private::TupleHelper::debug(debug, tu, Private::make_index_sequence<sizeof...(Ts)>());
} }
/*! /*!
@@ -232,7 +232,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
uint qHash(std::tuple<Ts...> tu) uint qHash(std::tuple<Ts...> tu)
{ {
return Private::TupleHelper<sizeof...(Ts)>::hash(tu); return Private::TupleHelper::hash(tu, Private::make_index_sequence<sizeof...(Ts)>());
} }
/*! /*!
@@ -243,7 +243,7 @@ namespace BlackMisc
QJsonObject serializeJson(const QStringList &members, std::tuple<Ts...> tu) QJsonObject serializeJson(const QStringList &members, std::tuple<Ts...> tu)
{ {
QJsonObject json; QJsonObject json;
Private::TupleHelper<sizeof...(Ts)>::serializeJson(json, members, tu); Private::TupleHelper::serializeJson(json, members, tu, Private::make_index_sequence<sizeof...(Ts)>());
return json; return json;
} }
@@ -254,7 +254,7 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple<Ts...> tu) void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple<Ts...> tu)
{ {
Private::TupleHelper<sizeof...(Ts)>::deserializeJson(json, members, tu); Private::TupleHelper::deserializeJson(json, members, tu, Private::make_index_sequence<sizeof...(Ts)>());
} }
} // namespace BlackMisc } // namespace BlackMisc

View File

@@ -73,6 +73,29 @@ namespace BlackMisc
} }
//! @} //! @}
// Our own implementation of std::index_sequence (because not implemented by MSVC2013)
//! \private
//! @{
template <size_t... Is>
struct index_sequence
{
static const size_t size = sizeof...(Is);
typedef std::tuple<std::integral_constant<size_t, Is>...> tuple_type;
};
template <size_t I, size_t C, size_t... Is>
struct GenSequence
{
typedef typename GenSequence<I + 1, C, Is..., I>::type type;
};
template <size_t C, size_t... Is>
struct GenSequence<C, C, Is...>
{
typedef index_sequence<Is...> type;
};
template <size_t C>
using make_index_sequence = typename GenSequence<0, C>::type;
//! @}
// Helper which will allow us to hook in our own customizations into BlackMisc::tie // Helper which will allow us to hook in our own customizations into BlackMisc::tie
//! \private //! \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 //! \private
template <int N> class TupleHelper
struct TupleHelper
{ {
template <class Tu> public:
static int compare(const Tu &a, const Tu &b) template <class Tu, size_t... Is>
static int compare(const Tu &a, const Tu &b, index_sequence<Is...>)
{ {
const int head = TupleHelper < N - 1 >::compare(a, b); return compareImpl(std::make_pair(get_ref<Is>(a), get_ref<Is>(b))...);
if (head) { return head; }
return compareHelper < N - 1 > (a, b);
} }
template <class Tu> template <class Tu, size_t... Is>
static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu) static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu, index_sequence<Is...>)
{ {
return TupleHelper < N - 1 >::marshall(arg, tu) << std::get < N - 1 > (tu); marshallImpl(arg, std::get<Is>(tu)...);
return arg;
} }
template <class Tu> template <class Tu, size_t... Is>
static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu) static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu, index_sequence<Is...>)
{ {
return TupleHelper < N - 1 >::unmarshall(arg, tu) >> std::get < N - 1 > (tu); unmarshallImpl(arg, std::get<Is>(tu)...);
return arg;
} }
template <class Tu> template <class Tu, size_t... Is>
static QDebug debug(QDebug dbg, Tu &tu) static QDebug debug(QDebug dbg, const Tu &tu, index_sequence<Is...>)
{ {
return TupleHelper < N - 1 >::debug(dbg, tu) << std::get < N - 1 > (tu); debugImpl(dbg, std::get<Is>(tu)...);
return dbg;
} }
template <class Tu> template <class Tu, size_t... Is>
static uint hash(const Tu &tu) static uint hash(const Tu &tu, index_sequence<Is...>)
{ {
return TupleHelper < N - 1 >::hash(tu) ^ qHash(std::get < N - 1 > (tu)); return hashImpl(qHash(std::get<Is>(tu))...);
} }
template <class Tu> template <class Tu, size_t... Is>
static void serializeJson(QJsonObject &json, const QStringList &members, const Tu &tu) static void serializeJson(QJsonObject &json, const QStringList &names, const Tu &tu, index_sequence<Is...>)
{ {
TupleHelper < N - 1 >::serializeJson(json, members, tu); serializeJsonImpl(json, std::make_pair(names[Is], std::get<Is>(tu))...);
json << std::make_pair(members.at(N - 1), std::get < N - 1 >(tu));
} }
template <class Tu> template <class Tu, size_t... Is>
static void deserializeJson(const QJsonObject &json, const QStringList &members, Tu &tu) static void deserializeJson(const QJsonObject &json, const QStringList &names, Tu &tu, index_sequence<Is...>)
{ {
TupleHelper < N - 1 >::deserializeJson(json, members, tu); deserializeJsonImpl(json, std::make_pair(names[Is], get_ref<Is>(tu))...);
json.value(members.at(N - 1)) >> std::get < N - 1 >(tu);
} }
};
//! \private private:
template <> template <size_t I, class T>
struct TupleHelper<0> static auto get_ref(T &&tu) -> decltype(std::ref(std::get<I>(std::forward<T>(tu))))
{ {
template <class Tu> return std::ref(std::get<I>(std::forward<T>(tu)));
static int compare(const Tu &, const Tu &) { return 0; } }
template <class Tu>
static QDBusArgument &marshall(QDBusArgument &arg, const Tu &) { return arg; } static int compareImpl() { return 0; }
template <class Tu> template <class T, class... Ts>
static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &) { return arg; } static int compareImpl(const std::pair<T, T> &head, const Ts &... tail)
template <class Tu> {
static QDebug debug(QDebug dbg, Tu &) { return dbg; } int result = compareHelper(head.first, head.second, typename std::is_base_of<CValueObject, typename std::decay<T>::type>::type());
template <class Tu> if (result) return result;
static uint hash(const Tu &) { return 0; } return compareImpl(tail...);
template <class Tu> }
static void serializeJson(QJsonObject &, const QStringList &, const Tu &) {}
template <class Tu> static void marshallImpl(QDBusArgument &) {}
static void deserializeJson(const QJsonObject &, const QStringList &, Tu &) {} template <class T, class... Ts>
static void marshallImpl(QDBusArgument &arg, const T &head, const Ts &... tail)
{
arg << head;
marshallImpl(arg, tail...);
}
static void unmarshallImpl(const QDBusArgument &) {}
template <class T, class... Ts>
static void unmarshallImpl(const QDBusArgument &arg, T &head, Ts &... tail)
{
arg >> head;
unmarshallImpl(arg, tail...);
}
static void debugImpl(QDebug) {}
template <class T, class... Ts>
static void debugImpl(QDebug dbg, const T &head, const Ts &... tail)
{
dbg << head;
debugImpl(dbg, tail...);
}
static void serializeJsonImpl(QJsonObject &) {}
template <class T, class... Ts>
static void serializeJsonImpl(QJsonObject &json, std::pair<QString, T> head, Ts... tail)
{
json << head;
serializeJsonImpl(json, tail...);
}
static void deserializeJsonImpl(const QJsonObject &) {}
template <class T, class... Ts>
static void deserializeJsonImpl(const QJsonObject &json, std::pair<QString, T> head, Ts... tail)
{
json.value(head.first) >> head.second;
deserializeJsonImpl(json, tail...);
}
static uint hashImpl() { return 0; }
template <class... Ts>
static uint hashImpl(uint head, Ts... tail) { return head ^ hashImpl(tail...); }
}; };
} // namespace Private } // namespace Private