]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | #ifndef BOOST_NUMERIC_SAFE_COMPARE_HPP |
2 | #define BOOST_NUMERIC_SAFE_COMPARE_HPP | |
3 | ||
4 | // Copyright (c) 2012 Robert Ramey | |
5 | // | |
6 | // Distributed under the Boost Software License, Version 1.0. (See | |
7 | // accompanying file LICENSE_1_0.txt or copy at | |
8 | // http://www.boost.org/LICENSE_1_0.txt) | |
9 | ||
10 | #include <type_traits> | |
11 | #include <limits> | |
12 | ||
13 | namespace boost { | |
14 | namespace safe_numerics { | |
15 | namespace safe_compare { | |
16 | ||
17 | //////////////////////////////////////////////////// | |
18 | // safe comparison on primitive integral types | |
19 | namespace safe_compare_detail { | |
20 | template<typename T> | |
21 | using make_unsigned = typename std::conditional< | |
22 | std::is_signed<T>::value, | |
23 | std::make_unsigned<T>, | |
24 | T | |
25 | >::type; | |
26 | ||
27 | // both arguments unsigned or signed | |
28 | template<bool TS, bool US> | |
29 | struct less_than { | |
30 | template<class T, class U> | |
31 | constexpr static bool invoke(const T & t, const U & u){ | |
32 | return t < u; | |
33 | } | |
34 | }; | |
35 | ||
36 | // T unsigned, U signed | |
37 | template<> | |
38 | struct less_than<false, true> { | |
39 | template<class T, class U> | |
40 | constexpr static bool invoke(const T & t, const U & u){ | |
41 | return | |
42 | (u < 0) ? | |
43 | false | |
44 | : | |
45 | less_than<false, false>::invoke( | |
46 | t, | |
47 | static_cast<const typename make_unsigned<U>::type &>(u) | |
48 | ) | |
49 | ; | |
50 | } | |
51 | }; | |
52 | // T signed, U unsigned | |
53 | template<> | |
54 | struct less_than<true, false> { | |
55 | template<class T, class U> | |
56 | constexpr static bool invoke(const T & t, const U & u){ | |
57 | return | |
58 | (t < 0) ? | |
59 | true | |
60 | : | |
61 | less_than<false, false>::invoke( | |
62 | static_cast<const typename make_unsigned<T>::type &>(t), | |
63 | u | |
64 | ) | |
65 | ; | |
66 | } | |
67 | }; | |
68 | } // safe_compare_detail | |
69 | ||
70 | template<class T, class U> | |
71 | typename std::enable_if< | |
72 | std::is_integral<T>::value && std::is_integral<U>::value, | |
73 | bool | |
74 | >::type | |
75 | constexpr less_than(const T & lhs, const U & rhs) { | |
76 | return safe_compare_detail::less_than< | |
77 | std::is_signed<T>::value, | |
78 | std::is_signed<U>::value | |
79 | >::template invoke(lhs, rhs); | |
80 | } | |
81 | ||
82 | template<class T, class U> | |
83 | typename std::enable_if< | |
84 | std::is_floating_point<T>::value && std::is_floating_point<U>::value, | |
85 | bool | |
86 | >::type | |
87 | constexpr less_than(const T & lhs, const U & rhs) { | |
88 | return lhs < rhs; | |
89 | } | |
90 | ||
91 | template<class T, class U> | |
92 | constexpr bool greater_than(const T & lhs, const U & rhs) { | |
93 | return less_than(rhs, lhs); | |
94 | } | |
95 | ||
96 | template<class T, class U> | |
97 | constexpr bool less_than_equal(const T & lhs, const U & rhs) { | |
98 | return ! greater_than(lhs, rhs); | |
99 | } | |
100 | ||
101 | template<class T, class U> | |
102 | constexpr bool greater_than_equal(const T & lhs, const U & rhs) { | |
103 | return ! less_than(lhs, rhs); | |
104 | } | |
105 | ||
106 | namespace safe_compare_detail { | |
107 | // both arguments unsigned or signed | |
108 | template<bool TS, bool US> | |
109 | struct equal { | |
110 | template<class T, class U> | |
111 | constexpr static bool invoke(const T & t, const U & u){ | |
112 | return t == u; | |
113 | } | |
114 | }; | |
115 | ||
116 | // T unsigned, U signed | |
117 | template<> | |
118 | struct equal<false, true> { | |
119 | template<class T, class U> | |
120 | constexpr static bool invoke(const T & t, const U & u){ | |
121 | return | |
122 | (u < 0) ? | |
123 | false | |
124 | : | |
125 | equal<false, false>::invoke( | |
126 | t, | |
127 | static_cast<const typename make_unsigned<U>::type &>(u) | |
128 | ) | |
129 | ; | |
130 | } | |
131 | }; | |
132 | // T signed, U unsigned | |
133 | template<> | |
134 | struct equal<true, false> { | |
135 | template<class T, class U> | |
136 | constexpr static bool invoke(const T & t, const U & u){ | |
137 | return | |
138 | (t < 0) ? | |
139 | false | |
140 | : | |
141 | equal<false, false>::invoke( | |
142 | static_cast<const typename make_unsigned<T>::type &>(t), | |
143 | u | |
144 | ) | |
145 | ; | |
146 | } | |
147 | }; | |
148 | } // safe_compare_detail | |
149 | ||
150 | template<class T, class U> | |
151 | typename std::enable_if< | |
152 | std::is_integral<T>::value && std::is_integral<U>::value, | |
153 | bool | |
154 | >::type | |
155 | constexpr equal(const T & lhs, const U & rhs) { | |
156 | return safe_compare_detail::equal< | |
157 | std::numeric_limits<T>::is_signed, | |
158 | std::numeric_limits<U>::is_signed | |
159 | >::template invoke(lhs, rhs); | |
160 | } | |
161 | ||
162 | template<class T, class U> | |
163 | typename std::enable_if< | |
164 | std::is_floating_point<T>::value && std::is_floating_point<U>::value, | |
165 | bool | |
166 | >::type | |
167 | constexpr equal(const T & lhs, const U & rhs) { | |
168 | return lhs == rhs; | |
169 | } | |
170 | ||
171 | template<class T, class U> | |
172 | constexpr bool not_equal(const T & lhs, const U & rhs) { | |
173 | return ! equal(lhs, rhs); | |
174 | } | |
175 | ||
176 | } // safe_compare | |
177 | } // safe_numerics | |
178 | } // boost | |
179 | ||
180 | #endif // BOOST_NUMERIC_SAFE_COMPARE_HPP |