refs #628 Remove the old tuple system.

This commit is contained in:
Mathew Sutcliffe
2016-04-02 19:18:08 +01:00
parent 4bd4baa535
commit 0acb302c63
14 changed files with 23 additions and 1066 deletions

View File

@@ -12,13 +12,14 @@
#ifndef BLACKMISC_COMPARE_H
#define BLACKMISC_COMPARE_H
#include "blackmisc/tuple.h"
#include "blackmisc/metaclass.h"
#include "blackmisc/inheritancetraits.h"
#include "blackmisc/typetraits.h"
namespace BlackMisc
{
class CEmpty;
//! \cond PRIVATE
namespace Private
{
@@ -61,10 +62,9 @@ namespace BlackMisc
* Lexicographically compare two tuples and return negative, positive, or zero,
* if a is less than, greater than, or equal to b.
* Each element is compared with compare(a', b') if supported by the element type, operator less-than otherwise.
* \todo Rename to compare() after removing tuple.h, which contains a function with the same name and signature.
*/
template <typename... Ts, typename... Us>
int compareTuples(const std::tuple<Ts...> &a, const std::tuple<Us...> &b)
int compare(const std::tuple<Ts...> &a, const std::tuple<Us...> &b)
{
static_assert(sizeof...(Ts) == sizeof...(Us), "tuples must be same size");
return Private::CompareHelper<sizeof...(Ts)>::compareTuples(a, b);
@@ -89,29 +89,6 @@ namespace BlackMisc
friend bool operator !=(const Derived &a, const Derived &b) { return compare(a, b) != 0; }
};
/*!
* CRTP class template from which a derived class can inherit operator== implemented by metatuple.
*/
template <class Derived>
class EqualsByTuple : private Private::EncapsulationBreaker
{
public:
//! Equals
friend bool operator ==(const Derived &a, const Derived &b) { return equals(a, b); }
//! Not equal
friend bool operator !=(const Derived &a, const Derived &b) { return ! equals(a, b); }
private:
static bool equals(const Derived &a, const Derived &b)
{
return toMetaTuple(a) == toMetaTuple(b) && baseEquals(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
}
template <typename T> static bool baseEquals(const T *a, const T *b) { return *a == *b; }
static bool baseEquals(const void *, const void *) { return true; }
static bool baseEquals(const CEmpty *, const CEmpty *) { return true; }
};
/*!
* CRTP class template from which a derived class can inherit operator== implemented by metaclass.
*/
@@ -158,36 +135,6 @@ namespace BlackMisc
friend bool operator >=(const Derived &a, const Derived &b) { return compare(a, b) >= 0; }
};
/*!
* CRTP class template from which a derived class can inherit operator< implemented by metatuple.
*/
template <class Derived>
class LessThanByTuple : private Private::EncapsulationBreaker
{
public:
//! Less than
friend bool operator <(const Derived &a, const Derived &b) { return less(a, b); }
//! Greater than
friend bool operator >(const Derived &a, const Derived &b) { return less(b, a); }
//! Less than or equal
friend bool operator <=(const Derived &a, const Derived &b) { return ! less(b, a); }
//! Greater than or equal
friend bool operator >=(const Derived &a, const Derived &b) { return ! less(a, b); }
private:
static bool less(const Derived &a, const Derived &b)
{
if (baseLess(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b))) { return true; }
return toMetaTuple(a) < toMetaTuple(b);
}
template <typename T> static bool baseLess(const T *a, const T *b) { return *a < *b; }
static bool baseLess(const void *, const void *) { return false; }
static bool baseLess(const CEmpty *, const CEmpty *) { return false; }
};
/*!
* CRTP class template from which a derived class can inherit operator< implemented by metaclass.
*/
@@ -219,30 +166,6 @@ namespace BlackMisc
static bool baseLess(const CEmpty *, const CEmpty *) { return false; }
};
/*!
* CRTP class template from which a derived class can inherit non-member compare() implemented by metatuple.
*
* \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION.
*/
template <class Derived>
class CompareByTuple : private Private::EncapsulationBreaker
{
public:
//! Return negative, zero, or positive if a is less than, equal to, or greater than b.
friend int compare(const Derived &a, const Derived &b) { return compareImpl(a, b); }
private:
static int compareImpl(const Derived &a, const Derived &b)
{
int baseCmp = baseCompare(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
if (baseCmp) { return baseCmp; }
return BlackMisc::compare(toMetaTuple(a), toMetaTuple(b));
}
template <typename T> static int baseCompare(const T *a, const T *b) { return compare(*a, *b); }
static int baseCompare(const void *, const void *) { return 0; }
static int baseCompare(const CEmpty *, const CEmpty *) { return 0; }
};
/*!
* CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass.
*/
@@ -259,7 +182,7 @@ namespace BlackMisc
int baseCmp = baseCompare(static_cast<const BaseOfT<Derived> *>(&a), static_cast<const BaseOfT<Derived> *>(&b));
if (baseCmp) { return baseCmp; }
auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
return BlackMisc::compareTuples(meta.toCaseAwareTuple(a), meta.toCaseAwareTuple(b));
return BlackMisc::compare(meta.toCaseAwareTuple(a), meta.toCaseAwareTuple(b));
}
template <typename T> static int baseCompare(const T *a, const T *b) { return compare(*a, *b); }
static int baseCompare(const void *, const void *) { return 0; }

View File

@@ -12,7 +12,6 @@
#ifndef BLACKMISC_DBUS_H
#define BLACKMISC_DBUS_H
#include "blackmisc/tuple.h"
#include "blackmisc/metaclass.h"
#include "blackmisc/inheritancetraits.h"
#include <QDBusArgument>
@@ -20,6 +19,8 @@
namespace BlackMisc
{
class CEmpty;
namespace Mixin
{
/*!
@@ -50,45 +51,6 @@ namespace BlackMisc
}
};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metatuple.
*
* \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION.
*
* \see BLACKMISC_DECLARE_USING_MIXIN_DBUS
*/
template <class Derived>
class DBusByTuple : public DBusOperators<Derived>, private Private::EncapsulationBreaker
{
public:
//! Marshall without begin/endStructure, for when composed within another object
void marshallToDbus(QDBusArgument &arg) const
{
baseMarshall(static_cast<const BaseOfT<Derived> *>(derived()), arg);
using BlackMisc::operator<<;
arg << Private::EncapsulationBreaker::toMetaTuple(*derived());
}
//! Unmarshall without begin/endStructure, for when composed within another object
void unmarshallFromDbus(const QDBusArgument &arg)
{
baseUnmarshall(static_cast<BaseOfT<Derived> *>(derived()), arg);
using BlackMisc::operator>>;
arg >> Private::EncapsulationBreaker::toMetaTuple(*derived());
}
private:
const Derived *derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg); }
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg); }
static void baseMarshall(const void *, QDBusArgument &) {}
static void baseUnmarshall(void *, const QDBusArgument &) {}
static void baseMarshall(const CEmpty *, QDBusArgument &) {}
static void baseUnmarshall(CEmpty *, const QDBusArgument &) {}
};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metaclass.
*

View File

@@ -26,6 +26,11 @@
namespace BlackMisc
{
// Needed so that our qHash overload doesn't hide the qHash overloads in the global namespace.
// This will be safe as long as no global qHash has the same signature as ours.
// Alternative would be to qualify all our invokations of the global qHash as ::qHash.
using ::qHash;
namespace Private
{
//! \cond PRIVATE
@@ -459,32 +464,6 @@ namespace BlackMisc
namespace Mixin
{
/*!
* CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metatuple.
*
* \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION.
*/
template <class Derived>
class HashByTuple : private Private::EncapsulationBreaker
{
public:
//! qHash overload, needed for storing value in a QSet.
friend uint qHash(const Derived &value, uint seed = 0)
{
return ::qHash(hashImpl(value), seed);
}
private:
static uint hashImpl(const Derived &value)
{
return BlackMisc::qHash(toMetaTuple(value)) ^ baseHash(static_cast<const BaseOfT<Derived> *>(&value));
}
template <typename T> static uint baseHash(const T *base) { return qHash(*base); }
static uint baseHash(const void *) { return 0; }
static uint baseHash(const CEmpty *) { return 0; }
};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metaclass.
*

View File

@@ -15,7 +15,6 @@
#include "blackmiscexport.h"
#include "icons.h"
#include "variant.h"
#include "tuple.h"
#include "inheritancetraits.h"
#include "dictionary.h"
#include <QIcon>

View File

@@ -13,7 +13,6 @@
#define BLACKMISC_JSON_H
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/tuple.h"
#include "blackmisc/metaclass.h"
#include "blackmisc/inheritancetraits.h"
#include "blackmisc/fileutils.h"
@@ -146,6 +145,8 @@ BLACKMISC_EXPORT QJsonObject &operator<<(QJsonObject &json, const std::pair<QStr
namespace BlackMisc
{
class CEmpty;
namespace Json
{
//! Append to first JSON object (concatenate)
@@ -237,56 +238,6 @@ namespace BlackMisc
}
};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple.
*
* \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION.
*
* \see BLACKMISC_DECLARE_USING_MIXIN_JSON
*/
template <class Derived>
class JsonByTuple : public JsonOperators<Derived>, private Private::EncapsulationBreaker
{
public:
//! Cast to JSON object
QJsonObject toJson() const
{
QJsonObject json = BlackMisc::serializeJson(Private::EncapsulationBreaker::toMetaTuple(*derived()));
return Json::appendJsonObject(json, baseToJson(static_cast<const BaseOfT<Derived> *>(derived())));
}
//! Convenience function JSON as string
QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const
{
QJsonDocument jsonDoc(toJson());
return jsonDoc.toJson(format);
}
//! Assign from JSON object
void convertFromJson(const QJsonObject &json)
{
baseConvertFromJson(static_cast<BaseOfT<Derived> *>(derived()), json);
BlackMisc::deserializeJson(json, Private::EncapsulationBreaker::toMetaTuple(*derived()));
}
//! Assign from JSON object string
void convertFromJson(const QString &jsonString)
{
convertFromJson(BlackMisc::Json::jsonObjectFromString(jsonString));
}
private:
const Derived *derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static QJsonObject baseToJson(const T *base) { return base->toJson(); }
template <typename T> static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); }
static QJsonObject baseToJson(const void *) { return {}; }
static void baseConvertFromJson(void *, const QJsonObject &) {}
static QJsonObject baseToJson(const CEmpty *) { return {}; }
static void baseConvertFromJson(CEmpty *, const QJsonObject &) {}
};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple.
*

View File

@@ -14,7 +14,6 @@
#include "blackmisc/metaclassprivate.h"
#include "blackmisc/invoke.h"
#include "blackmisc/tuple.h" // just for TupleConverterFlags
/*!
* \defgroup MetaClass Metaclass system
@@ -77,19 +76,17 @@ namespace BlackMisc
/*!
* Metadata flags attached to members of a meta class.
* \todo Remove TupleConverterFlags and change MetaFlag to a full enum.
* \ingroup MetaClass
*/
using MetaFlag = TupleConverterFlags;
//enum MetaFlag
//{
// DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators
// DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling
// DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug
// DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash()
// DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization
// CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString)
//};
enum MetaFlag
{
DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators
DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling
DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug
DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash()
DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization
CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString)
};
/*!
* Type wrapper for passing MetaFlag to CMetaClassIntrospector::with and CMetaClassIntrospector::without.

View File

@@ -8,7 +8,6 @@
*/
#include "blackmisc/pq/pqstring.h"
#include "blackmisc/tuple.h"
#include "blackmisc/pq/pq.h"
#include <QThreadStorage>

View File

@@ -15,7 +15,6 @@
#include "variant.h"
#include "propertyindexlist.h"
#include "blackmiscexport.h"
#include "tuple.h"
#include "inheritancetraits.h"
#include <QVariantMap>
#include <QDBusArgument>

View File

@@ -1,41 +0,0 @@
/* Copyright (C) 2013
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "tuple.h"
namespace BlackMisc
{
TupleConverterBase::Parser::Parser(QString string)
{
string.remove(QRegExp("^\\s*\\(\\s*")); // remove first '('
string.remove(QRegExp("\\s*\\)\\s*$")); // remove last ')'
QString current;
int level = 0;
for (const auto c : string)
{
if (c == '(') { level++; }
if (c == ')') { level--; }
if (c == ',' && level == 0) { m_raw.push_back(current.trimmed()); current.clear(); }
else { current += c; }
}
if (! current.trimmed().isEmpty()) { m_raw.push_back(current.trimmed()); current.clear(); }
for (const auto &member : m_raw)
{
QRegExp simple("^o\\.(\\w+)$");
if (member.contains(simple)) { m_names.push_back(simple.cap(1)); continue; }
QRegExp meta("^attr\\s*\\(\\s*o\\.(\\w+)");
if (member.contains(meta)) { m_names.push_back(meta.cap(1)); continue; }
qFatal("BLACK_DECLARE_TUPLE_CONVERSION: Parser couldn't extract member name from \"%s\"", qPrintable(member));
}
for (auto &name : m_names) { name.remove(QRegExp("^m_")); }
}
} // namespace

View File

@@ -1,431 +0,0 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_TUPLE_H
#define BLACKMISC_TUPLE_H
#include "blackmiscexport.h"
/*!
* \defgroup Tuples Tuple conversion of object data members
*/
namespace BlackMisc
{
//! Metadata flags attached to tuple elements.
//! \ingroup Tuples
enum TupleConverterFlags
{
DisabledForComparison = 1 << 0, //!< Element will be ignored by compare() and comparison operators
DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling
DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug
DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash()
DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization
CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString)
};
}
#include "tupleprivate.h"
/*!
* \brief Macro to make a class available to TupleConverter.
* \details Put this macro anywhere in the private section of a class declaration to make it usable in TupleConverter.
* \param T The name of the class.
* \hideinitializer
* \ingroup Tuples
*/
#define BLACK_ENABLE_TUPLE_CONVERSION(T) \
public: using EnabledTupleConversion = std::true_type; \
private: friend class BlackMisc::TupleConverter<T>;
/*!
* \brief Macro to make a class known to TupleConverter.
* \details Put this macro outside of any namespace, in the same header as T, to make it usable in TupleConverter.
* \param T The fully qualified name of the class.
* \param MEMBERS A parenthesized, comma-separated list of the data members of T, with each member prefixed by "o."
* (the letter o followed by dot). Can also use any types or functions inherited from TupleConverterBase.
* \par Example
* If class Things::MyThing has data members m_first, m_second, and m_third:
* \code
* BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, o.m_third))
* \endcode
* To disable m_third from participating in hash value generation:
* \code
* BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, attr(o.m_third, flags<DisabledForHash>())))
* \endcode
* \see BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE If T is a template, use this instead.
* \hideinitializer
* \ingroup Tuples
*/
#define BLACK_DECLARE_TUPLE_CONVERSION(T, MEMBERS) \
namespace BlackMisc \
{ \
template <> class TupleConverter<T> : TupleConverterBase \
{ \
friend class T; \
template <class, class> friend class BlackMisc::CValueObject; \
friend class BlackMisc::Private::EncapsulationBreaker; \
static_assert(Private::HasEnabledTupleConversion<T>::value, \
"Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \
static auto toTuple(const T &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
static auto toTuple(T &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
static auto toMetaTuple(const T &o) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static auto toMetaTuple(T &o) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static const Parser &parser() \
{ \
static const Parser p(#MEMBERS); \
return p; \
} \
static const QStringList &jsonMembers() \
{ \
return parser().m_names; \
} \
public: \
static auto constToTuple(const T &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
}; \
}
/*!
* \brief Same as BLACK_DECLARE_TUPLE_CONVERSION(), but T can be a class template.
* \hideinitializer
* \ingroup Tuples
*/
#define BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE(T, MEMBERS) \
namespace BlackMisc \
{ \
template <class... U> class TupleConverter<T<U...>> : TupleConverterBase \
{ \
friend class T<U...>; \
template <class, class> friend class BlackMisc::CValueObject; \
friend class BlackMisc::Private::EncapsulationBreaker; \
static_assert(Private::HasEnabledTupleConversion<T<U...>>::value, \
"Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \
static auto toTuple(const T<U...> &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
static auto toTuple(T<U...> &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
static auto toMetaTuple(const T<U...> &o) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static auto toMetaTuple(T<U...> &o) \
{ \
auto tu = BlackMisc::tieMeta MEMBERS; \
parser().extendMetaTuple(tu); \
return tu; \
} \
static const Parser &parser() \
{ \
static const Parser p(#MEMBERS); \
return p; \
} \
static const QStringList &jsonMembers() \
{ \
return parser().m_names; \
} \
public: \
static auto constToTuple(const T<U...> &o) \
{ \
return BlackMisc::tie MEMBERS; \
} \
}; \
}
namespace BlackMisc
{
/*!
* \brief Base class for TupleConverter<T>.
* \details Defines common types and functions which can be used inside the BLACK_DECLARE_TUPLE_CONVERSION() macro.
* \ingroup Tuples
*/
class TupleConverterBase
{
protected:
//! \brief A shorthand alias for passing flags as a compile-time constant.
template <qint64 F = 0>
using flags = std::integral_constant<qint64, F>;
//! \brief Create a tuple element with default metadata.
template <class T>
static Private::Attribute<T> attr(T &obj)
{
return { obj };
}
//! \brief Create a tuple element with attached metadata.
//! @{
template <class T, qint64 F>
static Private::Attribute<T, F> attr(T &obj, std::integral_constant<qint64, F>)
{
return { obj };
}
template <class T>
static Private::Attribute<T> attr(T &obj, QString jsonName)
{
return { obj, jsonName };
}
template <class T, qint64 F>
static Private::Attribute<T, F> attr(T &obj, QString jsonName, std::integral_constant<qint64, F>)
{
return { obj, jsonName };
}
//! @}
//! \brief Helper class which parses the stringified macro argument.
struct BLACKMISC_EXPORT Parser
{
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<std::decay_t<Tu>>::value>());
}
};
};
/*!
* \brief Class template for converting class objects to tuples
* \details If a class T uses the BLACK_ENABLE_TUPLE_CONVERSION() and BLACK_DECLARE_TUPLE_CONVERSION() macros, and <CODE>object</CODE>
* is an instance of T, then <CODE> TupleConverter<T>::toTuple(object) </CODE> will return a std::tuple representing object.
* This tuple can then be passed to a generic function like one of those listed under See Also:
* \see BlackMisc::compare(), BlackMisc::qHash(), BlackMisc::operator<<(), BlackMisc::operator>>(), std::operator==().
* \remarks The toTuple() function is a private member of TupleConverter, and the class T is declared to be its friend.
* \nosubgrouping
* \ingroup Tuples
*/
template <class T> class TupleConverter : private TupleConverterBase
{
// BLACK_DECLARE_TUPLE_CONVERSION generates an explicit specialization of TupleConverter,
// so this unspecialized template will only be used if the macro is missing. It is also
// a good place to put Doxygen comments to document the API of the macro-generated specializations.
static_assert(std::is_void<T>::value, // always false; is_void<> trick is just to make the condition dependent on the template parameter T
"Missing BLACK_DECLARE_TUPLE_CONVERSION macro for T");
public:
/*!
* \name Static Private Member Functions
* \brief Returns a tuple of references to object's data members listed in BLACK_DECLARE_TUPLE_CONVERSION().
* Can be used like <CODE> std::tie </CODE>.
*/
//! @{
static std::tuple<> toTuple(const T &object) = delete;
static std::tuple<> toTuple(T &object) = delete;
static std::tuple<> constToTuple(const T &object) = delete;
//! @}
/*!
* \name Static Private Member Functions
* \brief Returns a tuple of structs, each of which contains a reference to one of object's data members and its attched metadata.
*/
//! @{
static std::tuple<> toMetaTuple(const T &object) = delete;
static std::tuple<> toMetaTuple(T &object) = delete;
//! @}
/*!
* \name Static Private Member Functions
* \brief Returns an object with information extracted from the stringified macro argument.
*/
static const Parser &parser() = delete;
/*!
* \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() = delete;
};
// Needed so that our qHash overload doesn't hide the qHash overloads in the global namespace.
// This will be safe as long as no global qHash has the same signature as ours.
// Alternative would be to qualify all our invokations of the global qHash as ::qHash.
using ::qHash;
/*!
* \brief Works like std::tie, returning a tuple of references to just the values, with metadata removed.
* \ingroup Tuples
*/
template <class... Ts>
auto tie(Ts &&... args)
{
return std::make_tuple(Private::tieHelper(args)...);
}
/*!
* \brief Works like std::tie, returning a tuple of objects, each of which contains metadata plus a reference to a value.
* \ingroup Tuples
*/
template <class... Ts>
auto tieMeta(Ts &&... args)
{
return std::make_tuple(Private::tieMetaHelper(args)...);
}
/*!
* \brief Lexicographical tuple comparison function which is CValueObject-aware.
* \details Tuple members which are CValueObjects are compared using the compare() friend function of CValueObject;
* other tuple members are compared using operator< and operator>.
* \ingroup Tuples
*/
template <class... Ts>
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
{
auto metaA = Private::recoverMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
auto metaB = Private::recoverMeta(b, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::compare_(metaA, metaB, Private::skipFlaggedIndices<DisabledForComparison>(metaA));
}
/*!
* \brief Marshall the elements of a tuple into a QDBusArgument.
* \ingroup Tuples
*/
template <class... Ts>
QDBusArgument &operator <<(QDBusArgument &arg, std::tuple<Ts...> tu)
{
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::marshall(arg, valueTu, Private::skipFlaggedIndices<DisabledForMarshalling>(metaTu));
}
/*!
* \brief Unmarshall a QDBusArgument into the elements of a tuple.
* \ingroup Tuples
*/
template <class... Ts>
const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple<Ts...> tu)
{
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::unmarshall(arg, valueTu, Private::skipFlaggedIndices<DisabledForMarshalling>(metaTu));
}
/*!
* \brief Stream a tuple to qDebug.
* \ingroup Tuples
*/
template <class... Ts>
QDebug operator <<(QDebug debug, std::tuple<Ts &...> tu)
{
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::debug(debug, valueTu, Private::skipFlaggedIndices<DisabledForDebugging>(metaTu));
}
/*!
* \brief Stream a tuple to qDebug.
* \ingroup Tuples
*/
template <class... Ts>
QNoDebug operator <<(QNoDebug noDebug, std::tuple<Ts &...> tu)
{
Q_UNUSED(tu);
return noDebug;
}
/*!
* \brief Generate a hash value from the elements of a tuple.
* \ingroup Tuples
*/
template <class... Ts>
uint qHash(std::tuple<Ts...> tu)
{
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::hash(valueTu, Private::skipFlaggedIndices<DisabledForHashing>(metaTu));
}
/*!
* \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)
{
QJsonObject json;
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
Private::TupleHelper::serializeJson(json, members, valueTu, Private::skipFlaggedIndices<DisabledForJson>(metaTu));
return json;
}
/*!
* \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)
{
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
Private::TupleHelper::deserializeJson(json, members, valueTu, Private::skipFlaggedIndices<DisabledForJson>(metaTu));
}
/*!
* \brief Convert to a JSON object
* \ingroup Tuples
*/
template <class... Ts>
QJsonObject serializeJson(std::tuple<Ts...> tu)
{
QJsonObject json;
Private::assertMeta(tu);
Private::TupleHelper::serializeJson(json, tu, Private::skipFlaggedIndices<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(tu);
Private::TupleHelper::deserializeJson(json, tu, Private::skipFlaggedIndices<DisabledForJson>(tu));
}
} // namespace BlackMisc
#endif // guard

View File

@@ -1,377 +0,0 @@
/* Copyright (C) 2013
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#ifndef BLACKMISC_TUPLE_PRIVATE_H
#define BLACKMISC_TUPLE_PRIVATE_H
#include "integersequence.h"
#include <QtGlobal>
#include <QDBusArgument>
#include <QHash>
#include <QJsonObject>
#include <QDateTime>
#include <QString>
#include <QJsonArray>
#include <QDebug>
#include <tuple>
#include <type_traits>
#include <functional>
namespace BlackMisc
{
class CEmpty;
template <class> class TupleConverter;
template <class Derived, class Base = CEmpty> class CValueObject;
namespace Private
{
// Inhibit doxygen warnings about missing documentation
//! \cond PRIVATE
// To allow CValueObject policy classes to use the tuple system
class EncapsulationBreaker
{
protected:
template <class T>
static auto toMetaTuple(T &o)
{
return TupleConverter<std::decay_t<T>>::toMetaTuple(o);
}
};
// Using SFINAE to help detect missing BLACK_ENABLE_TUPLE_CONVERSION macro in static_assert
std::false_type hasEnabledTupleConversionHelper(...);
template <class T>
typename T::EnabledTupleConversion hasEnabledTupleConversionHelper(T *);
template <class T>
struct HasEnabledTupleConversion
{
using type = decltype(hasEnabledTupleConversionHelper(static_cast<T *>(nullptr)));
static constexpr bool value = type::value;
};
// Using tag dispatch to select which implementation of compare() to use
template <class T>
int compareHelper(const T &a, const T &b, std::true_type isCValueObjectTag)
{
Q_UNUSED(isCValueObjectTag);
return compare(a, b);
}
template <class T>
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;
}
// Create an index_sequence containing indices which match a given predicate.
template <class P, size_t I, size_t C, bool B = false, size_t I2 = 0xDeadBeef, size_t... Is>
struct GenSequenceOnPredicate;
template <class P, size_t I, size_t C, size_t I2, size_t... Is>
struct GenSequenceOnPredicate<P, I, C, true, I2, Is...>
{
static constexpr bool test = P::template test<I>::value;
using type = typename GenSequenceOnPredicate<P, I + 1, C, test, I, Is..., I2>::type;
};
template <class P, size_t I, size_t C, size_t I2, size_t... Is>
struct GenSequenceOnPredicate<P, I, C, false, I2, Is...>
{
static constexpr bool test = P::template test<I>::value;
using type = typename GenSequenceOnPredicate<P, I + 1, C, test, I, Is...>::type;
};
template <class P, size_t C, size_t I2, size_t... Is>
struct GenSequenceOnPredicate<P, C, C, true, I2, Is...>
{
using type = index_sequence<Is..., I2>;
};
template <class P, size_t C, size_t I2, size_t... Is>
struct GenSequenceOnPredicate<P, C, C, false, I2, Is...>
{
using type = index_sequence<Is...>;
};
template <class P>
using make_index_sequence_if = typename GenSequenceOnPredicate<P, 0, std::tuple_size<typename P::tuple_type>::value>::type;
// Predicates used with make_index_sequence_if.
template <qint64 F, class Tu>
struct FlagPresent
{
using tuple_type = Tu;
template <size_t I>
struct test : std::integral_constant<bool, bool(std::tuple_element_t<I, Tu>::flags & F)> {};
};
template <qint64 F, class Tu>
struct FlagMissing
{
using tuple_type = Tu;
template <size_t I>
struct test : std::integral_constant<bool, ! bool(std::tuple_element_t<I, Tu>::flags & F)> {};
};
// Combine make_index_sequence_if with predicates to get the indices of tuple elements with certain flags.
template <qint64 F, class Tu>
auto findFlaggedIndices(Tu &&) -> make_index_sequence_if<FlagPresent<F, std::decay_t<Tu>>>
{
return {};
}
template <qint64 F, class Tu>
auto skipFlaggedIndices(Tu &&) -> make_index_sequence_if<FlagMissing<F, std::decay_t<Tu>>>
{
return {};
}
// CRTP base class for Attribute, to select appropriate method of comparison.
template <class Derived, bool AlwaysEqual, bool CaseInsensitive>
struct AttributeComparable;
template <class Derived, bool CaseInsensitive>
struct AttributeComparable<Derived, true, CaseInsensitive>
{
friend int compare(const Derived &, const Derived &) { return 0; }
friend bool operator ==(const Derived &, const Derived &) { return true; }
friend bool operator !=(const Derived &, const Derived &) { return false; }
friend bool operator <(const Derived &, const Derived &) { return false; }
friend bool operator <=(const Derived &, const Derived &) { return true; }
friend bool operator >(const Derived &, const Derived &) { return false; }
friend bool operator >=(const Derived &, const Derived &) { return true; }
};
template <class Derived>
struct AttributeComparable<Derived, false, false>
{
template <class T> using isCValueObject = typename std::is_base_of<CEmpty, T>::type; // historical use case, may need tweaking in future
friend int compare(const Derived &a, const Derived &b) { return compareHelper(a.m_obj, b.m_obj, isCValueObject<Derived>()); }
friend bool operator ==(const Derived &a, const Derived &b) { return a.m_obj == b.m_obj; }
friend bool operator !=(const Derived &a, const Derived &b) { return a.m_obj != b.m_obj; }
friend bool operator <(const Derived &a, const Derived &b) { return a.m_obj < b.m_obj; }
friend bool operator <=(const Derived &a, const Derived &b) { return a.m_obj <= b.m_obj; }
friend bool operator >(const Derived &a, const Derived &b) { return a.m_obj > b.m_obj; }
friend bool operator >=(const Derived &a, const Derived &b) { return a.m_obj >= b.m_obj; }
};
template <class Derived>
struct AttributeComparable<Derived, false, true>
{
friend int compare(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive); }
friend bool operator ==(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) == 0; }
friend bool operator !=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) != 0; }
friend bool operator <(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) < 0; }
friend bool operator <=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) <= 0; }
friend bool operator >(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) > 0; }
friend bool operator >=(const Derived &a, const Derived &b) { return a.m_obj.compare(b.m_obj, Qt::CaseInsensitive) >= 0; }
};
// A tuple element with attached metadata.
template <class T, qint64 Flags = 0>
struct Attribute : public AttributeComparable<Attribute<T, Flags>, bool(Flags & DisabledForComparison), bool(Flags & CaseInsensitiveComparison)>
{
using type = T;
static constexpr qint64 flags = Flags;
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;
};
// Helpers used in tie(), tieMeta(), and elsewhere, which arrange for the correct types to be passed to std::make_tuple.
// See http://en.cppreference.com/w/cpp/utility/tuple/make_tuple
// "For each Ti in Types..., the corresponding type Vi in Vtypes... is std::decay<Ti>::type
// unless application of std::decay results in std::reference_wrapper<X>, in which case the deduced type is X&."
template <class T>
std::reference_wrapper<T> tieHelper(T &obj)
{
return obj;
}
template <class T, qint64 Flags>
std::reference_wrapper<T> tieHelper(Attribute<T, Flags> attr)
{
return attr.m_obj;
}
template <class T>
Attribute<T> tieMetaHelper(T &obj)
{
return obj;
}
template <class T, qint64 Flags>
Attribute<T, Flags> tieMetaHelper(Attribute<T, Flags> attr)
{
return attr;
}
// Compile-time assert for functions which require a meta tuple
template <class Tu>
void assertMeta(const Tu &) { static_assert(std::is_void<Tu>::value, "Function expected a meta tuple, got a value tuple"); }
template <class... Ts, qint64... Fs>
void assertMeta(const 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...>)
{
return std::make_tuple(tieHelper(std::get<Is>(std::forward<Tu>(tu)))...);
}
// Convert a value tuple to a meta tuple with default metadata
template <class Tu, size_t... Is>
auto recoverMeta(Tu &&tu, index_sequence<Is...>)
{
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
{
public:
template <class Tu, size_t... Is>
static int compare_(const Tu &a, const Tu &b, index_sequence<Is...>) // underscore to avoid hiding the name "compare" in other scopes
{
return compareImpl(std::make_pair(std::get<Is>(a), std::get<Is>(b))...);
}
template <class Tu, size_t... Is>
static QDBusArgument &marshall(QDBusArgument &arg, const Tu &tu, index_sequence<Is...>)
{
marshallImpl(arg, std::get<Is>(tu)...);
return arg;
}
template <class Tu, size_t... Is>
static const QDBusArgument &unmarshall(const QDBusArgument &arg, Tu &tu, index_sequence<Is...>)
{
unmarshallImpl(arg, std::get<Is>(tu)...);
return arg;
}
template <class Tu, size_t... Is>
static QDebug debug(QDebug dbg, const Tu &tu, index_sequence<Is...>)
{
debugImpl(dbg, std::get<Is>(tu)...);
return dbg;
}
template <class Tu, size_t... Is>
static uint hash(const Tu &tu, index_sequence<Is...>)
{
return hashImpl(qHash(std::get<Is>(tu))...);
}
template <class Tu, size_t... Is>
static void serializeJson(QJsonObject &json, const QStringList &names, const Tu &tu, index_sequence<Is...>)
{
serializeJsonImpl(json, std::make_pair(names[Is], get_ref<Is>(tu))...);
}
template <class Tu, size_t... Is>
static void deserializeJson(const QJsonObject &json, const QStringList &names, Tu &tu, index_sequence<Is...>)
{
deserializeJsonImpl(json, std::make_pair(names[Is], get_ref<Is>(tu))...);
}
template <class Tu, size_t... Is>
static void serializeJson(QJsonObject &json, const Tu &tu, index_sequence<Is...>)
{
serializeJsonImpl(json, std::make_pair(std::get<Is>(tu).m_jsonName, get_ref<Is>(tu))...);
Q_UNUSED(tu); // avoid compiler warning when all attributes are JSON disabled
}
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))...);
Q_UNUSED(tu); // avoid compiler warning when all attributes are JSON disabled
}
private:
template <size_t I, class Tu>
static auto get_ref(Tu &&tu)
{
return tieHelper(std::get<I>(std::forward<Tu>(tu)));
}
static int compareImpl() { return 0; }
template <class T, class... Ts>
static int compareImpl(const std::pair<T, T> &head, const Ts &... tail)
{
int result = compare(head.first, head.second);
if (result) return result;
return compareImpl(tail...);
}
static void marshallImpl(QDBusArgument &) {}
template <class T, class... Ts>
static void marshallImpl(QDBusArgument &arg, const T &head, const Ts &... tail)
{
marshallHelper(arg, head, 0);
marshallImpl(arg, tail...);
}
template <class T, std::enable_if_t<std::is_base_of<CEmpty, T>::value, int> = 0>
static void marshallHelper(QDBusArgument &arg, const T &val, int) { static_cast<const typename T::CValueObject &>(val).marshallToDbus(arg); }
template <class T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
static void marshallHelper(QDBusArgument &arg, const T &val, int) { arg << static_cast<int>(val); }
template <class T>
static void marshallHelper(QDBusArgument &arg, const T &val, ...) { arg << val; }
static void unmarshallImpl(const QDBusArgument &) {}
template <class T, class... Ts>
static void unmarshallImpl(const QDBusArgument &arg, T &head, Ts &... tail)
{
unmarshallHelper(arg, head, 0);
unmarshallImpl(arg, tail...);
}
template <class T, std::enable_if_t<std::is_base_of<CEmpty, T>::value, int> = 0>
static void unmarshallHelper(const QDBusArgument &arg, T &val, int) { static_cast<typename T::CValueObject &>(val).unmarshallFromDbus(arg); }
template <class T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
static void unmarshallHelper(const QDBusArgument &arg, T &val, int) { int i; arg >> i; val = static_cast<T>(i); }
template <class T>
static void unmarshallHelper(const QDBusArgument &arg, T &val, ...) { arg >> val; }
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...); }
};
//! \endcond
} // namespace Private
} // namespace BlackMisc
#endif // guard

View File

@@ -15,7 +15,6 @@
#include "blackmiscexport.h"
#include "dbus.h"
#include "metaclass.h"
#include "tuple.h"
#include "json.h"
#include "compare.h"
#include "variant.h"
@@ -68,7 +67,7 @@ namespace BlackMisc
* \tparam Base The class which this one shall inherit from (default is CEmpty,
* but this can be changed to create a deeper inheritance hierarchy).
*/
template <class Derived, class Base /*= CEmpty*/> class CValueObject :
template <class Derived, class Base = CEmpty> class CValueObject :
public Base,
public Mixin::MetaType<Derived>,
public Mixin::HashByMetaClass<Derived>,

View File

@@ -15,7 +15,6 @@
#include "variantprivate.h"
#include "blackmiscexport.h"
#include "stringutils.h"
#include "tuple.h"
#include "compare.h"
#include "dbus.h"
#include "json.h"