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
{
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
{
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
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)
#endif // guard

View File

@@ -85,7 +85,7 @@ namespace BlackMisc
int CCallsign::compareImpl(const CValueObject &otherBase) const
{
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
{
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
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)
#endif // guard

View File

@@ -26,7 +26,8 @@ namespace BlackMisc
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
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>
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
{
auto valuesA = Private::stripMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
auto valuesB = Private::stripMeta(b, Private::make_index_sequence<sizeof...(Ts)>());
auto metaTu = Private::recoverMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
return Private::TupleHelper::compare(valuesA, valuesB, Private::skipFlaggedIndices<DisabledForComparison>(metaTu));
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));
}
/*!

View File

@@ -116,9 +116,47 @@ namespace BlackMisc
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.
template <class T, qint64 Flags = 0>
struct Attribute
struct Attribute : public AttributeComparable<Attribute<T, Flags>, Flags & DisabledForComparison, Flags & CaseInsensitiveComparison>
{
typedef T type;
static const qint64 flags = Flags;
@@ -127,13 +165,6 @@ namespace BlackMisc
void extend(QString jsonName) { if (m_jsonName.isEmpty()) m_jsonName = jsonName; }
T &m_obj;
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.
@@ -193,9 +224,9 @@ namespace BlackMisc
{
public:
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>
@@ -260,7 +291,7 @@ namespace BlackMisc
template <class T, class... Ts>
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;
return compareImpl(tail...);
}