#ifndef XRPL_PROTOCOL_BOOK_H_INCLUDED #define XRPL_PROTOCOL_BOOK_H_INCLUDED #include #include #include #include namespace ripple { /** Specifies an order book. The order book is a pair of Issues called in and out. @see Issue. */ class Book final : public CountedObject { public: Issue in; Issue out; std::optional domain; Book() { } Book( Issue const& in_, Issue const& out_, std::optional const& domain_) : in(in_), out(out_), domain(domain_) { } }; bool isConsistent(Book const& book); std::string to_string(Book const& book); std::ostream& operator<<(std::ostream& os, Book const& x); template void hash_append(Hasher& h, Book const& b) { using beast::hash_append; hash_append(h, b.in, b.out); if (b.domain) hash_append(h, *(b.domain)); } Book reversed(Book const& book); /** Equality comparison. */ /** @{ */ [[nodiscard]] inline constexpr bool operator==(Book const& lhs, Book const& rhs) { return (lhs.in == rhs.in) && (lhs.out == rhs.out) && (lhs.domain == rhs.domain); } /** @} */ /** Strict weak ordering. */ /** @{ */ [[nodiscard]] inline constexpr std::weak_ordering operator<=>(Book const& lhs, Book const& rhs) { if (auto const c{lhs.in <=> rhs.in}; c != 0) return c; if (auto const c{lhs.out <=> rhs.out}; c != 0) return c; // Manually compare optionals if (lhs.domain && rhs.domain) return *lhs.domain <=> *rhs.domain; // Compare values if both exist if (!lhs.domain && rhs.domain) return std::weak_ordering::less; // Empty is considered less if (lhs.domain && !rhs.domain) return std::weak_ordering::greater; // Non-empty is greater return std::weak_ordering::equivalent; // Both are empty } /** @} */ } // namespace ripple //------------------------------------------------------------------------------ namespace std { template <> struct hash : private boost::base_from_member, 0>, private boost::base_from_member, 1> { private: using currency_hash_type = boost::base_from_member, 0>; using issuer_hash_type = boost::base_from_member, 1>; public: hash() = default; using value_type = std::size_t; using argument_type = ripple::Issue; value_type operator()(argument_type const& value) const { value_type result(currency_hash_type::member(value.currency)); if (!isXRP(value.currency)) boost::hash_combine( result, issuer_hash_type::member(value.account)); return result; } }; //------------------------------------------------------------------------------ template <> struct hash { private: using issue_hasher = std::hash; using uint256_hasher = ripple::uint256::hasher; issue_hasher m_issue_hasher; uint256_hasher m_uint256_hasher; public: hash() = default; using value_type = std::size_t; using argument_type = ripple::Book; value_type operator()(argument_type const& value) const { value_type result(m_issue_hasher(value.in)); boost::hash_combine(result, m_issue_hasher(value.out)); if (value.domain) boost::hash_combine(result, m_uint256_hasher(*value.domain)); return result; } }; } // namespace std //------------------------------------------------------------------------------ namespace boost { template <> struct hash : std::hash { hash() = default; using Base = std::hash; // VFALCO NOTE broken in vs2012 // using Base::Base; // inherit ctors }; template <> struct hash : std::hash { hash() = default; using Base = std::hash; // VFALCO NOTE broken in vs2012 // using Base::Base; // inherit ctors }; } // namespace boost #endif