From bf61657376c5f4827e8fe8df669d319268f51938 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Sat, 2 Jul 2016 01:41:50 +0100 Subject: [PATCH] refs #698 Added equalsBy and equalsByKeys methods for containers. --- src/blackmisc/predicates.h | 29 +++++++++++++++++++++++++++++ src/blackmisc/range.h | 25 +++++++++++++++++++++++++ src/blackmisc/typetraits.h | 10 ++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/blackmisc/predicates.h b/src/blackmisc/predicates.h index 8bbc6955d..f3d21feec 100644 --- a/src/blackmisc/predicates.h +++ b/src/blackmisc/predicates.h @@ -72,6 +72,26 @@ namespace BlackMisc template bool operator()(const T &a, const T &b) const { return head.isStable(a, b) ? head(a, b) : tail(a, b); } }; + //! \private + template struct EqualsByMembers; + + //! \private + template struct EqualsByMembers + { + M m; + EqualsByMembers(M m_) : m(m_) {} + template bool operator()(const T &a, const T &b) const { return (a.*m)() == (b.*m)(); } + }; + + //! \private + template struct EqualsByMembers + { + EqualsByMembers head; + EqualsByMembers tail; + EqualsByMembers(M m, Tail... tail_) : head(m), tail(tail_...) {} + template bool operator()(const T &a, const T &b) const { return head(a, b) && tail(a, b); } + }; + //! \private struct Matches { @@ -141,6 +161,15 @@ namespace BlackMisc return [value = std::forward(value)](const T &object) { return object == value; }; } + /*! + * Returns a predicate that returns true if its arguments compare equal to each other, considering only the captured members. + */ + template + Private::EqualsByMembers EqualsByMembers(Ts... vs) + { + return { vs... }; + } + /*! * Returns a predicate that returns true if its argument matches a captured CPropertyIndexVariantMap. */ diff --git a/src/blackmisc/range.h b/src/blackmisc/range.h index c4b27b905..d422d33d5 100644 --- a/src/blackmisc/range.h +++ b/src/blackmisc/range.h @@ -16,6 +16,7 @@ #include "iterator.h" #include "predicates.h" #include "algorithm.h" +#include "typetraits.h" #include #include #include @@ -110,6 +111,21 @@ namespace BlackMisc return containsBy(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...)); } + //! Return true if this container equals another container according to the given element equality predicate. + template + bool equalsBy(const T &other, Predicate c) const + { + if (equalPointers(&derived(), &other)) { return true; } + return std::equal(derived().begin(), derived().end(), other.begin(), other.end(), c); + } + + //! Return true if this container equals another container, considering only the given element members. + template + bool equalsByKeys(const T &other, Key0 k0, Keys... keys) const + { + return equalsBy(other, BlackMisc::Predicates::EqualsByMembers(k0, keys...)); + } + //! Copy n elements from the container at random. Derived randomElements(int n) const { @@ -126,6 +142,15 @@ namespace BlackMisc return result; } + protected: + //! Efficiently compare addresses of two objects. Return false if types are not compatible. + //! @{ + template ::value, int> = 0> + static bool equalPointers(const T *a, const U *b) { return a == b; } + template ::value, int> = 0> + static bool equalPointers(const T *, const U *) { return false; } + //! @} + private: Derived &derived() { return static_cast(*this); } const Derived &derived() const { return static_cast(*this); } diff --git a/src/blackmisc/typetraits.h b/src/blackmisc/typetraits.h index 4c3f1b6e7..44f3d3d4d 100644 --- a/src/blackmisc/typetraits.h +++ b/src/blackmisc/typetraits.h @@ -102,6 +102,16 @@ namespace BlackMisc struct HasCompare(), std::declval()))>> : public std::true_type {}; //! \endcond + /*! + * Trait which is true if the expression a == b is valid when a and b are instances of T and U. + */ + template > + struct IsEqualityComparable : public std::false_type {}; + //! \cond + template + struct IsEqualityComparable() == std::declval())>> : public std::true_type {}; + //! \endcond + } #endif