Support STAmount conversions to XRPAmount and IOUAmount

This commit is contained in:
Nik Bougalis
2015-08-21 10:05:18 -07:00
parent 1e9624270d
commit 94af42da44
4 changed files with 164 additions and 16 deletions

View File

@@ -24,6 +24,8 @@
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/STBase.h>
#include <ripple/protocol/Issue.h>
#include <ripple/protocol/IOUAmount.h>
#include <ripple/protocol/XRPAmount.h>
#include <beast/cxx14/memory.h> // <memory>
namespace ripple {
@@ -114,6 +116,10 @@ public:
STAmount (Issue const& issue, int mantissa, int exponent = 0);
// Legacy support for new-style amounts
STAmount (IOUAmount const& amount, Issue const& issue);
STAmount (XRPAmount const& amount);
STBase*
copy (std::size_t n, void* buf) const override
{
@@ -271,6 +277,9 @@ public:
{
return (mValue == 0) && mIsNative;
}
XRPAmount xrp () const;
IOUAmount iou () const;
};
//------------------------------------------------------------------------------

View File

@@ -25,6 +25,7 @@
#include <beast/utility/Zero.h>
#include <boost/operators.hpp>
#include <cstdint>
#include <beast/cxx14/type_traits.h>
using beast::zero;
@@ -35,82 +36,94 @@ class XRPAmount
, private boost::additive <XRPAmount>
{
private:
std::int64_t value_;
std::int64_t drops_;
public:
/** @{ */
XRPAmount () = default;
XRPAmount (XRPAmount const& other) = default;
XRPAmount& operator= (XRPAmount const& other) = default;
XRPAmount (beast::Zero)
: value_ (0)
: drops_ (0)
{
}
XRPAmount&
operator= (beast::Zero)
{
value_ = 0;
drops_ = 0;
return *this;
}
XRPAmount (std::int64_t value)
: value_ (value)
template <class Integer,
class = typename std::enable_if_t <
std::is_integral<Integer>::value>>
XRPAmount (Integer drops)
: drops_ (static_cast<std::int64_t> (drops))
{
}
template <class Integer,
class = typename std::enable_if_t <
std::is_integral<Integer>::value>>
XRPAmount&
operator= (std::int64_t v)
operator= (Integer drops)
{
value_ = v;
drops_ = static_cast<std::int64_t> (drops);
return *this;
}
XRPAmount&
operator+= (XRPAmount const& other)
{
value_ += other.value_;
drops_ += other.drops_;
return *this;
}
XRPAmount&
operator-= (XRPAmount const& other)
{
value_ -= other.value_;
drops_ -= other.drops_;
return *this;
}
XRPAmount
operator- () const
{
return { -value_ };
return { -drops_ };
}
bool
operator==(XRPAmount const& other) const
{
return value_ == other.value_;
return drops_ == other.drops_;
}
bool
operator<(XRPAmount const& other) const
{
return value_ < other.value_;
return drops_ < other.drops_;
}
/** Returns true if the amount is not zero */
explicit
operator bool() const noexcept
{
return value_ != 0;
return drops_ != 0;
}
/** Return the sign of the amount */
int
signum() const noexcept
{
return (value_ < 0) ? -1 : (value_ ? 1 : 0);
return (drops_ < 0) ? -1 : (drops_ ? 1 : 0);
}
/** Returns the number of drops */
std::int64_t
drops () const
{
return drops_;
}
};
@@ -118,7 +131,7 @@ public:
inline
bool isLegalAmount (XRPAmount const& amount)
{
return amount <= SYSTEM_CURRENCY_START;
return amount.drops () <= SYSTEM_CURRENCY_START;
}
}

View File

@@ -248,12 +248,72 @@ STAmount::STAmount (Issue const& issue,
{
}
// Legacy support for new-style amounts
STAmount::STAmount (IOUAmount const& amount, Issue const& issue)
: mIssue (issue)
, mOffset (amount.exponent ())
, mIsNative (false)
, mIsNegative (amount < zero)
{
if (mIsNegative)
mValue = static_cast<std::uint64_t> (-amount.mantissa ());
else
mValue = static_cast<std::uint64_t> (amount.mantissa ());
canonicalize ();
}
STAmount::STAmount (XRPAmount const& amount)
: mOffset (0)
, mIsNative (true)
, mIsNegative (amount < zero)
{
if (mIsNegative)
mValue = static_cast<std::uint64_t> (-amount.drops ());
else
mValue = static_cast<std::uint64_t> (amount.drops ());
canonicalize ();
}
std::unique_ptr<STAmount>
STAmount::construct (SerialIter& sit, SField const& name)
{
return std::make_unique<STAmount>(sit, name);
}
//------------------------------------------------------------------------------
//
// Conversion
//
//------------------------------------------------------------------------------
XRPAmount STAmount::xrp () const
{
if (!mIsNative)
throw std::logic_error ("Cannot return non-native STAmount as XRPAmount");
auto drops = static_cast<std::int64_t> (mValue);
if (mIsNegative)
drops = -drops;
return { drops };
}
IOUAmount STAmount::iou () const
{
if (mIsNative)
throw std::logic_error ("Cannot return native STAmount as IOUAmount");
auto mantissa = static_cast<std::int64_t> (mValue);
auto exponent = mOffset;
if (mIsNegative)
mantissa = -mantissa;
return { mantissa, exponent };
}
//------------------------------------------------------------------------------
//
// Operators

View File

@@ -567,6 +567,70 @@ public:
#endif
}
void
testConvertXRP ()
{
testcase ("STAmount to XRPAmount conversions");
Issue const usd { Currency (0x5553440000000000), AccountID (0x4985601) };
Issue const xrp { xrpIssue () };
for (std::uint64_t drops = 100000000000000000; drops != 1; drops = drops / 10)
{
auto const t = amountFromString (xrp, std::to_string (drops));
auto const s = t.xrp ();
expect (s.drops() == drops);
expect (t == STAmount (XRPAmount (drops)));
expect (s == XRPAmount (drops));
}
try
{
auto const t = amountFromString (usd, "136500");
fail (to_string (t.xrp ()));
}
catch (std::logic_error const&)
{
pass ();
}
catch (...)
{
fail ("wrong exception");
}
}
void
testConvertIOU ()
{
testcase ("STAmount to IOUAmount conversions");
Issue const usd { Currency (0x5553440000000000), AccountID (0x4985601) };
Issue const xrp { xrpIssue () };
for (std::uint64_t dollars = 10000000000; dollars != 1; dollars = dollars / 10)
{
auto const t = amountFromString (usd, std::to_string (dollars));
auto const s = t.iou ();
expect (t == STAmount (s, usd));
expect (s.mantissa () == t.mantissa ());
expect (s.exponent () == t.exponent ());
}
try
{
auto const t = amountFromString (xrp, "136500");
fail (to_string (t.iou ()));
}
catch (std::logic_error const&)
{
pass ();
}
catch (...)
{
fail ("wrong exception");
}
}
//--------------------------------------------------------------------------
void run ()
@@ -577,6 +641,8 @@ public:
testArithmetic ();
testUnderflow ();
testRounding ();
testConvertXRP ();
testConvertIOU ();
}
};