diff --git a/src/blackmisc/algorithm.h b/src/blackmisc/algorithm.h index ca4aedc62..b1fee7faf 100644 --- a/src/blackmisc/algorithm.h +++ b/src/blackmisc/algorithm.h @@ -12,6 +12,8 @@ #ifndef BLACKMISC_ALGORITHM_H #define BLACKMISC_ALGORITHM_H +#include "integersequence.h" + #include #include #include @@ -138,6 +140,50 @@ namespace BlackMisc "BlackMisc::topologicallySortedInsert", "Cyclic less-than relation detected (not a partial ordering)"); container.insert(rit.base(), std::forward(value)); } + + namespace Private + { + //! \private + template + void tupleForEachImpl(T &&tuple, F &&visitor, index_sequence) + { + // parameter pack swallow idiom + static_cast(std::initializer_list + { + (static_cast(std::forward(visitor)(std::get(std::forward(tuple)))), 0)... + }); + } + //! \private + template + void tupleForEachPairImpl(T &&tuple, F &&visitor, index_sequence) + { + // parameter pack swallow idiom + static_cast(std::initializer_list + { + (static_cast(std::forward(visitor)(std::get(std::forward(tuple)), std::get(std::forward(tuple)))), 0)... + }); + } + } + + /*! + * Invoke a visitor function on each element of a tuple in order. + */ + template + void tupleForEach(T &&tuple, F &&visitor) + { + using seq = Private::make_index_sequence>::value>; + return Private::tupleForEachImpl(std::forward(tuple), std::forward(visitor), seq()); + } + + /*! + * Invoke a visitor function on each pair of elements of a tuple in order. + */ + template + void tupleForEachPair(T &&tuple, F &&visitor) + { + using seq = Private::make_index_sequence>::value / 2>; + return Private::tupleForEachPairImpl(std::forward(tuple), std::forward(visitor), seq()); + } } #endif diff --git a/src/blackmisc/predicates.h b/src/blackmisc/predicates.h index f3d21feec..97168f10a 100644 --- a/src/blackmisc/predicates.h +++ b/src/blackmisc/predicates.h @@ -15,6 +15,7 @@ #define BLACKMISC_PREDICATES_H #include "integersequence.h" +#include "algorithm.h" #include #include @@ -29,69 +30,6 @@ namespace BlackMisc namespace Private { - - //! \private - template struct MemberEqual; - - //! \private - template struct MemberEqual - { - M m; - V v; - MemberEqual(M m_, V v_) : m(m_), v(v_) {} - template bool operator()(const T &obj) const { return (obj.*m)() == v; } - }; - - //! \private - template struct MemberEqual - { - MemberEqual head; - MemberEqual tail; - MemberEqual(M m, V v, Tail... tail_) : head(m, v), tail(tail_...) {} - template bool operator()(const T &obj) const { return head(obj) && tail(obj); } - }; - - //! \private - template struct MemberLess; - - //! \private - template struct MemberLess - { - M m; - MemberLess(M m_) : m(m_) {} - template bool operator()(const T &a, const T &b) const { return (a.*m)() < (b.*m)(); } - template bool isStable(const T &a, const T &b) const { return (a.*m)() != (b.*m)(); } - }; - - //! \private - template struct MemberLess - { - MemberLess head; - MemberLess tail; - MemberLess(M m, Tail... tail_) : head(m), tail(tail_...) {} - 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 { @@ -99,8 +37,7 @@ namespace BlackMisc Matches(const CPropertyIndexVariantMap &map) : m_map(map) {} template bool operator()(const T &value) const; }; - - } //namespace Private + } /*! * Predicate which tests whether some member functions return some values. @@ -108,9 +45,14 @@ namespace BlackMisc * \return A unary functor whose operator() which will perform the actual test. */ template - Private::MemberEqual MemberEqual(Ts... vs) + auto MemberEqual(Ts... vs) { - return { vs... }; + return [vs...](const auto &object) + { + bool equal = true; + tupleForEachPair(std::make_tuple(vs...), [ & ](auto member, const auto &value) { equal = equal && (object.*member)() == value; }); + return equal; + }; } /*! @@ -119,9 +61,19 @@ namespace BlackMisc * \return A binary functor whose operator() which will perform the actual test. */ template - Private::MemberLess MemberLess(Ts... vs) + auto MemberLess(Ts... vs) { - return { vs... }; + return [vs...](const auto &a, const auto &b) + { + bool less = true; + bool greater = false; + tupleForEach(std::make_tuple(vs...), [ & ](auto member) + { + less = less && ! greater && (a.*member)() < (b.*member)(); + greater = (b.*member)() < (a.*member)(); + }); + return less; + }; } /*! @@ -165,9 +117,14 @@ namespace BlackMisc * 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) + auto EqualsByMembers(Ts... vs) { - return { vs... }; + return [vs...](const auto &a, const auto &b) + { + bool equal = true; + tupleForEach(std::make_tuple(vs...), [ & ](auto member) { equal = equal && (a.*member)() == (b.*member)(); }); + return equal; + }; } /*!