]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Copyright 2019 Hans Dembinski |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt | |
5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #ifndef BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP | |
8 | #define BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP | |
9 | ||
10 | #include <boost/histogram/detail/detect.hpp> | |
11 | #include <boost/mp11/algorithm.hpp> | |
12 | #include <boost/mp11/list.hpp> | |
13 | #include <boost/mp11/utility.hpp> | |
20effc67 | 14 | #include <type_traits> |
92f5a8d4 TL |
15 | |
16 | namespace boost { | |
17 | namespace histogram { | |
18 | namespace detail { | |
19 | ||
20 | template <class T, class U> | |
20effc67 TL |
21 | using if_not_same = std::enable_if_t<(!std::is_same<T, U>::value), bool>; |
22 | ||
23 | // template <class T, class U> | |
24 | // using if_not_same_and_has_eq = | |
25 | // std::enable_if_t<(!std::is_same<T, U>::value && !has_method_eq<T, U>::value), | |
26 | // bool>; | |
92f5a8d4 TL |
27 | |
28 | // totally_ordered is for types with a <= b == !(a > b) [floats with NaN violate this] | |
29 | // Derived must implement <,== for symmetric form and <,>,== for non-symmetric. | |
30 | ||
31 | // partially_ordered is for types with a <= b == a < b || a == b [for floats with NaN] | |
20effc67 | 32 | // Derived must implement <,== for symmetric form and <,>,== for non-symmetric. |
92f5a8d4 TL |
33 | |
34 | template <class T, class U> | |
35 | struct mirrored { | |
36 | friend bool operator<(const U& a, const T& b) noexcept { return b > a; } | |
37 | friend bool operator>(const U& a, const T& b) noexcept { return b < a; } | |
38 | friend bool operator==(const U& a, const T& b) noexcept { return b == a; } | |
39 | friend bool operator<=(const U& a, const T& b) noexcept { return b >= a; } | |
40 | friend bool operator>=(const U& a, const T& b) noexcept { return b <= a; } | |
41 | friend bool operator!=(const U& a, const T& b) noexcept { return b != a; } | |
20effc67 | 42 | }; // namespace histogram |
92f5a8d4 TL |
43 | |
44 | template <class T> | |
45 | struct mirrored<T, void> { | |
46 | template <class U> | |
20effc67 | 47 | friend if_not_same<T, U> operator<(const U& a, const T& b) noexcept { |
92f5a8d4 TL |
48 | return b > a; |
49 | } | |
50 | template <class U> | |
20effc67 | 51 | friend if_not_same<T, U> operator>(const U& a, const T& b) noexcept { |
92f5a8d4 TL |
52 | return b < a; |
53 | } | |
54 | template <class U> | |
20effc67 TL |
55 | friend std::enable_if_t<(!has_method_eq<U, T>::value), bool> operator==( |
56 | const U& a, const T& b) noexcept { | |
57 | return b.operator==(a); | |
92f5a8d4 TL |
58 | } |
59 | template <class U> | |
20effc67 | 60 | friend if_not_same<T, U> operator<=(const U& a, const T& b) noexcept { |
92f5a8d4 TL |
61 | return b >= a; |
62 | } | |
63 | template <class U> | |
20effc67 | 64 | friend if_not_same<T, U> operator>=(const U& a, const T& b) noexcept { |
92f5a8d4 TL |
65 | return b <= a; |
66 | } | |
67 | template <class U> | |
20effc67 | 68 | friend if_not_same<T, U> operator!=(const U& a, const T& b) noexcept { |
92f5a8d4 TL |
69 | return b != a; |
70 | } | |
71 | }; | |
72 | ||
73 | template <class T> | |
74 | struct mirrored<T, T> { | |
75 | friend bool operator>(const T& a, const T& b) noexcept { return b.operator<(a); } | |
76 | }; | |
77 | ||
78 | template <class T, class U> | |
79 | struct equality { | |
80 | friend bool operator!=(const T& a, const U& b) noexcept { return !a.operator==(b); } | |
81 | }; | |
82 | ||
83 | template <class T> | |
84 | struct equality<T, void> { | |
85 | template <class U> | |
20effc67 | 86 | friend if_not_same<T, U> operator!=(const T& a, const U& b) noexcept { |
92f5a8d4 TL |
87 | return !(a == b); |
88 | } | |
89 | }; | |
90 | ||
91 | template <class T, class U> | |
92 | struct totally_ordered_impl : equality<T, U>, mirrored<T, U> { | |
93 | friend bool operator<=(const T& a, const U& b) noexcept { return !(a > b); } | |
94 | friend bool operator>=(const T& a, const U& b) noexcept { return !(a < b); } | |
95 | }; | |
96 | ||
97 | template <class T> | |
98 | struct totally_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> { | |
99 | template <class U> | |
20effc67 | 100 | friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept { |
92f5a8d4 TL |
101 | return !(a > b); |
102 | } | |
103 | template <class U> | |
20effc67 | 104 | friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept { |
92f5a8d4 TL |
105 | return !(a < b); |
106 | } | |
107 | }; | |
108 | ||
109 | template <class T, class... Ts> | |
110 | using totally_ordered = mp11::mp_rename< | |
111 | mp11::mp_product<totally_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >, | |
112 | mp11::mp_inherit>; | |
113 | ||
114 | template <class T, class U> | |
115 | struct partially_ordered_impl : equality<T, U>, mirrored<T, U> { | |
116 | friend bool operator<=(const T& a, const U& b) noexcept { return a < b || a == b; } | |
117 | friend bool operator>=(const T& a, const U& b) noexcept { return a > b || a == b; } | |
118 | }; | |
119 | ||
120 | template <class T> | |
121 | struct partially_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> { | |
122 | template <class U> | |
20effc67 | 123 | friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept { |
92f5a8d4 TL |
124 | return a < b || a == b; |
125 | } | |
126 | template <class U> | |
20effc67 | 127 | friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept { |
92f5a8d4 TL |
128 | return a > b || a == b; |
129 | } | |
130 | }; | |
131 | ||
132 | template <class T, class... Ts> | |
133 | using partially_ordered = mp11::mp_rename< | |
134 | mp11::mp_product<partially_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >, | |
135 | mp11::mp_inherit>; | |
136 | ||
137 | } // namespace detail | |
138 | } // namespace histogram | |
139 | } // namespace boost | |
140 | ||
141 | #endif // BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP |