File indexing completed on 2024-05-12 16:59:21

0001 /*
0002  *   SPDX-FileCopyrightText: 2015-2016 Ivan Cukic <ivan.cukic@kde.org>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #ifndef UTILS_MEMBER_MATCHER_H
0008 #define UTILS_MEMBER_MATCHER_H
0009 
0010 namespace kamd
0011 {
0012 namespace utils
0013 {
0014 namespace member_matcher
0015 {
0016 struct placeholder {
0017 } _;
0018 
0019 namespace detail
0020 { //_
0021 enum ComparisonOperation {
0022     Less,
0023     LessOrEqual,
0024     Equal,
0025     GreaterOrEqual,
0026     Greater,
0027 };
0028 
0029 // Member comparison object
0030 // Call operator returns true if:
0031 //     collection item <comparison> specified item
0032 // where <comparison> can be <, >, ==, >=, <=
0033 template<typename Member, typename Value>
0034 struct member_comparator { //_
0035 
0036     member_comparator(ComparisonOperation comparison, Member member, Value value)
0037         : m_comparator(comparison)
0038         , m_member(member)
0039         , m_value(value)
0040     {
0041     }
0042 
0043     const ComparisonOperation m_comparator;
0044     const Member m_member;
0045     const Value m_value;
0046 
0047     // When passing only a item to compare with,
0048     // it means that we already have the value for comparison.
0049     // For example (member(M) > 5)(2)
0050     template<typename T>
0051     inline bool operator()(const T &collItem) const
0052     {
0053         return operator()(collItem, m_value);
0054     }
0055 
0056     // When passing the placeholder aka 'ignore' as a value,
0057     // it means that we already have the value for comparison.
0058     // For example (member(M) > 5)(collItem, _)
0059     template<typename T>
0060     inline bool operator()(const T &collItem, const placeholder &) const
0061     {
0062         return operator()(collItem, m_value);
0063     }
0064 
0065     // Like the previous one, but with reversed argument order
0066     template<typename T>
0067     inline bool operator()(const placeholder &, const T &collItem) const
0068     {
0069         return compare(m_value, (collItem.*m_member)());
0070     }
0071 
0072     // Comparing two values
0073     // For example (member(M) > _)(item, 5)
0074     template<typename T, typename V>
0075     inline bool operator()(const T &collItem, const V &value) const
0076     {
0077         // TODO: Make this work if the arguments are reversed,
0078         //       or even if both arguments need to be checked
0079         //       for the specified member
0080         return compare((collItem.*m_member)(), value);
0081     }
0082 
0083 private:
0084     template<typename Left, typename Right>
0085     inline bool compare(const Left &left, const Right &right) const
0086     {
0087         return m_comparator == Less          ? left < right
0088             : m_comparator == LessOrEqual    ? left <= right
0089             : m_comparator == Equal          ? left == right
0090             : m_comparator == GreaterOrEqual ? left >= right
0091             : m_comparator == Greater        ? left > right
0092                                              : false;
0093     }
0094 
0095 }; //^
0096 
0097 // Chaining multiple comparators to achieve lexicographical
0098 // comparison of multiple members in order.
0099 // This would me so much nicer with variadic templates... f**ing MSVC.
0100 template<typename First, typename Second>
0101 struct member_comparator_chain {
0102     member_comparator_chain(First first, Second second)
0103         : first(first)
0104         , second(second)
0105     {
0106     }
0107 
0108     // Implement if needed...
0109     // template <typename T>
0110     // inline bool operator()(const T &item) const
0111     // {
0112     //     return first(item) || second(item);
0113     // }
0114 
0115     template<typename T, typename V>
0116     inline bool operator()(const T &item, const V &value) const
0117     {
0118         return first(item, value) || (!first(value, item) && second(item, value));
0119     }
0120 
0121     First first;
0122     Second second;
0123 };
0124 
0125 template<typename First, typename Second>
0126 inline member_comparator_chain<First, Second> operator&&(First first, Second second)
0127 {
0128     return member_comparator_chain<First, Second>(first, second);
0129 }
0130 
0131 // Provides syntax sugar for building member comparators
0132 template<typename Member>
0133 struct member_matcher { //_
0134     member_matcher(Member m)
0135         : m_member(m)
0136     {
0137     }
0138 
0139 #define IMPLEMENT_COMPARISON_OPERATOR(OPERATOR, NAME)                                                                                                          \
0140     template<typename Value>                                                                                                                                   \
0141     inline member_comparator<Member, Value> operator OPERATOR(const Value &value) const                                                                        \
0142     {                                                                                                                                                          \
0143         return member_comparator<Member, Value>(NAME, m_member, value);                                                                                        \
0144     }
0145 
0146     IMPLEMENT_COMPARISON_OPERATOR(<, Less)
0147     IMPLEMENT_COMPARISON_OPERATOR(<=, LessOrEqual)
0148     IMPLEMENT_COMPARISON_OPERATOR(==, Equal)
0149     IMPLEMENT_COMPARISON_OPERATOR(>=, GreaterOrEqual)
0150     IMPLEMENT_COMPARISON_OPERATOR(>, Greater)
0151 
0152 #undef IMPLEMENT_COMPARISON_OPERATOR
0153 
0154     Member m_member;
0155 }; //^
0156 
0157 } //^ namespace detail
0158 
0159 template<typename Member>
0160 detail::member_matcher<Member> member(Member m)
0161 {
0162     return detail::member_matcher<Member>(m);
0163 }
0164 } // namespace member
0165 
0166 } // namespace utils
0167 } // namespace kamd
0168 
0169 #endif // UTILS_MEMBER_MATCHER_H