refs #210 added jsonName in Private::Attribute

* Explicit JSON name can be set for tuple members
* Names can still be extracted by preprocessor stringification if not explicitly set
* In both cases, names are embedded in Attribute metadata, so no need to call jsonMembers() in the value classes
This commit is contained in:
Mathew Sutcliffe
2014-06-18 23:46:31 +01:00
parent 11824206a1
commit fbb89375da
2 changed files with 83 additions and 5 deletions

View File

@@ -63,11 +63,13 @@
static auto toMetaTuple(const T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static auto toMetaTuple(T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static const Parser &parser() \
@@ -111,11 +113,13 @@
static auto toMetaTuple(const T<U...> &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static auto toMetaTuple(T<U...> &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static const Parser &parser() \
@@ -169,11 +173,23 @@ namespace BlackMisc
}
//! \brief Create a tuple element with attached metadata.
//! @{
template <class T, quint64 F>
static Private::Attribute<T, F> attr(T &obj, std::integral_constant<quint64, F>)
{
return { obj };
}
template <class T>
static Private::Attribute<T> attr(T &obj, QString jsonName)
{
return { obj, jsonName };
}
template <class T, quint64 F>
static Private::Attribute<T, F> attr(T &obj, QString jsonName, std::integral_constant<quint64, F>)
{
return { obj, jsonName };
}
//! @}
//! \brief Helper class which parses the stringified macro argument.
struct Parser
@@ -181,6 +197,14 @@ namespace BlackMisc
Parser(QString); //!< Constructor.
QStringList m_raw; //!< The raw macro argument, split by top-level commas.
QStringList m_names; //!< The names of the tuple members, stripped of any o.m_ prefix.
//! Fills in any incomplete metadata in a tuple using information from the Parser.
template <class Tu>
void extendMetaTuple(Tu &&tu) const
{
Private::extendMeta(std::forward<Tu>(tu), m_names,
Private::make_index_sequence<std::tuple_size<typename std::decay<Tu>::type>::value>());
}
};
};
@@ -233,6 +257,7 @@ namespace BlackMisc
/*!
* \name Static Private Member Functions
* \brief Returns a list of the names of the tuple members.
* \deprecated This information is now embedded in the meta tuples.
*/
static const QStringList &jsonMembers();
};
@@ -339,6 +364,7 @@ namespace BlackMisc
/*!
* \brief Convert to a JSON object
* \ingroup Tuples
* \deprecated The QStringList members can be embedded in tuple metadata.
*/
template <class... Ts>
QJsonObject serializeJson(const QStringList &members, std::tuple<Ts...> tu)
@@ -353,6 +379,7 @@ namespace BlackMisc
/*!
* \brief Convert from JSON to object
* \ingroup Tuples
* \deprecated The QStringList members can be embedded in tuple metadata.
*/
template <class... Ts>
void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple<Ts...> tu)
@@ -362,6 +389,30 @@ namespace BlackMisc
Private::TupleHelper::deserializeJson(json, members, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForJson>(metaTu));
}
/*!
* \brief Convert to a JSON object
* \ingroup Tuples
*/
template <class... Ts>
QJsonObject serializeJson(std::tuple<Ts...> tu)
{
QJsonObject json;
Private::assertMeta<std::tuple<Ts...>>();
Private::TupleHelper::serializeJson(json, tu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForJson>(tu));
return json;
}
/*!
* \brief Convert from JSON to object
* \ingroup Tuples
*/
template <class... Ts>
void deserializeJson(const QJsonObject &json, std::tuple<Ts...> tu)
{
Private::assertMeta<std::tuple<Ts...>>();
Private::TupleHelper::deserializeJson(json, tu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForJson>(tu));
}
} // namespace BlackMisc
#endif // guard

View File

@@ -138,8 +138,10 @@ namespace BlackMisc
typedef T type;
static const quint64 flags = Flags;
Attribute(T &obj) : m_obj(obj) {}
Attribute(T &obj, QString jsonName = {}) : m_obj(obj), m_jsonName(jsonName) {}
void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; }
T &m_obj;
QString m_jsonName;
bool operator ==(const Attribute &other) const { return m_obj == other.m_obj; }
bool operator !=(const Attribute &other) const { return m_obj != other.m_obj; }
@@ -174,6 +176,12 @@ namespace BlackMisc
return attr;
}
// Compile-time assert for functions which require a meta tuple
template <class Tu>
struct assertMeta { static_assert(std::is_void<Tu>::value, "Function expected a meta tuple, got a value tuple"); };
template <class... Ts, quint64... Fs>
struct assertMeta<std::tuple<Attribute<Ts, Fs>...>> {};
// Convert a meta tuple to a value tuple
template <class Tu, size_t... Is>
auto stripMeta(Tu &&tu, index_sequence<Is...>) -> decltype(std::make_tuple(tieHelper(std::get<Is>(std::forward<Tu>(tu)))...))
@@ -188,6 +196,13 @@ namespace BlackMisc
return std::make_tuple(tieMetaHelper(std::get<Is>(std::forward<Tu>(tu)))...);
}
// Fill in any incomplete metadata in a meta tuple, from an appropriate source
template <class Tu, size_t... Is>
void extendMeta(Tu &&tu, const QStringList &jsonNames, index_sequence<Is...>)
{
[](...){}((std::get<Is>(std::forward<Tu>(tu)).extend(jsonNames[Is]), 0)...);
}
// Applying operations to all elements in a tuple, using index_sequence for clean recursion
class TupleHelper
{
@@ -237,11 +252,23 @@ namespace BlackMisc
deserializeJsonImpl(json, std::make_pair(names[Is], get_ref<Is>(tu))...);
}
private:
template <size_t I, class T>
static auto get_ref(T &&tu) -> decltype(std::ref(std::get<I>(std::forward<T>(tu))))
template <class Tu, size_t... Is>
static void serializeJson(QJsonObject &json, const Tu &tu, index_sequence<Is...>)
{
return std::ref(std::get<I>(std::forward<T>(tu)));
serializeJsonImpl(json, std::make_pair(std::get<Is>(tu).m_jsonName, std::get<Is>(tu).m_obj)...);
}
template <class Tu, size_t... Is>
static void deserializeJson(const QJsonObject &json, Tu &tu, index_sequence<Is...>)
{
deserializeJsonImpl(json, std::make_pair(std::get<Is>(tu).m_jsonName, get_ref<Is>(tu))...);
}
private:
template <size_t I, class Tu>
static auto get_ref(Tu &&tu) -> decltype(tieHelper(std::get<I>(std::forward<Tu>(tu))))
{
return tieHelper(std::get<I>(std::forward<Tu>(tu)));
}
static int compareImpl() { return 0; }