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