Files
rippled/include/xrpl/tx/paths/detail/AmountSpec.h
2026-02-17 18:10:07 +00:00

199 lines
4.0 KiB
C++

#pragma once
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/XRPAmount.h>
#include <optional>
namespace xrpl {
struct AmountSpec
{
explicit AmountSpec() = default;
bool native;
union
{
XRPAmount xrp;
IOUAmount iou = {};
};
std::optional<AccountID> issuer;
std::optional<Currency> currency;
friend std::ostream&
operator<<(std::ostream& stream, AmountSpec const& amt)
{
if (amt.native)
stream << to_string(amt.xrp);
else
stream << to_string(amt.iou);
if (amt.currency)
stream << "/(" << *amt.currency << ")";
if (amt.issuer)
stream << "/" << *amt.issuer << "";
return stream;
}
};
struct EitherAmount
{
#ifndef NDEBUG
bool native = false;
#endif
union
{
IOUAmount iou = {};
XRPAmount xrp;
};
EitherAmount() = default;
explicit EitherAmount(IOUAmount const& a) : iou(a)
{
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
// ignore warning about half of iou amount being uninitialized
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
explicit EitherAmount(XRPAmount const& a) : xrp(a)
{
#ifndef NDEBUG
native = true;
#endif
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
explicit EitherAmount(AmountSpec const& a)
{
#ifndef NDEBUG
native = a.native;
#endif
if (a.native)
xrp = a.xrp;
else
iou = a.iou;
}
#ifndef NDEBUG
friend std::ostream&
operator<<(std::ostream& stream, EitherAmount const& amt)
{
if (amt.native)
stream << to_string(amt.xrp);
else
stream << to_string(amt.iou);
return stream;
}
#endif
};
template <class T>
T&
get(EitherAmount& amt)
{
static_assert(sizeof(T) == -1, "Must used specialized function");
return T(0);
}
template <>
inline IOUAmount&
get<IOUAmount>(EitherAmount& amt)
{
XRPL_ASSERT(!amt.native, "xrpl::get<IOUAmount>(EitherAmount&) : is not XRP");
return amt.iou;
}
template <>
inline XRPAmount&
get<XRPAmount>(EitherAmount& amt)
{
XRPL_ASSERT(amt.native, "xrpl::get<XRPAmount>(EitherAmount&) : is XRP");
return amt.xrp;
}
template <class T>
T const&
get(EitherAmount const& amt)
{
static_assert(sizeof(T) == -1, "Must used specialized function");
return T(0);
}
template <>
inline IOUAmount const&
get<IOUAmount>(EitherAmount const& amt)
{
XRPL_ASSERT(!amt.native, "xrpl::get<IOUAmount>(EitherAmount const&) : is not XRP");
return amt.iou;
}
template <>
inline XRPAmount const&
get<XRPAmount>(EitherAmount const& amt)
{
XRPL_ASSERT(amt.native, "xrpl::get<XRPAmount>(EitherAmount const&) : is XRP");
return amt.xrp;
}
inline AmountSpec
toAmountSpec(STAmount const& amt)
{
XRPL_ASSERT(
amt.mantissa() < std::numeric_limits<std::int64_t>::max(),
"xrpl::toAmountSpec(STAmount const&) : maximum mantissa");
bool const isNeg = amt.negative();
std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa();
AmountSpec result;
result.native = isXRP(amt);
if (result.native)
{
result.xrp = XRPAmount(sMant);
}
else
{
result.iou = IOUAmount(sMant, amt.exponent());
result.issuer = amt.issue().account;
result.currency = amt.issue().currency;
}
return result;
}
inline EitherAmount
toEitherAmount(STAmount const& amt)
{
if (isXRP(amt))
return EitherAmount{amt.xrp()};
return EitherAmount{amt.iou()};
}
inline AmountSpec
toAmountSpec(EitherAmount const& ea, std::optional<Currency> const& c)
{
AmountSpec r;
r.native = (!c || isXRP(*c));
r.currency = c;
XRPL_ASSERT(
ea.native == r.native,
"xrpl::toAmountSpec(EitherAmount const&&, std::optional<Currency>) : "
"matching native");
if (r.native)
{
r.xrp = ea.xrp;
}
else
{
r.iou = ea.iou;
}
return r;
}
} // namespace xrpl