-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlex_compare.hpp
114 lines (100 loc) · 3 KB
/
lex_compare.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#ifndef LCO_LEX_COMPARE_HPP
#define LCO_LEX_COMPARE_HPP
namespace lco
{
/**
* Lexicographically compares two objects
* @param lhs Left hand side object to compare
* @param rhs Right hand side object to compare
* @param field First field of the objects to compare
* @param fields The rest of the fields to compare
* @return true if lhs is lexicographically before rhs
*/
template <typename Object, typename Field, typename... Fields>
bool LessThan(const Object& lhs, const Object& rhs, const Field& field, Fields... fields)
{
if (LessThan(lhs, rhs, field))
{
return true;
}
else if (LessThan(rhs, lhs, field))
{
return false;
}
return LessThan(lhs, rhs, fields...);
}
/**
* Lexicographically compares two objects
* @param lhs Left hand side object to compare
* @param rhs Right hand side object to compare
* @param field The field of the objects to compare
* @return true if lhs is lexicographically before rhs
*/
template <typename Object, typename Field>
bool LessThan(const Object& lhs, const Object& rhs, const Field& field)
{
return impl::LessThan(lhs, rhs, field);
}
/**
* A predicate comparator that invokes the wrapped functor
* on the objects to compare and expects the functor to return
* true if lhs is lexicographically smaller than rhs along whatever
* custom comparisons the user wants. Use this only if your compairons
* cannot be directly expressed as comparing two fields of an object
*/
template <typename Object, typename Functor>
class Pred
{
public:
Pred(Functor f)
:f(std::move(f))
{
}
bool operator()(const Object& lhs, const Object& rhs) const
{
return f(lhs, rhs);
}
private:
Functor f;
};
// Helper macro for defining predicates
#define LCOPRED(Object, functor) lco::Pred<Object, decltype(&functor)>(&functor)
// Actual implementations of comparisons on a type-by-type basis to allow heterogenous support of
// fields, methods, and custom functions
namespace impl
{
/**
* Compares the result of a getter function of lhs to that of rhs. ie lhs.method() < rhs.method()
*/
template <typename Object, typename MethodReturn>
bool LessThan(const Object& lhs, const Object& rhs, MethodReturn(Object::*method)() const)
{
return (lhs.*method)() < (rhs.*method)();
}
/**
* Compare a field of lhs to a field of rhs using member variables ie lhs.field < rhs.field
*/
template <typename Object, typename MemberType>
bool LessThan(const Object& lhs, const Object& rhs, MemberType Object::*member)
{
return (lhs.*member) < (rhs.*member);
}
/**
* Compares lhs to rhs using a special predicate which will assume that lhs < rhs if f(lhs, rhs) = true
*/
template <typename Object, typename Functor>
bool LessThan(const Object& lhs, const Object& rhs, const Pred<Object, Functor>& f)
{
return f(lhs, rhs);
}
/**
* Lexicographically compares lhs to rhs by the result of the passed in functor ie f(lhs) < f(rhs)
*/
template <typename Object, typename Functor>
bool LessThan(const Object& lhs, const Object& rhs, const Functor& f)
{
return f(lhs) < f(rhs);
}
} // impl
} // lco
#endif // LCO_LEX_COMPARE_HPP