refs #345 Added a metatuple flag for case insensitive comparisons, so CAirportIcao and CCallsign comparisons can use metatuples.

This commit is contained in:
Mathew Sutcliffe
2014-10-31 23:10:17 +00:00
parent 1283d50737
commit ecf8e6aafb
6 changed files with 59 additions and 22 deletions

View File

@@ -27,7 +27,7 @@ namespace BlackMisc
int CAirportIcao::compareImpl(const CValueObject &otherBase) const int CAirportIcao::compareImpl(const CValueObject &otherBase) const
{ {
const auto &other = static_cast<const CAirportIcao &>(otherBase); const auto &other = static_cast<const CAirportIcao &>(otherBase);
return this->m_icaoCode.compare(other.m_icaoCode, Qt::CaseInsensitive); return compare(TupleConverter<CAirportIcao>::toMetaTuple(*this), TupleConverter<CAirportIcao>::toMetaTuple(other));
} }
/* /*
@@ -96,7 +96,7 @@ namespace BlackMisc
bool CAirportIcao::operator ==(const CAirportIcao &other) const bool CAirportIcao::operator ==(const CAirportIcao &other) const
{ {
if (this == &other) return true; if (this == &other) return true;
return this->asString().compare(other.asString(), Qt::CaseInsensitive) == 0; return TupleConverter<CAirportIcao>::toMetaTuple(*this) == TupleConverter<CAirportIcao>::toMetaTuple(other);
} }
/* /*

View File

@@ -106,7 +106,9 @@ namespace BlackMisc
} // namespace } // namespace
} // namespace } // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CAirportIcao, (o.m_icaoCode)) BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CAirportIcao, (
attr(o.m_icaoCode, flags<CaseInsensitiveComparison>())
))
Q_DECLARE_METATYPE(BlackMisc::Aviation::CAirportIcao) Q_DECLARE_METATYPE(BlackMisc::Aviation::CAirportIcao)
#endif // guard #endif // guard

View File

@@ -85,7 +85,7 @@ namespace BlackMisc
int CCallsign::compareImpl(const CValueObject &otherBase) const int CCallsign::compareImpl(const CValueObject &otherBase) const
{ {
const auto &other = static_cast<const CCallsign &>(otherBase); const auto &other = static_cast<const CCallsign &>(otherBase);
return this->m_callsign.compare(other.m_callsign, Qt::CaseInsensitive); return compare(TupleConverter<CCallsign>::toMetaTuple(*this), TupleConverter<CCallsign>::toMetaTuple(other));
} }
/* /*
@@ -181,7 +181,7 @@ namespace BlackMisc
bool CCallsign::operator ==(const CCallsign &other) const bool CCallsign::operator ==(const CCallsign &other) const
{ {
if (this == &other) return true; if (this == &other) return true;
return this->asString().compare(other.asString(), Qt::CaseInsensitive) == 0; return TupleConverter<CCallsign>::toMetaTuple(*this) == TupleConverter<CCallsign>::toMetaTuple(other);
} }
/* /*

View File

@@ -139,7 +139,11 @@ namespace BlackMisc
} // namespace } // namespace
} // namespace } // namespace
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CCallsign, (o.m_callsign, o.m_callsignAsSet, o.m_telephonyDesignator)) BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Aviation::CCallsign, (
attr(o.m_callsign, flags<CaseInsensitiveComparison>()),
attr(o.m_callsignAsSet, flags<DisabledForComparison>()),
attr(o.m_telephonyDesignator, flags<DisabledForComparison>())
))
Q_DECLARE_METATYPE(BlackMisc::Aviation::CCallsign) Q_DECLARE_METATYPE(BlackMisc::Aviation::CCallsign)
#endif // guard #endif // guard

View File

@@ -26,7 +26,8 @@ namespace BlackMisc
DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling
DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug
DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash() DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash()
DisabledForJson = 1 << 4 //!< Element will be ignored during JSON serialization DisabledForJson = 1 << 4, //!< Element will be ignored during JSON serialization
CaseInsensitiveComparison = 1 << 5 //!< Element will be compared case insensitively (must be a QString)
}; };
} }
@@ -305,10 +306,9 @@ namespace BlackMisc
template <class... Ts> template <class... Ts>
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b) int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
{ {
auto valuesA = Private::stripMeta(a, Private::make_index_sequence<sizeof...(Ts)>()); auto metaA = Private::recoverMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
auto valuesB = Private::stripMeta(b, Private::make_index_sequence<sizeof...(Ts)>()); auto metaB = Private::recoverMeta(b, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(a, Private::make_index_sequence<sizeof...(Ts)>()); return Private::TupleHelper::compare_(metaA, metaB, Private::skipFlaggedIndices<DisabledForComparison>(metaA));
return Private::TupleHelper::compare(valuesA, valuesB, Private::skipFlaggedIndices<DisabledForComparison>(metaTu));
} }
/*! /*!

View File

@@ -116,9 +116,47 @@ namespace BlackMisc
return {}; 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<CValueObject, T>::type;
friend int compare(const Derived &a, const Derived &b) { return compareHelper(a.m_obj, b.m_obj, isCValueObject<decltype(a.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; }
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. // A tuple element with attached metadata.
template <class T, qint64 Flags = 0> template <class T, qint64 Flags = 0>
struct Attribute struct Attribute : public AttributeComparable<Attribute<T, Flags>, Flags & DisabledForComparison, Flags & CaseInsensitiveComparison>
{ {
typedef T type; typedef T type;
static const qint64 flags = Flags; static const qint64 flags = Flags;
@@ -127,13 +165,6 @@ namespace BlackMisc
void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; } void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; }
T &m_obj; T &m_obj;
QString m_jsonName; QString m_jsonName;
friend bool operator ==(const Attribute &a, const Attribute &b) { return a.m_obj == b.m_obj; }
friend bool operator !=(const Attribute &a, const Attribute &b) { return a.m_obj != b.m_obj; }
friend bool operator <(const Attribute &a, const Attribute &b) { return a.m_obj < b.m_obj; }
friend bool operator <=(const Attribute &a, const Attribute &b) { return a.m_obj <= b.m_obj; }
friend bool operator >(const Attribute &a, const Attribute &b) { return a.m_obj > b.m_obj; }
friend bool operator >=(const Attribute &a, const Attribute &b) { return a.m_obj >= b.m_obj; }
}; };
// Helpers used in tie(), tieMeta(), and elsewhere, which arrange for the correct types to be passed to std::make_tuple. // Helpers used in tie(), tieMeta(), and elsewhere, which arrange for the correct types to be passed to std::make_tuple.
@@ -193,9 +224,9 @@ namespace BlackMisc
{ {
public: public:
template <class Tu, size_t... Is> template <class Tu, size_t... Is>
static int compare(const Tu &a, const Tu &b, index_sequence<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(get_ref<Is>(a), get_ref<Is>(b))...); return compareImpl(std::make_pair(std::get<Is>(a), std::get<Is>(b))...);
} }
template <class Tu, size_t... Is> template <class Tu, size_t... Is>
@@ -260,7 +291,7 @@ namespace BlackMisc
template <class T, class... Ts> template <class T, class... Ts>
static int compareImpl(const std::pair<T, T> &head, const Ts &... tail) static int compareImpl(const std::pair<T, T> &head, const Ts &... tail)
{ {
int result = compareHelper(head.first, head.second, typename std::is_base_of<CValueObject, typename std::decay<T>::type>::type()); int result = compare(head.first, head.second);
if (result) return result; if (result) return result;
return compareImpl(tail...); return compareImpl(tail...);
} }