comparisons simplified

This commit is contained in:
Hans Dembinski 2019-06-11 22:33:53 +02:00
parent 5fb5758e14
commit b99184792d

View File

@ -32,8 +32,16 @@ namespace boost {
namespace histogram { namespace histogram {
namespace detail { namespace detail {
template <class T, class = std::enable_if_t<std::is_arithmetic<T>::value>> template <class T>
struct requires_arithmetic {}; struct is_large_int : std::false_type {};
template <class A>
struct is_large_int<large_int<A>> : std::true_type {};
template <class T, class ReturnType>
using if_arithmetic_or_large_int =
std::enable_if_t<(std::is_arithmetic<T>::value || is_large_int<T>::value),
ReturnType>;
template <class L, class T> template <class L, class T>
using next_type = mp11::mp_at_c<L, (mp11::mp_find<L, T>::value + 1)>; using next_type = mp11::mp_at_c<L, (mp11::mp_find<L, T>::value + 1)>;
@ -250,7 +258,7 @@ public:
/// implementation detail /// implementation detail
class const_reference class const_reference
: detail::partially_ordered<const_reference, const_reference, large_int, void> { : detail::partially_ordered<const_reference, const_reference, void> {
public: public:
const_reference(buffer_type& b, std::size_t i) noexcept : bref_(b), idx_(i) { const_reference(buffer_type& b, std::size_t i) noexcept : bref_(b), idx_(i) {
BOOST_ASSERT(idx_ < bref_.size); BOOST_ASSERT(idx_ < bref_.size);
@ -271,38 +279,22 @@ public:
return apply_binary<detail::safe_less>(o); return apply_binary<detail::safe_less>(o);
} }
bool operator<(const large_int& o) const noexcept {
return apply_binary<detail::safe_less>(o);
}
template <class U>
bool operator<(const U& o) const noexcept {
return apply_binary<detail::safe_less>(o);
}
bool operator>(const const_reference& rhs) const noexcept {
return apply_binary<detail::safe_greater>(rhs);
}
bool operator>(const large_int& rhs) const noexcept {
return apply_binary<detail::safe_greater>(rhs);
}
template <class U>
bool operator>(const U& o) const noexcept {
return apply_binary<detail::safe_greater>(o);
}
bool operator==(const const_reference& o) const noexcept { bool operator==(const const_reference& o) const noexcept {
return apply_binary<detail::safe_equal>(o); return apply_binary<detail::safe_equal>(o);
} }
bool operator==(const large_int& rhs) const noexcept { template <class U>
return apply_binary<detail::safe_equal>(rhs); detail::if_arithmetic_or_large_int<U, bool> operator<(const U& o) const noexcept {
return apply_binary<detail::safe_less>(o);
} }
template <class U> template <class U>
bool operator==(const U& o) const noexcept { detail::if_arithmetic_or_large_int<U, bool> operator>(const U& o) const noexcept {
return apply_binary<detail::safe_greater>(o);
}
template <class U>
detail::if_arithmetic_or_large_int<U, bool> operator==(const U& o) const noexcept {
return apply_binary<detail::safe_equal>(o); return apply_binary<detail::safe_equal>(o);
} }
@ -327,8 +319,7 @@ public:
/// implementation detail /// implementation detail
class reference : public const_reference, class reference : public const_reference,
public detail::partially_ordered<reference, reference, public detail::partially_ordered<reference, reference, void> {
const_reference, large_int, void> {
public: public:
reference(buffer_type& b, std::size_t i) noexcept : const_reference(b, i) {} reference(buffer_type& b, std::size_t i) noexcept : const_reference(b, i) {}
@ -340,74 +331,44 @@ public:
return operator=(static_cast<const_reference>(x)); return operator=(static_cast<const_reference>(x));
} }
// references do not rebind, assign through
reference& operator=(const const_reference& x) { reference& operator=(const const_reference& x) {
// safe for self-assignment, assigning matching type doesn't invalide buffer // safe for self-assignment, assigning matching type doesn't invalide buffer
x.bref_.visit([this, ix = x.idx_](const auto* xp) { this->operator=(xp[ix]); }); x.bref_.visit([this, ix = x.idx_](const auto* xp) { this->operator=(xp[ix]); });
return *this; return *this;
} }
template <class U, class = detail::requires_arithmetic<U>> template <class U>
reference& operator=(const U& x) { detail::if_arithmetic_or_large_int<U, reference&> operator=(const U& x) {
this->bref_.visit([this, &x](auto* p) { this->bref_.visit([this, &x](auto* p) {
p[this->idx_] = 0; // LCOV_EXCL_LINE gcc-8 optimizes this away even at -O0 // gcc-8 optimizes the expression `p[this->idx_] = 0` away even at -O0,
adder()(p, this->bref_, this->idx_, x); // so we merge it into the next line which is properly counted
adder()((p[this->idx_] = 0, p), this->bref_, this->idx_, x);
}); });
return *this; return *this;
} }
reference& operator=(const large_int& x) {
this->bref_.visit([this, &x](auto* p) {
p[this->idx_] = 0; // LCOV_EXCL_LINE gcc-8 optimizes this away even at -O0
adder()(p, this->bref_, this->idx_, x);
});
return *this;
}
bool operator<(const const_reference& o) const noexcept {
return const_reference::operator<(o);
}
bool operator>(const const_reference& o) const noexcept {
return const_reference::operator>(o);
}
bool operator==(const const_reference& o) const noexcept {
return const_reference::operator==(o);
}
bool operator<(const reference& o) const noexcept { bool operator<(const reference& o) const noexcept {
return const_reference::operator<(static_cast<const const_reference&>(o));
}
bool operator==(const reference& o) const noexcept {
return const_reference::operator==(static_cast<const const_reference&>(o));
}
bool operator<(const large_int& o) const noexcept {
return const_reference::operator<(o); return const_reference::operator<(o);
} }
bool operator>(const large_int& o) const noexcept { bool operator==(const reference& o) const noexcept {
return const_reference::operator>(o);
}
bool operator==(const large_int& o) const noexcept {
return const_reference::operator==(o); return const_reference::operator==(o);
} }
template <class U, class = detail::requires_arithmetic<U>> template <class U>
bool operator<(const U& o) const noexcept { detail::if_arithmetic_or_large_int<U, bool> operator<(const U& o) const noexcept {
return static_cast<const const_reference&>(*this) < o; return const_reference::operator<(o);
} }
template <class U, class = detail::requires_arithmetic<U>> template <class U>
bool operator>(const U& o) const noexcept { detail::if_arithmetic_or_large_int<U, bool> operator>(const U& o) const noexcept {
return static_cast<const const_reference&>(*this) > o; return const_reference::operator>(o);
} }
template <class U, class = detail::requires_arithmetic<U>> template <class U>
bool operator==(const U& o) const noexcept { detail::if_arithmetic_or_large_int<U, bool> operator==(const U& o) const noexcept {
return static_cast<const const_reference&>(*this) == o; return const_reference::operator==(o);
} }
reference& operator+=(const const_reference& x) { reference& operator+=(const const_reference& x) {
@ -415,13 +376,8 @@ public:
return *this; return *this;
} }
template <class U, class = detail::requires_arithmetic<U>> template <class U>
reference& operator+=(const U& x) { detail::if_arithmetic_or_large_int<U, reference&> operator+=(const U& x) {
this->bref_.visit(adder(), this->bref_, this->idx_, x);
return *this;
}
reference& operator+=(const large_int& x) {
this->bref_.visit(adder(), this->bref_, this->idx_, x); this->bref_.visit(adder(), this->bref_, this->idx_, x);
return *this; return *this;
} }