File indexing completed on 2024-05-12 05:29:23

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