safe_comparison.hpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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. #ifndef BOOST_HISTOGRAM_DETAIL_SAFE_COMPARISON_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_SAFE_COMPARISON_HPP
  8. #include <boost/mp11/utility.hpp>
  9. #include <boost/type.hpp>
  10. #include <type_traits>
  11. namespace boost {
  12. namespace histogram {
  13. namespace detail {
  14. template <class T>
  15. auto make_unsigned(const T& t) noexcept {
  16. static_assert(std::is_integral<T>::value, "");
  17. return static_cast<std::make_unsigned_t<T>>(t);
  18. }
  19. template <class T>
  20. using number_category =
  21. mp11::mp_if<std::is_integral<T>,
  22. mp11::mp_if<std::is_signed<T>, type<int>, type<unsigned>>, type<void>>;
  23. // version of std::equal_to<> which handles signed and unsigned integers correctly
  24. struct safe_equal {
  25. template <class T, class U>
  26. bool operator()(const T& t, const U& u) const noexcept {
  27. return impl(number_category<T>{}, number_category<U>{}, t, u);
  28. }
  29. template <class C1, class C2, class T, class U>
  30. bool impl(C1, C2, const T& t, const U& u) const noexcept {
  31. return t == u;
  32. }
  33. template <class T, class U>
  34. bool impl(type<int>, type<unsigned>, const T& t, const U& u) const noexcept {
  35. return t >= 0 && make_unsigned(t) == u;
  36. }
  37. template <class T, class U>
  38. bool impl(type<unsigned>, type<int>, const T& t, const U& u) const noexcept {
  39. return impl(type<int>{}, type<unsigned>{}, u, t);
  40. }
  41. };
  42. // version of std::less<> which handles signed and unsigned integers correctly
  43. struct safe_less {
  44. template <class T, class U>
  45. bool operator()(const T& t, const U& u) const noexcept {
  46. return impl(number_category<T>{}, number_category<U>{}, t, u);
  47. }
  48. template <class C1, class C2, class T, class U>
  49. bool impl(C1, C2, const T& t, const U& u) const noexcept {
  50. return t < u;
  51. }
  52. template <class T, class U>
  53. bool impl(type<int>, type<unsigned>, const T& t, const U& u) const noexcept {
  54. return t < 0 || make_unsigned(t) < u;
  55. }
  56. template <class T, class U>
  57. bool impl(type<unsigned>, type<int>, const T& t, const U& u) const noexcept {
  58. return 0 < u && t < make_unsigned(u);
  59. }
  60. };
  61. // version of std::greater<> which handles signed and unsigned integers correctly
  62. struct safe_greater {
  63. template <class T, class U>
  64. bool operator()(const T& t, const U& u) const noexcept {
  65. return safe_less()(u, t);
  66. }
  67. };
  68. } // namespace detail
  69. } // namespace histogram
  70. } // namespace boost
  71. #endif