operators.hpp 4.4 KB

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