mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-26 10:45:37 +08:00
Issue #77 Move mixin classes to separate files
By separating them from unrelated code, their dependents can use them without depending on unrelated code, which in turn helps to reduce cyclic dependencies.
This commit is contained in:
188
src/blackmisc/mixin/mixincompare.h
Normal file
188
src/blackmisc/mixin/mixincompare.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/* Copyright (C) 2015
|
||||
* 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. 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_MIXIN_MIXINCOMPARE_H
|
||||
#define BLACKMISC_MIXIN_MIXINCOMPARE_H
|
||||
|
||||
#include "blackmisc/metaclass.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include "blackmisc/typetraits.h"
|
||||
#include "blackmisc/range.h"
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CEmpty;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator== implemented using its compare function.
|
||||
*
|
||||
* \tparam Derived Must overload a function bool compare(const Derived &, const Derived &) which can be found by ADL.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByCompare
|
||||
{
|
||||
public:
|
||||
//! Equals
|
||||
friend bool operator ==(const Derived &a, const Derived &b) { return compare(a, b) == 0; }
|
||||
|
||||
//! Not equal
|
||||
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 metaclass.
|
||||
*/
|
||||
template <class Derived>
|
||||
class EqualsByMetaClass
|
||||
{
|
||||
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)
|
||||
{
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
|
||||
bool result = baseEquals(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
|
||||
meta.forEachMember([ & ](auto member) { result = result && EqualsByMetaClass::membersEqual(member.in(a), member.in(b), member.m_flags); });
|
||||
return result;
|
||||
}
|
||||
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; }
|
||||
|
||||
template <typename T, typename Flags>
|
||||
static bool membersEqual(const T &a, const T &b, Flags)
|
||||
{
|
||||
return membersEqual(a, b, std::integral_constant<bool, static_cast<bool>(Flags::value & CaseInsensitiveComparison)>());
|
||||
}
|
||||
template <typename T>
|
||||
static bool membersEqual(const T &a, const T &b, std::true_type) { return a.compare(b, Qt::CaseInsensitive) == 0; }
|
||||
template <typename T>
|
||||
static bool membersEqual(const T &a, const T &b, std::false_type) { return a == b; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit operator< implemented using its compare function.
|
||||
*
|
||||
* \tparam Derived Must overload a function bool compare(const Derived &, const Derived &) which can be found by ADL.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByCompare
|
||||
{
|
||||
public:
|
||||
//! Less than
|
||||
friend bool operator <(const Derived &a, const Derived &b) { return compare(a, b) < 0; }
|
||||
|
||||
//! Greater than
|
||||
friend bool operator >(const Derived &a, const Derived &b) { return compare(a, b) > 0; }
|
||||
|
||||
//! Less than or equal
|
||||
friend bool operator <=(const Derived &a, const Derived &b) { return compare(a, b) <= 0; }
|
||||
|
||||
//! Greater than or equal
|
||||
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 metaclass.
|
||||
*/
|
||||
template <class Derived>
|
||||
class LessThanByMetaClass
|
||||
{
|
||||
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)
|
||||
{
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
|
||||
bool result = baseLess(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
|
||||
bool gt = baseLess(static_cast<const TBaseOfT<Derived> *>(&b), static_cast<const TBaseOfT<Derived> *>(&a));
|
||||
meta.forEachMember([ & ](auto member) { result = result || LessThanByMetaClass::membersLess(gt, member.in(a), member.in(b), member.m_flags); });
|
||||
return result;
|
||||
}
|
||||
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; }
|
||||
|
||||
template <typename T, typename Flags>
|
||||
static bool membersLess(bool &io_greaterThan, const T &a, const T &b, Flags)
|
||||
{
|
||||
using CaseInsensitive = std::integral_constant<bool, static_cast<bool>(Flags::value & CaseInsensitiveComparison)>;
|
||||
if (io_greaterThan) { return false; }
|
||||
io_greaterThan = membersLess(b, a, CaseInsensitive());
|
||||
return membersLess(a, b, CaseInsensitive());
|
||||
}
|
||||
template <typename T>
|
||||
static bool membersLess(const T &a, const T &b, std::true_type) { return a.compare(b, Qt::CaseInsensitive) < 0; }
|
||||
template <typename T>
|
||||
static bool membersLess(const T &a, const T &b, std::false_type) { return a < b; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit non-member compare() implemented by metaclass.
|
||||
*/
|
||||
template <class Derived>
|
||||
class CompareByMetaClass
|
||||
{
|
||||
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)
|
||||
{
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForComparison>());
|
||||
int result = baseCompare(static_cast<const TBaseOfT<Derived> *>(&a), static_cast<const TBaseOfT<Derived> *>(&b));
|
||||
meta.forEachMember([ & ](auto member) { result = result ? result : CompareByMetaClass::membersCompare(member.in(a), member.in(b), member.m_flags); });
|
||||
return result;
|
||||
}
|
||||
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; }
|
||||
|
||||
template <typename T, typename Flags>
|
||||
static int membersCompare(const T &a, const T &b, Flags)
|
||||
{
|
||||
using CaseInsensitive = std::integral_constant<bool, static_cast<bool>(Flags::value & CaseInsensitiveComparison)>;
|
||||
return membersCompare(a, b, CaseInsensitive(), THasCompare<T, T>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
static int membersCompare(const T &a, const T &b, std::true_type, U) { return a.compare(b, Qt::CaseInsensitive); }
|
||||
template <typename T>
|
||||
static int membersCompare(const T &a, const T &b, std::false_type, std::true_type) { return compare(a, b); }
|
||||
template <typename T>
|
||||
static int membersCompare(const T &a, const T &b, std::false_type, std::false_type) { return a < b ? -1 : b < a ? 1 : 0; }
|
||||
};
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
#endif
|
||||
95
src/blackmisc/mixin/mixindatastream.h
Normal file
95
src/blackmisc/mixin/mixindatastream.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Copyright (C) 2019
|
||||
* 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. 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_MIXIN_MIXINDATASTREAM_H
|
||||
#define BLACKMISC_MIXIN_MIXINDATASTREAM_H
|
||||
|
||||
#include "blackmisc/metaclass.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include <QDataStream>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CEmpty;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template to generate non-member QDataStream streaming operators.
|
||||
*
|
||||
* \tparam Derived Must implement public methods marshalToDataStream(QDataStream &) and unmarshalFromDataStream(QDataStream &).
|
||||
*/
|
||||
template <class Derived>
|
||||
class DataStreamOperators
|
||||
{
|
||||
public:
|
||||
//! Marshal a value to a QDataStream.
|
||||
friend QDataStream &operator <<(QDataStream &stream, const Derived &value)
|
||||
{
|
||||
value.marshalToDataStream(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Unmarshal a value from a QDataStream.
|
||||
friend QDataStream &operator >>(QDataStream &stream, Derived &value)
|
||||
{
|
||||
value.unmarshalFromDataStream(stream);
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template to generate QDataStream marshalling methods using CMetaClass.
|
||||
*
|
||||
* \see BLACKMISC_DECLARE_USING_MIXIN_DATASTREAM
|
||||
*/
|
||||
template <class Derived>
|
||||
class DataStreamByMetaClass : public DataStreamOperators<Derived>
|
||||
{
|
||||
public:
|
||||
//! Marshal a value to a QDataStream.
|
||||
void marshalToDataStream(QDataStream &stream) const
|
||||
{
|
||||
baseMarshal(static_cast<const TBaseOfT<Derived> *>(derived()), stream);
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
|
||||
meta.forEachMember([ &, this ](auto member) { stream << member.in(*this->derived()); });
|
||||
}
|
||||
|
||||
//! Unmarshal a value from a QDataStream.
|
||||
void unmarshalFromDataStream(QDataStream &stream)
|
||||
{
|
||||
baseUnmarshal(static_cast<TBaseOfT<Derived> *>(derived()), stream);
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
|
||||
meta.forEachMember([ &, this ](auto member) { stream >> member.in(*this->derived()); });
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T> static void baseMarshal(const T *base, QDataStream &stream) { base->marshalToDataStream(stream); }
|
||||
template <typename T> static void baseUnmarshal(T *base, QDataStream &stream) { base->unmarshalFromDataStream(stream); }
|
||||
static void baseMarshal(const void *, QDataStream &) {}
|
||||
static void baseUnmarshal(void *, QDataStream &) {}
|
||||
static void baseMarshal(const CEmpty *, QDataStream &) {}
|
||||
static void baseUnmarshal(CEmpty *, QDataStream &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::DataStreamByMetaClass,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_DATASTREAM(DERIVED) \
|
||||
using ::BlackMisc::Mixin::DataStreamByMetaClass<DERIVED>::marshalToDataStream; \
|
||||
using ::BlackMisc::Mixin::DataStreamByMetaClass<DERIVED>::unmarshalFromDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
140
src/blackmisc/mixin/mixindbus.h
Normal file
140
src/blackmisc/mixin/mixindbus.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Copyright (C) 2014
|
||||
* 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. 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_MIXIN_MIXINDBUS_H
|
||||
#define BLACKMISC_MIXIN_MIXINDBUS_H
|
||||
|
||||
#include "blackmisc/metaclass.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include "blackmisc/typetraits.h"
|
||||
#include <QDBusArgument>
|
||||
#include <type_traits>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CEmpty;
|
||||
|
||||
/*!
|
||||
* Tag type signifying overloaded marshalling methods that preserve data at the expense of size.
|
||||
*/
|
||||
class LosslessTag {};
|
||||
|
||||
// *INDENT-OFF*
|
||||
namespace Private
|
||||
{
|
||||
//! \cond PRIVATE
|
||||
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
|
||||
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { value.marshallToDbus(arg); }
|
||||
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
|
||||
void marshallMember(QDBusArgument &arg, const T &value, std::true_type) { value.marshallToDbus(arg, LosslessTag()); }
|
||||
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
|
||||
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { arg << value; }
|
||||
|
||||
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
|
||||
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { value.unmarshallFromDbus(arg); }
|
||||
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
|
||||
void unmarshallMember(const QDBusArgument &arg, T &value, std::true_type) { value.unmarshallFromDbus(arg, LosslessTag()); }
|
||||
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
|
||||
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { arg >> value; }
|
||||
//! \endcond
|
||||
}
|
||||
// *INDENT-ON*
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*
|
||||
* \tparam Derived Must implement public methods void marshallToDbus(QDBusArgument &arg) const and void unmarshallFromDbus(const QDBusArgument &arg).
|
||||
*/
|
||||
template <class Derived, class...>
|
||||
class DBusOperators
|
||||
{
|
||||
public:
|
||||
//! Unmarshalling operator >>, DBus to object
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &arg, Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.unmarshallFromDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
//! Marshalling operator <<, object to DBus
|
||||
friend QDBusArgument &operator<<(QDBusArgument &arg, const Derived &obj)
|
||||
{
|
||||
arg.beginStructure();
|
||||
obj.marshallToDbus(arg);
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
template <class Derived>
|
||||
class DBusOperators<Derived, LosslessTag> {};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metaclass.
|
||||
*
|
||||
* \see BLACKMISC_DECLARE_USING_MIXIN_DBUS
|
||||
*/
|
||||
template <class Derived, class... Tags>
|
||||
class DBusByMetaClass : public DBusOperators<Derived, Tags...>
|
||||
{
|
||||
public:
|
||||
//! Marshall without begin/endStructure, for when composed within another object
|
||||
void marshallToDbus(QDBusArgument &arg, Tags...) const
|
||||
{
|
||||
baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg);
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
|
||||
meta.forEachMember([ &, this ](auto member)
|
||||
{
|
||||
using lossless = std::integral_constant<bool, member.has(MetaFlags<LosslessMarshalling>())>;
|
||||
Private::marshallMember(arg, member.in(*this->derived()), lossless());
|
||||
});
|
||||
}
|
||||
|
||||
//! Unmarshall without begin/endStructure, for when composed within another object
|
||||
void unmarshallFromDbus(const QDBusArgument &arg, Tags...)
|
||||
{
|
||||
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
|
||||
meta.forEachMember([ &, this ](auto member)
|
||||
{
|
||||
using lossless = std::integral_constant<bool, member.has(MetaFlags<LosslessMarshalling>())>;
|
||||
Private::unmarshallMember(arg, member.in(*this->derived()), lossless());
|
||||
});
|
||||
}
|
||||
|
||||
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, Tags()...); }
|
||||
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg, Tags()...); }
|
||||
static void baseMarshall(const void *, QDBusArgument &) {}
|
||||
static void baseUnmarshall(void *, const QDBusArgument &) {}
|
||||
static void baseMarshall(const CEmpty *, QDBusArgument &) {}
|
||||
static void baseUnmarshall(CEmpty *, const QDBusArgument &) {}
|
||||
};
|
||||
|
||||
// *INDENT-OFF*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::DBusByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_DBUS(DERIVED, ...) \
|
||||
using ::BlackMisc::Mixin::DBusByMetaClass<DERIVED BLACK_TRAILING_VA_ARGS(__VA_ARGS__)>::marshallToDbus; \
|
||||
using ::BlackMisc::Mixin::DBusByMetaClass<DERIVED BLACK_TRAILING_VA_ARGS(__VA_ARGS__)>::unmarshallFromDbus;
|
||||
// *INDENT-ON*
|
||||
|
||||
} // Mixin
|
||||
} // BlackMisc
|
||||
|
||||
#endif // guard
|
||||
91
src/blackmisc/mixin/mixinhash.h
Normal file
91
src/blackmisc/mixin/mixinhash.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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. 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_MIXIN_MIXINHASH_H
|
||||
#define BLACKMISC_MIXIN_MIXINHASH_H
|
||||
|
||||
#include "blackmisc/metaclass.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QHash>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonValueRef>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QtDebug>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CEmpty;
|
||||
|
||||
// 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
|
||||
// Work around MSVC2015 bug affecting generic lambda
|
||||
template <typename T>
|
||||
struct Hasher
|
||||
{
|
||||
template <typename U>
|
||||
void operator()(const U &member) { m_hash ^= qHash(member.in(m_object)); }
|
||||
const T &m_object;
|
||||
uint &m_hash;
|
||||
};
|
||||
//! \endcond
|
||||
}
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with hashing instances by metaclass.
|
||||
*
|
||||
* \tparam Derived Must be registered with BLACK_DECLARE_TUPLE_CONVERSION.
|
||||
*/
|
||||
template <class Derived>
|
||||
class HashByMetaClass
|
||||
{
|
||||
public:
|
||||
//! qHash overload, needed for storing value in a QSet.
|
||||
friend uint qHash(const Derived &value, uint seed = 0) // clazy:exclude=qhash-namespace
|
||||
{
|
||||
return ::qHash(hashImpl(value), seed);
|
||||
}
|
||||
|
||||
private:
|
||||
static uint hashImpl(const Derived &value)
|
||||
{
|
||||
uint hash = baseHash(static_cast<const TBaseOfT<Derived> *>(&value));
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForHashing>());
|
||||
meta.forEachMember(Private::Hasher<Derived> { value, hash });
|
||||
return hash;
|
||||
}
|
||||
|
||||
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; }
|
||||
};
|
||||
}
|
||||
} // namespace BlackMisc
|
||||
|
||||
#endif // BLACKMISC_DICTIONARY_H
|
||||
|
||||
54
src/blackmisc/mixin/mixinicon.h
Normal file
54
src/blackmisc/mixin/mixinicon.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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. 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_MIXIN_MIXINICON_H
|
||||
#define BLACKMISC_MIXIN_MIXINICON_H
|
||||
|
||||
#include "blackmisc/icon.h"
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <tuple>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CIcon;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit icon-related functions.
|
||||
*/
|
||||
template <class Derived, CIcons::IconIndex IconIndex = CIcons::StandardIconUnknown16>
|
||||
class Icon
|
||||
{
|
||||
public:
|
||||
//! As icon, not implemented by all classes
|
||||
CIcon toIcon() const { return CIcon::iconByIndex(IconIndex); }
|
||||
|
||||
//! As pixmap, required for most GUI views
|
||||
QPixmap toPixmap() const { return derived()->toIcon().toPixmap(); }
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::Icon,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_ICON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toIcon; \
|
||||
using ::BlackMisc::Mixin::Icon<DERIVED>::toPixmap;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
202
src/blackmisc/mixin/mixinindex.h
Normal file
202
src/blackmisc/mixin/mixinindex.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/* 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. 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_MIXIN_MIXININDEX_H
|
||||
#define BLACKMISC_MIXIN_MIXININDEX_H
|
||||
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include "blackmisc/predicates.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/propertyindexlist.h"
|
||||
#include "blackmisc/propertyindexvariantmap.h"
|
||||
#include "blackmisc/variant.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QtDebug>
|
||||
#include <QtGlobal>
|
||||
#include <type_traits>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit property indexing functions.
|
||||
*
|
||||
* This is only a placeholder for future support of implementing property indexing through the tuple system.
|
||||
* At the moment, it just implements the default properties: String, Icon, and Pixmap.
|
||||
*/
|
||||
template <class Derived>
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
//! Base class enums
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexPixmap = 10, // manually set to avoid circular dependencies
|
||||
IndexIcon,
|
||||
IndexString
|
||||
};
|
||||
|
||||
//! Update by variant map
|
||||
//! \return number of values changed, with skipEqualValues equal values will not be changed
|
||||
CPropertyIndexList apply(const CPropertyIndexVariantMap &indexMap, bool skipEqualValues = false);
|
||||
|
||||
//! Set property by index
|
||||
void setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant);
|
||||
|
||||
//! Property by index
|
||||
CVariant propertyByIndex(const CPropertyIndex &index) const;
|
||||
|
||||
//! Property by index as String
|
||||
QString propertyByIndexAsString(const CPropertyIndex &index, bool i18n = false) const;
|
||||
|
||||
//! Compare for index
|
||||
int comparePropertyByIndex(const CPropertyIndex &index, const Derived &compareValue) const;
|
||||
|
||||
//! Is given variant equal to value of property index?
|
||||
bool equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const;
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
|
||||
CVariant myself() const { return CVariant::from(*derived()); }
|
||||
template <typename T, std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
|
||||
void myself(const CVariant &variant) { *derived() = variant.to<T>(); }
|
||||
|
||||
template <typename T, std::enable_if_t<! std::is_default_constructible<T>::value, int> = 0>
|
||||
CVariant myself() const { qFatal("isMyself should have been handled before reaching here"); return {}; }
|
||||
template <typename T, std::enable_if_t<! std::is_default_constructible<T>::value, int> = 0>
|
||||
void myself(const CVariant &) { qFatal("isMyself should have been handled before reaching here"); }
|
||||
|
||||
template <typename T>
|
||||
CVariant basePropertyByIndex(const T *base, const CPropertyIndex &index) const { return base->propertyByIndex(index); }
|
||||
template <typename T>
|
||||
void baseSetPropertyByIndex(T *base, const CVariant &var, const CPropertyIndex &index) { base->setPropertyByIndex(index, var); }
|
||||
|
||||
CVariant basePropertyByIndex(const void *, const CPropertyIndex &index) const
|
||||
{
|
||||
qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {};
|
||||
}
|
||||
|
||||
void baseSetPropertyByIndex(void *, const CVariant &, const CPropertyIndex &index)
|
||||
{
|
||||
qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString()));
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::Index,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
// *INDENT-OFF*
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_INDEX(DERIVED) \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::apply; \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::setPropertyByIndex; \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::propertyByIndex; \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::propertyByIndexAsString; \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::comparePropertyByIndex; \
|
||||
using ::BlackMisc::Mixin::Index<DERIVED>::equalsPropertyByIndex;
|
||||
// *INDENT-ON*
|
||||
|
||||
template <class Derived>
|
||||
CPropertyIndexList Index<Derived>::apply(const BlackMisc::CPropertyIndexVariantMap &indexMap, bool skipEqualValues)
|
||||
{
|
||||
if (indexMap.isEmpty()) return {};
|
||||
|
||||
CPropertyIndexList changed;
|
||||
const auto &map = indexMap.map();
|
||||
for (auto it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
const CVariant value = it.value();
|
||||
const CPropertyIndex index = it.key();
|
||||
if (skipEqualValues)
|
||||
{
|
||||
const bool equal = derived()->equalsPropertyByIndex(value, index);
|
||||
if (equal) { continue; }
|
||||
}
|
||||
derived()->setPropertyByIndex(index, value);
|
||||
changed.push_back(index);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void Index<Derived>::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant)
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
myself<Derived>(variant);
|
||||
}
|
||||
else
|
||||
{
|
||||
baseSetPropertyByIndex(static_cast<TIndexBaseOfT<Derived> *>(derived()), variant, index);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
CVariant Index<Derived>::propertyByIndex(const CPropertyIndex &index) const
|
||||
{
|
||||
if (index.isMyself()) { return myself<Derived>(); }
|
||||
const auto i = index.frontCasted<ColumnIndex>(); // keep that "auto", otherwise I won's compile
|
||||
switch (i)
|
||||
{
|
||||
case IndexIcon: return CVariant::from(derived()->toIcon());
|
||||
case IndexPixmap: return CVariant::from(derived()->toPixmap());
|
||||
case IndexString: return CVariant(derived()->toQString());
|
||||
default: return basePropertyByIndex(static_cast<const TIndexBaseOfT<Derived> *>(derived()), index);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
QString Index<Derived>::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const
|
||||
{
|
||||
return derived()->propertyByIndex(index).toQString(i18n);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
bool Index<Derived>::equalsPropertyByIndex(const CVariant &compareValue, const CPropertyIndex &index) const
|
||||
{
|
||||
return derived()->propertyByIndex(index) == compareValue;
|
||||
}
|
||||
|
||||
template<class Derived>
|
||||
int Index<Derived>::comparePropertyByIndex(const CPropertyIndex &index, const Derived &compareValue) const
|
||||
{
|
||||
if (this == &compareValue) { return 0; }
|
||||
if (index.isMyself()) {
|
||||
// slow, only last resort
|
||||
return derived()->toQString().compare(compareValue.toQString());
|
||||
}
|
||||
|
||||
const auto i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexIcon:
|
||||
case IndexPixmap:
|
||||
case IndexString:
|
||||
default:
|
||||
break; // also covers
|
||||
}
|
||||
|
||||
// slow, only last resort
|
||||
return derived()->toQString().compare(compareValue.toQString());
|
||||
}
|
||||
} // ns
|
||||
} // ns
|
||||
|
||||
#endif // guard
|
||||
208
src/blackmisc/mixin/mixinjson.h
Normal file
208
src/blackmisc/mixin/mixinjson.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/* Copyright (C) 2014
|
||||
* 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. 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_MIXIN_MIXINJSON_H
|
||||
#define BLACKMISC_MIXIN_MIXINJSON_H
|
||||
|
||||
#include "blackmisc/json.h"
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonValueRef>
|
||||
#include <QStringList>
|
||||
#include <QtGlobal>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CEmpty;
|
||||
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
|
||||
*
|
||||
* \tparam Must implement public methods QJsonObject toJson() const and void convertFromJson(const QJsonObject &json).
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonOperators
|
||||
{
|
||||
public:
|
||||
//! operator >> for JSON
|
||||
friend const QJsonObject &operator>>(const QJsonObject &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json);
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend const QJsonValue &operator>>(const QJsonValue &json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator >> for JSON
|
||||
friend QJsonValueRef operator>>(QJsonValueRef json, Derived &obj)
|
||||
{
|
||||
obj.convertFromJson(json.toObject());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonArray &operator<<(QJsonArray &json, const Derived &obj)
|
||||
{
|
||||
json.append(obj.toJson());
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const Derived &> &value)
|
||||
{
|
||||
json.insert(value.first, QJsonValue(value.second.toJson()));
|
||||
return json;
|
||||
}
|
||||
|
||||
//! operator << for JSON
|
||||
friend QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const Derived &> &value)
|
||||
{
|
||||
json[value.first] = QJsonValue(value.second.toJson());
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with JSON by metatuple.
|
||||
*
|
||||
* \see BLACKMISC_DECLARE_USING_MIXIN_JSON
|
||||
*/
|
||||
template <class Derived>
|
||||
class JsonByMetaClass : public JsonOperators<Derived>
|
||||
{
|
||||
public:
|
||||
//! Cast to JSON object
|
||||
QJsonObject toJson() const
|
||||
{
|
||||
QJsonObject json;
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>());
|
||||
meta.forEachMember([ &, this ](auto member)
|
||||
{
|
||||
json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(member.in(*this->derived())));
|
||||
});
|
||||
return Json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<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<TBaseOfT<Derived> *>(derived()), json);
|
||||
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>());
|
||||
meta.forEachMember([ &, this ](auto member)
|
||||
{
|
||||
const auto value = json.value(CExplicitLatin1String(member.latin1Name()));
|
||||
if (value.isUndefined())
|
||||
{
|
||||
constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
// QLatin1String used instead of QStringLiteral below since the latter causes an internal compiler bug
|
||||
// in GCC 8 and higher
|
||||
if (required) { throw CJsonException(QLatin1String("Missing required member '%1'").arg(member.latin1Name())); }
|
||||
}
|
||||
else
|
||||
{
|
||||
CJsonScope scope(member.latin1Name());
|
||||
Q_UNUSED(scope);
|
||||
value >> member.in(*this->derived());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//! Assign from JSON object string
|
||||
void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false)
|
||||
{
|
||||
const QJsonObject jsonObject = BlackMisc::Json::jsonObjectFromString(jsonString, acceptCacheFormat);
|
||||
convertFromJson(jsonObject);
|
||||
}
|
||||
|
||||
//! Get object from QJsonObject
|
||||
template<class DerivedObj = Derived>
|
||||
static DerivedObj fromJson(const QJsonObject &json)
|
||||
{
|
||||
DerivedObj obj;
|
||||
obj.convertFromJson(json);
|
||||
return obj;
|
||||
}
|
||||
|
||||
//! Get object from JSON string
|
||||
template<class DerivedObj = Derived>
|
||||
static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson = false)
|
||||
{
|
||||
DerivedObj obj;
|
||||
if (jsonString.isEmpty()) { return obj; }
|
||||
const QJsonObject jsonObj = acceptCacheJson ? Json::swiftDataObjectValue(jsonString) : Json::jsonObjectFromString(jsonString);
|
||||
obj.convertFromJson(jsonObj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
//! Get object from JSON string
|
||||
template<class DerivedObj = Derived>
|
||||
static Derived fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg)
|
||||
{
|
||||
success = false;
|
||||
Derived obj;
|
||||
try
|
||||
{
|
||||
if (jsonString.isEmpty()) { return obj; }
|
||||
const QJsonObject jsonObj = acceptCacheJson ? Json::swiftDataObjectValue(jsonString) : Json::jsonObjectFromString(jsonString);
|
||||
obj.convertFromJson(jsonObj);
|
||||
success = true;
|
||||
}
|
||||
catch (const CJsonException &ex)
|
||||
{
|
||||
errMsg = ex.toString("JSON conversion");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
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 &) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::JsonByTuple,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
#define BLACKMISC_DECLARE_USING_MIXIN_JSON(DERIVED) \
|
||||
using ::BlackMisc::Mixin::JsonByMetaClass<DERIVED>::toJson; \
|
||||
using ::BlackMisc::Mixin::JsonByMetaClass<DERIVED>::convertFromJson;
|
||||
} // Mixin ns
|
||||
} // guard
|
||||
|
||||
#endif // guard
|
||||
100
src/blackmisc/mixin/mixinmetatype.h
Normal file
100
src/blackmisc/mixin/mixinmetatype.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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. 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_MIXIN_MIXINMETATYPE_H
|
||||
#define BLACKMISC_MIXIN_MIXINMETATYPE_H
|
||||
|
||||
#include "blackmisc/inheritancetraits.h"
|
||||
#include "blackmisc/variantprivate.h"
|
||||
#include <QMetaType>
|
||||
#include <QtGlobal>
|
||||
#include <QString>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit common methods dealing with the metatype of the class.
|
||||
*
|
||||
* \see BLACKMISC_DECLARE_USING_MIXIN_METATYPE
|
||||
*/
|
||||
template <class Derived>
|
||||
class MetaType
|
||||
{
|
||||
public:
|
||||
//! Register metadata
|
||||
static void registerMetadata()
|
||||
{
|
||||
Private::MetaTypeHelper<Derived>::maybeRegisterMetaType();
|
||||
}
|
||||
|
||||
//! Returns the Qt meta type ID of this object
|
||||
//! \remark for CVariant this returns the id of CVariant, not of the encapsulated object. valueVariant.userType()` returns metatype of the contained object
|
||||
int getMetaTypeId() const
|
||||
{
|
||||
return Private::MetaTypeHelper<Derived>::maybeGetMetaTypeId();
|
||||
}
|
||||
|
||||
//! Class name
|
||||
QString getClassName() const
|
||||
{
|
||||
return QMetaType::typeName(getMetaTypeId());
|
||||
}
|
||||
|
||||
//! Returns true if this object is an instance of the class with the given meta type ID, or one of its subclasses.
|
||||
bool isA(int metaTypeId) const
|
||||
{
|
||||
if (metaTypeId == QMetaType::UnknownType) { return false; }
|
||||
if (metaTypeId == getMetaTypeId()) { return true; }
|
||||
return baseIsA(static_cast<const TMetaBaseOfT<Derived> *>(derived()), metaTypeId);
|
||||
}
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
|
||||
template <typename Base2> static bool baseIsA(const Base2 *base, int metaTypeId) { return base->isA(metaTypeId); }
|
||||
static bool baseIsA(const void *, int) { return false; }
|
||||
};
|
||||
|
||||
// *INDENT-OFF*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::MetaType,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_METATYPE(DERIVED) \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::registerMetadata; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::getMetaTypeId; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::getClassName; \
|
||||
using ::BlackMisc::Mixin::MetaType<DERIVED>::isA;
|
||||
// *INDENT-ON*
|
||||
|
||||
} // Mixin
|
||||
|
||||
/*!
|
||||
* This registers the value type T with the BlackMisc meta type system,
|
||||
* making it available for use with the extended feature set of BlackMisc::CVariant.
|
||||
*
|
||||
* The implementation (ab)uses the QMetaType converter function registration mechanism
|
||||
* to store a type-erased representation of the set of operations supported by T.
|
||||
*/
|
||||
template <typename T>
|
||||
void registerMetaValueType()
|
||||
{
|
||||
if (QMetaType::hasRegisteredConverterFunction<T, Private::IValueObjectMetaInfo *>()) { return; }
|
||||
auto converter = [](const T &) { static Private::CValueObjectMetaInfo<T> info; return &info; };
|
||||
bool ok = QMetaType::registerConverter<T, Private::IValueObjectMetaInfo *>(converter);
|
||||
Q_ASSERT(ok);
|
||||
Q_UNUSED(ok);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
98
src/blackmisc/mixin/mixinstring.h
Normal file
98
src/blackmisc/mixin/mixinstring.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* Copyright (C) 2015
|
||||
* 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. 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_MIXIN_MIXINSTRING_H
|
||||
#define BLACKMISC_MIXIN_MIXINSTRING_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QStringRef>
|
||||
#include <QStringView>
|
||||
#include <QTextStream>
|
||||
#include <QtGlobal>
|
||||
#include <string>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Mixin
|
||||
{
|
||||
/*!
|
||||
* CRTP class template from which a derived class can inherit string streaming operations.
|
||||
*
|
||||
* \tparam Derived Must implement a public method QString convertToQString(bool i18n = false) const.
|
||||
*
|
||||
* \see BLACKMISC_DECLARE_USING_MIXIN_STRING
|
||||
*/
|
||||
template <class Derived>
|
||||
class String
|
||||
{
|
||||
public:
|
||||
//! Stream << overload to be used in debugging messages
|
||||
friend QDebug operator<<(QDebug debug, const Derived &obj)
|
||||
{
|
||||
debug << obj.stringForStreaming();
|
||||
return debug;
|
||||
}
|
||||
|
||||
//! Operator << when there is no debug stream
|
||||
friend QNoDebug operator<<(QNoDebug nodebug, const Derived &obj)
|
||||
{
|
||||
Q_UNUSED(obj)
|
||||
return nodebug;
|
||||
}
|
||||
|
||||
//! Operator << based on text stream
|
||||
friend QTextStream &operator<<(QTextStream &stream, const Derived &obj)
|
||||
{
|
||||
stream << obj.stringForStreaming();
|
||||
return stream;
|
||||
}
|
||||
|
||||
//! Stream operator << for std::cout
|
||||
friend std::ostream &operator<<(std::ostream &ostr, const Derived &obj)
|
||||
{
|
||||
ostr << obj.stringForStreaming().toStdString();
|
||||
return ostr;
|
||||
}
|
||||
|
||||
//! Cast as QString
|
||||
QString toQString(bool i18n = false) const { return derived()->convertToQString(i18n); }
|
||||
|
||||
//! Cast to pretty-printed QString
|
||||
//! \deprecated not really used and just using toQString
|
||||
QString toFormattedQString(bool i18n = false) const { return derived()->toQString(i18n); }
|
||||
|
||||
//! To std string
|
||||
std::string toStdString(bool i18n = false) const { return derived()->convertToQString(i18n).toStdString(); }
|
||||
|
||||
//! String for streaming operators
|
||||
QString stringForStreaming() const { return derived()->convertToQString(); }
|
||||
|
||||
private:
|
||||
const Derived *derived() const { return static_cast<const Derived *>(this); }
|
||||
Derived *derived() { return static_cast<Derived *>(this); }
|
||||
};
|
||||
|
||||
// *INDENT-OFF*
|
||||
/*!
|
||||
* When a derived class and a base class both inherit from Mixin::String,
|
||||
* the derived class uses this macro to disambiguate the inherited members.
|
||||
*/
|
||||
# define BLACKMISC_DECLARE_USING_MIXIN_STRING(DERIVED) \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toFormattedQString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::toStdString; \
|
||||
using ::BlackMisc::Mixin::String<DERIVED>::stringForStreaming;
|
||||
// *INDENT-ON*
|
||||
} // ns
|
||||
} // ns
|
||||
|
||||
#endif // guard
|
||||
Reference in New Issue
Block a user