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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::less_than31 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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::less_than40 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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::less_than56 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
less_than(const T & lhs,const U & rhs)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
less_than(const T & lhs,const U & rhs)87 constexpr less_than(const T & lhs, const U & rhs) {
88 return lhs < rhs;
89 }
90
91 template<class T, class U>
greater_than(const T & lhs,const U & rhs)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>
less_than_equal(const T & lhs,const U & rhs)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>
greater_than_equal(const T & lhs,const U & rhs)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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::equal111 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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::equal120 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>
invokeboost::safe_numerics::safe_compare::safe_compare_detail::equal136 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
equal(const T & lhs,const U & rhs)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
equal(const T & lhs,const U & rhs)167 constexpr equal(const T & lhs, const U & rhs) {
168 return lhs == rhs;
169 }
170
171 template<class T, class U>
not_equal(const T & lhs,const U & rhs)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
181