safe_compare.hpp 4.7 KB

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