Use <=> operator for base_uint, Issue, and Book: (#4411)

- Implement the `operator==` and the `operator<=>` (aka the spaceship
  operator) in `base_uint`, `Issue`, and `Book`. 
- C++20-compliant compilers automatically provide the remaining
  comparison operators (e.g. `operator<`, `operator<=`, ...).
- Remove the function compare() because it is no longer needed.
- Maintain the same semantics as the existing code.
- Add some unit tests to gain further confidence.
- Fix #2525.
This commit is contained in:
drlongle
2023-03-15 04:54:54 +01:00
committed by GitHub
parent f7b3ddd87b
commit 84cde3ce0b
7 changed files with 138 additions and 216 deletions

View File

@@ -33,6 +33,7 @@
#include <ripple/beast/utility/Zero.h>
#include <boost/endian/conversion.hpp>
#include <boost/functional/hash.hpp>
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
@@ -549,103 +550,66 @@ using uint160 = base_uint<160>;
using uint256 = base_uint<256>;
template <std::size_t Bits, class Tag>
inline int
compare(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
[[nodiscard]] inline constexpr std::strong_ordering
operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
{
auto ret = std::mismatch(a.cbegin(), a.cend(), b.cbegin());
// This comparison might seem wrong on a casual inspection because it
// compares data internally stored as std::uint32_t byte-by-byte. But
// note that the underlying data is stored in big endian, even if the
// plaform is little endian. This makes the comparison correct.
//
// FIXME: use std::lexicographical_compare_three_way once support is
// added to MacOS.
if (ret.first == a.cend())
return 0;
auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
// a > b
if (*ret.first > *ret.second)
return 1;
// a == b
if (ret.first == lhs.cend())
return std::strong_ordering::equivalent;
// a < b
return -1;
return (*ret.first > *ret.second) ? std::strong_ordering::greater
: std::strong_ordering::less;
}
template <std::size_t Bits, class Tag>
inline bool
operator<(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
template <std::size_t Bits, typename Tag>
[[nodiscard]] inline constexpr bool
operator==(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
{
return compare(a, b) < 0;
}
template <std::size_t Bits, class Tag>
inline bool
operator<=(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return compare(a, b) <= 0;
}
template <std::size_t Bits, class Tag>
inline bool
operator>(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return compare(a, b) > 0;
}
template <std::size_t Bits, class Tag>
inline bool
operator>=(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return compare(a, b) >= 0;
}
template <std::size_t Bits, class Tag>
inline bool
operator==(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return compare(a, b) == 0;
}
template <std::size_t Bits, class Tag>
inline bool
operator!=(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return compare(a, b) != 0;
return (lhs <=> rhs) == 0;
}
//------------------------------------------------------------------------------
template <std::size_t Bits, class Tag>
inline bool
inline constexpr bool
operator==(base_uint<Bits, Tag> const& a, std::uint64_t b)
{
return a == base_uint<Bits, Tag>(b);
}
template <std::size_t Bits, class Tag>
inline bool
operator!=(base_uint<Bits, Tag> const& a, std::uint64_t b)
{
return !(a == b);
}
//------------------------------------------------------------------------------
template <std::size_t Bits, class Tag>
inline const base_uint<Bits, Tag>
inline constexpr base_uint<Bits, Tag>
operator^(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return base_uint<Bits, Tag>(a) ^= b;
}
template <std::size_t Bits, class Tag>
inline const base_uint<Bits, Tag>
inline constexpr base_uint<Bits, Tag>
operator&(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return base_uint<Bits, Tag>(a) &= b;
}
template <std::size_t Bits, class Tag>
inline const base_uint<Bits, Tag>
inline constexpr base_uint<Bits, Tag>
operator|(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return base_uint<Bits, Tag>(a) |= b;
}
template <std::size_t Bits, class Tag>
inline const base_uint<Bits, Tag>
inline constexpr base_uint<Bits, Tag>
operator+(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
{
return base_uint<Bits, Tag>(a) += b;