operators.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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_OPERATORS_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP
  8. #include <boost/histogram/detail/detect.hpp>
  9. #include <boost/mp11/algorithm.hpp>
  10. #include <boost/mp11/list.hpp>
  11. #include <boost/mp11/utility.hpp>
  12. #include <type_traits>
  13. namespace boost {
  14. namespace histogram {
  15. namespace detail {
  16. template <class T, class U>
  17. using if_not_same = std::enable_if_t<(!std::is_same<T, U>::value), bool>;
  18. // template <class T, class U>
  19. // using if_not_same_and_has_eq =
  20. // std::enable_if_t<(!std::is_same<T, U>::value && !has_method_eq<T, U>::value),
  21. // bool>;
  22. // totally_ordered is for types with a <= b == !(a > b) [floats with NaN violate this]
  23. // Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
  24. // partially_ordered is for types with a <= b == a < b || a == b [for floats with NaN]
  25. // Derived must implement <,== for symmetric form and <,>,== for non-symmetric.
  26. template <class T, class U>
  27. struct mirrored {
  28. friend bool operator<(const U& a, const T& b) noexcept { return b > a; }
  29. friend bool operator>(const U& a, const T& b) noexcept { return b < a; }
  30. friend bool operator==(const U& a, const T& b) noexcept { return b == a; }
  31. friend bool operator<=(const U& a, const T& b) noexcept { return b >= a; }
  32. friend bool operator>=(const U& a, const T& b) noexcept { return b <= a; }
  33. friend bool operator!=(const U& a, const T& b) noexcept { return b != a; }
  34. }; // namespace histogram
  35. template <class T>
  36. struct mirrored<T, void> {
  37. template <class U>
  38. friend if_not_same<T, U> operator<(const U& a, const T& b) noexcept {
  39. return b > a;
  40. }
  41. template <class U>
  42. friend if_not_same<T, U> operator>(const U& a, const T& b) noexcept {
  43. return b < a;
  44. }
  45. template <class U>
  46. friend std::enable_if_t<(!has_method_eq<U, T>::value), bool> operator==(
  47. const U& a, const T& b) noexcept {
  48. return b.operator==(a);
  49. }
  50. template <class U>
  51. friend if_not_same<T, U> operator<=(const U& a, const T& b) noexcept {
  52. return b >= a;
  53. }
  54. template <class U>
  55. friend if_not_same<T, U> operator>=(const U& a, const T& b) noexcept {
  56. return b <= a;
  57. }
  58. template <class U>
  59. friend if_not_same<T, U> operator!=(const U& a, const T& b) noexcept {
  60. return b != a;
  61. }
  62. };
  63. template <class T>
  64. struct mirrored<T, T> {
  65. friend bool operator>(const T& a, const T& b) noexcept { return b.operator<(a); }
  66. };
  67. template <class T, class U>
  68. struct equality {
  69. friend bool operator!=(const T& a, const U& b) noexcept { return !a.operator==(b); }
  70. };
  71. template <class T>
  72. struct equality<T, void> {
  73. template <class U>
  74. friend if_not_same<T, U> operator!=(const T& a, const U& b) noexcept {
  75. return !(a == b);
  76. }
  77. };
  78. template <class T, class U>
  79. struct totally_ordered_impl : equality<T, U>, mirrored<T, U> {
  80. friend bool operator<=(const T& a, const U& b) noexcept { return !(a > b); }
  81. friend bool operator>=(const T& a, const U& b) noexcept { return !(a < b); }
  82. };
  83. template <class T>
  84. struct totally_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
  85. template <class U>
  86. friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
  87. return !(a > b);
  88. }
  89. template <class U>
  90. friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
  91. return !(a < b);
  92. }
  93. };
  94. template <class T, class... Ts>
  95. using totally_ordered = mp11::mp_rename<
  96. mp11::mp_product<totally_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >,
  97. mp11::mp_inherit>;
  98. template <class T, class U>
  99. struct partially_ordered_impl : equality<T, U>, mirrored<T, U> {
  100. friend bool operator<=(const T& a, const U& b) noexcept { return a < b || a == b; }
  101. friend bool operator>=(const T& a, const U& b) noexcept { return a > b || a == b; }
  102. };
  103. template <class T>
  104. struct partially_ordered_impl<T, void> : equality<T, void>, mirrored<T, void> {
  105. template <class U>
  106. friend if_not_same<T, U> operator<=(const T& a, const U& b) noexcept {
  107. return a < b || a == b;
  108. }
  109. template <class U>
  110. friend if_not_same<T, U> operator>=(const T& a, const U& b) noexcept {
  111. return a > b || a == b;
  112. }
  113. };
  114. template <class T, class... Ts>
  115. using partially_ordered = mp11::mp_rename<
  116. mp11::mp_product<partially_ordered_impl, mp11::mp_list<T>, mp11::mp_list<Ts...> >,
  117. mp11::mp_inherit>;
  118. } // namespace detail
  119. } // namespace histogram
  120. } // namespace boost
  121. #endif // BOOST_HISTOGRAM_DETAIL_OPERATORS_HPP