New Zero struct implements "compare with zero."

* Zero lets classes efficiently compare with 0, so
  you can use constructors like x < zero or y != zero.
* New BEAST_CONSTEXPR to handle Windows/C++11 differences
  regarding the constexpr specifier.
This commit is contained in:
Tom Swirly
2014-04-10 19:14:52 -04:00
committed by Vinnie Falco
parent 524f41177c
commit 64ee0d07d0
26 changed files with 591 additions and 425 deletions

View File

@@ -24,13 +24,8 @@
#ifndef BEAST_CONFIG_COMPILERCONFIG_H_INCLUDED
#define BEAST_CONFIG_COMPILERCONFIG_H_INCLUDED
// This file has to work when included in a C source file.
#ifndef BEAST_CONFIG_PLATFORMCONFIG_H_INCLUDED
#error "PlatformConfig.h must come first!"
#endif
#include <assert.h>
#include "PlatformConfig.h"
// This file defines miscellaneous macros for debugging, assertions, etc.
@@ -47,6 +42,15 @@
# define BEAST_CDECL
#endif
/** This macro fixes C++'s constexpr for VS2012, which doesn't understand it.
*/
#if BEAST_MSVC
# define BEAST_CONSTEXPR const
#else
# define BEAST_CONSTEXPR constexpr
#endif
// Debugging and assertion macros
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
// MODULES: ../../crypto/impl/Sha256.cpp
// MODULES: ../../crypto/impl/Sha256.cpp ../../container/impl/spookyv2.cpp
#if BEAST_INCLUDE_BEASTCONFIG
#include "../../../BeastConfig.h"

View File

@@ -31,3 +31,4 @@
#include "tests/bassert.test.cpp"
#include "tests/empty_base_optimization.test.cpp"
#include "tests/Zero.test.cpp"

View File

@@ -0,0 +1,140 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2014, Tom Ritchford <tom@swirly.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UTILITY_ZERO_H_INCLUDED
#define BEAST_UTILITY_ZERO_H_INCLUDED
#include "../config/CompilerConfig.h"
namespace beast {
/** Zero allows classes to offer efficient comparisons to zero.
Zero is a struct to allow classes to efficiently compare with zero without
requiring an rvalue construction.
It's often the case that we have classes which combine a number and a unit.
In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons
like t > 1 or t != 1 do not.
The class Zero allows such comparisons to be easily made.
The comparing class T either needs to have a method called signum() which
returns a positive number, 0, or a negative; or there needs to be a signum
function which resolves in the namespace which takes an instance of T and
returns a positive, zero or negative number.
*/
struct Zero {};
namespace {
static BEAST_CONSTEXPR Zero zero{};
} // namespace
/** The default implementation of signum calls the method on the class.
Calls to signum must be made from a namespace that does not include
overloads of the function.
*/
template <typename T>
auto signum(T const& t) -> decltype(t.signum()) {
return t.signum();
}
namespace detail {
namespace zero_helper {
template <class T>
auto call_signum (T const& t) -> decltype(signum(t)) {
return signum(t);
}
} // zero_helper
} // detail
/** Handle operators where T is on the left side using signum. */
template <typename T>
bool operator==(T const& t, Zero) {
return detail::zero_helper::call_signum(t) == 0;
}
template <typename T>
bool operator!=(T const& t, Zero) {
return detail::zero_helper::call_signum(t) != 0;
}
template <typename T>
bool operator>(T const& t, Zero) {
return detail::zero_helper::call_signum(t) > 0;
}
template <typename T>
bool operator>=(T const& t, Zero) {
return detail::zero_helper::call_signum(t) >= 0;
}
template <typename T>
bool operator<(T const& t, Zero) {
return detail::zero_helper::call_signum(t) < 0;
}
template <typename T>
bool operator<=(T const& t, Zero) {
return detail::zero_helper::call_signum(t) <= 0;
}
/** Handle operators where T is on the right side by reversing the operation,
so that T is on the left side.
*/
template <typename T>
bool operator==(Zero, T const& t) {
return t == zero;
}
template <typename T>
bool operator!=(Zero, T const& t) {
return t != zero;
}
template <typename T>
bool operator>(Zero, T const& t) {
return t < zero;
}
template <typename T>
bool operator>=(Zero, T const& t) {
return t <= zero;
}
template <typename T>
bool operator<(Zero, T const& t) {
return t > zero;
}
template <typename T>
bool operator<=(Zero, T const& t) {
return t >= zero;
}
} // beast
#endif

View File

@@ -0,0 +1,136 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2014, Nikolaos D. Bougalis <nikb@bougalis.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "../Zero.h"
#include "../../unit_test/suite.h"
namespace beast {
struct adl_tester {};
int signum (adl_tester) { return 0; }
namespace detail {
struct adl_tester2 {};
int signum (adl_tester2) { return 0; }
} // detail
class Zero_test : public beast::unit_test::suite
{
private:
struct IntegerWrapper
{
int value;
IntegerWrapper (int v)
: value (v)
{
}
int signum() const
{
return value;
}
};
public:
void expect_same(bool result, bool correct, char const* message)
{
expect(result == correct, message);
}
void
test_lhs_zero (IntegerWrapper x)
{
expect_same (x >= zero, x.signum () >= 0,
"lhs greater-than-or-equal-to");
expect_same (x > zero, x.signum () > 0,
"lhs greater than");
expect_same (x == zero, x.signum () == 0,
"lhs equal to");
expect_same (x != zero, x.signum () != 0,
"lhs not equal to");
expect_same (x < zero, x.signum () < 0,
"lhs less than");
expect_same (x <= zero, x.signum () <= 0,
"lhs less-than-or-equal-to");
}
void
test_lhs_zero ()
{
testcase ("lhs zero");
test_lhs_zero(-7);
test_lhs_zero(0);
test_lhs_zero(32);
}
void
test_rhs_zero (IntegerWrapper x)
{
expect_same (zero >= x, 0 >= x.signum (),
"rhs greater-than-or-equal-to");
expect_same (zero > x, 0 > x.signum (),
"rhs greater than");
expect_same (zero == x, 0 == x.signum (),
"rhs equal to");
expect_same (zero != x, 0 != x.signum (),
"rhs not equal to");
expect_same (zero < x, 0 < x.signum (),
"rhs less than");
expect_same (zero <= x, 0 <= x.signum (),
"rhs less-than-or-equal-to");
}
void
test_rhs_zero ()
{
testcase ("rhs zero");
test_rhs_zero(-4);
test_rhs_zero(0);
test_rhs_zero(64);
}
void
test_adl ()
{
expect (adl_tester{} == zero, "ADL failure!");
expect (detail::adl_tester2{} == zero, "ADL failure!");
}
void
run()
{
test_lhs_zero ();
test_rhs_zero ();
test_adl ();
}
};
BEAST_DEFINE_TESTSUITE(Zero, types, beast);
}

0
src/beast/tests.sh Normal file → Executable file
View File

View File

@@ -25,119 +25,6 @@
#include "../../beast/beast/utility/noexcept.h"
#include "../../beast/beast/cxx14/type_traits.h" // <type_traits>
//------------------------------------------------------------------------------
struct Zero
{
Zero()
{
}
};
namespace {
static Zero const zero;
}
namespace detail {
namespace Zero_helpers {
template <class T>
int
get_signum (T const& t) noexcept
{
return signum(t);
}
}
}
/** Handle operators where T is on the left side using signum. */
template <class T>
bool operator==(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) == 0;
}
template <class T>
bool operator!=(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) != 0;
}
template <class T>
bool operator>(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) > 0;
}
template <class T>
bool operator>=(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) >= 0;
}
template <class T>
bool operator<(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) < 0;
}
template <class T>
bool operator<=(T const& t, Zero)
{
return detail::Zero_helpers::get_signum(t) <= 0;
}
/** Handle operators where T is on the right side by reversing the operation,
so that T is on the left side.
*/
template <class T>
bool operator==(Zero, T const& t)
{
return t == zero;
}
template <class T>
bool operator!=(Zero, T const& t)
{
return t != zero;
}
template <class T>
bool operator>(Zero, T const& t)
{
return t < zero;
}
template <class T>
bool operator>=(Zero, T const& t)
{
return t <= zero;
}
template <class T>
bool operator<(Zero, T const& t)
{
return t > zero;
}
template <class T>
bool operator<=(Zero, T const& t)
{
return t >= zero;
}
/** Default implementation calls the method on the class.
Alternatively, signum may be overloaded in the same namespace and found
via argument dependent lookup.
*/
template <class T>
auto signum(T const& t) -> decltype(t.signum()) {
return t.signum();
}
//------------------------------------------------------------------------------
namespace ripple {
namespace core {

View File

@@ -39,7 +39,7 @@ struct Amounts
bool
empty() const noexcept
{
return ! in.isPositive() || ! out.isPositive();
return in <= zero || out <= zero;
}
Amount in;

View File

@@ -212,7 +212,7 @@ dir() const noexcept
m_offer.account(), m_offer.amount().out));
// Check for unfunded offer
if (! owner_funds.isPositive())
if (owner_funds <= zero)
{
// If the owner's balance in the pristine view is the same,
// we haven't modified the balance and therefore the

View File

@@ -230,7 +230,7 @@ public:
Amount const limit (
raw (4131113916555555, -16)); // .4131113916555555
Amounts const result (q.ceil_out (value, limit));
expect (! result.in.isZero());
expect (result.in != zero);
}
}

View File

@@ -1116,7 +1116,7 @@ STAmount LedgerEntrySet::rippleOwed (const uint160& uToAccountID, const uint160&
}
else
{
saBalance.zero (uCurrencyID, uToAccountID);
saBalance.clear (uCurrencyID, uToAccountID);
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleOwed: No credit line between "
<< RippleAddress::createHumanAccountID (uFromAccountID)
@@ -1149,7 +1149,7 @@ STAmount LedgerEntrySet::rippleLimit (const uint160& uToAccountID, const uint160
}
else
{
saLimit.zero (uCurrencyID, uToAccountID);
saLimit.clear (uCurrencyID, uToAccountID);
#if 0
// We could cut off coming here if we test for no line sooner.
assert (false);
@@ -1244,7 +1244,7 @@ STAmount LedgerEntrySet::rippleHolds (const uint160& uAccountID, const uint160&
if (!sleRippleState)
{
saBalance.zero (uCurrencyID, uIssuerID);
saBalance.clear (uCurrencyID, uIssuerID);
}
else if (uAccountID > uIssuerID)
{
@@ -1279,7 +1279,7 @@ STAmount LedgerEntrySet::accountHolds (const uint160& uAccountID, const uint160&
if (saBalance < uReserve)
{
saAmount.zero ();
saAmount.clear ();
}
else
{
@@ -1525,8 +1525,8 @@ TER LedgerEntrySet::rippleCredit (const uint160& uSenderID, const uint160& uRece
std::uint32_t uFlags;
// YYY Could skip this if rippling in reverse.
if (saBefore.isPositive () // Sender balance was positive.
&& !saBalance.isPositive () // Sender is zero or negative.
if (saBefore > zero // Sender balance was positive.
&& saBalance <= zero // Sender is zero or negative.
&& isSetBit ((uFlags = sleRippleState->getFieldU32 (sfFlags)), !bSenderHigh ? lsfLowReserve : lsfHighReserve) // Sender reserve is set.
&& !isSetBit (uFlags, !bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)
&& !sleRippleState->getFieldAmount (!bSenderHigh ? sfLowLimit : sfHighLimit) // Sender trust limit is 0.
@@ -1617,7 +1617,7 @@ TER LedgerEntrySet::accountSend (const uint160& uSenderID, const uint160& uRecei
{
TER terResult = tesSUCCESS;
assert (!saAmount.isNegative ());
assert (saAmount >= zero);
if (!saAmount || (uSenderID == uReceiverID))
{

View File

@@ -2927,11 +2927,11 @@ void NetworkOPsImp::getBookPage (Ledger::pointer lpLedger, const uint160& uTaker
saOwnerFunds = lesActive.accountHolds (uOfferOwnerID, uTakerGetsCurrencyID, uTakerGetsIssuerID);
// m_journal.info << boost::str(boost::format("getBookPage: saOwnerFunds=%s (new)") % saOwnerFunds.getFullText());
if (saOwnerFunds.isNegative ())
if (saOwnerFunds < zero)
{
// Treat negative funds as zero.
saOwnerFunds.zero ();
saOwnerFunds.clear ();
}
}
}
@@ -2985,7 +2985,7 @@ void NetworkOPsImp::getBookPage (Ledger::pointer lpLedger, const uint160& uTaker
umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
if (!saOwnerFunds.isZero () || uOfferOwnerID == uTakerID)
if (saOwnerFunds != zero || uOfferOwnerID == uTakerID)
{
// Only provide funded offers and offers of the taker.
Json::Value& jvOf = jvOffers.append (jvOffer);

View File

@@ -114,7 +114,7 @@ bool PathRequest::needsUpdate (bool newOnly, LedgerIndex index)
bool PathRequest::isValid (RippleLineCache::ref crCache)
{
ScopedLockType sl (mLock);
bValid = raSrcAccount.isSet () && raDstAccount.isSet () && saDstAmount.isPositive ();
bValid = raSrcAccount.isSet () && raDstAccount.isSet () && saDstAmount > zero;
Ledger::pointer lrLedger = crCache->getLedger ();
if (bValid)
@@ -246,7 +246,7 @@ int PathRequest::parseJson (const Json::Value& jvParams, bool complete)
if (!saDstAmount.bSetJson (jvParams["destination_amount"]) ||
(saDstAmount.getCurrency ().isZero () && saDstAmount.getIssuer ().isNonZero ()) ||
(saDstAmount.getCurrency () == CURRENCY_BAD) ||
!saDstAmount.isPositive ())
saDstAmount <= zero)
{
jvStatus = rpcError (rpcDST_AMT_MALFORMED);
return PFR_PJ_INVALID;

View File

@@ -307,7 +307,7 @@ TER PathState::pushNode (
}
else if ((isSetBit (sleBck->getFieldU32 (sfFlags), lsfRequireAuth)
&& !isSetBit (sleRippleState->getFieldU32 (sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth)))
&& sleRippleState->getFieldAmount(sfBalance).isZero()) // CHECKME
&& sleRippleState->getFieldAmount(sfBalance) == zero) // CHECKME
{
WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from issuer without auth.";
@@ -319,7 +319,7 @@ TER PathState::pushNode (
STAmount saOwed = lesEntries.rippleOwed (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
STAmount saLimit;
if (!saOwed.isPositive ()
if (saOwed <= zero
&& -saOwed >= (saLimit = lesEntries.rippleLimit (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)))
{
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("pushNode: dry: saOwed=%s saLimit=%s")

View File

@@ -104,7 +104,7 @@ Pathfinder::Pathfinder (RippleLineCache::ref cache,
mLedger (cache->getLedger ()), mRLCache (cache)
{
if (((mSrcAccountID == mDstAccountID) && (mSrcCurrencyID == mDstAmount.getCurrency ())) || mDstAmount.isZero ())
if ((mSrcAccountID == mDstAccountID && mSrcCurrencyID == mDstAmount.getCurrency ()) || mDstAmount == zero)
{
// no need to send to same account with same currency, must send non-zero
bValid = false;
@@ -373,7 +373,7 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath)
WriteLog (lsDEBUG, Pathfinder) << "Skipping a non-filling path: " << mCompletePaths[lqt.get<3> ()].getJson (0);
}
if (remaining.isPositive ())
if (remaining > zero)
{
WriteLog (lsINFO, Pathfinder) << "Paths could not send " << remaining << " of " << mDstAmount;
}
@@ -409,7 +409,7 @@ boost::unordered_set<uint160> usAccountSourceCurrencies (
const STAmount& saBalance = rspEntry->getBalance ();
// Filter out non
if (saBalance.isPositive () // Have IOUs to send.
if (saBalance > zero // Have IOUs to send.
|| (rspEntry->getLimitPeer () // Peer extends credit.
&& ((-saBalance) < rspEntry->getLimitPeer ()))) // Credit left.
{
@@ -489,7 +489,7 @@ int Pathfinder::getPathsOut (RippleCurrency const& currencyID, const uint160& ac
if (currencyID != rspEntry->getLimit ().getCurrency ())
nothing ();
else if (!rspEntry->getBalance ().isPositive () &&
else if (rspEntry->getBalance () <= zero &&
(!rspEntry->getLimitPeer ()
|| -rspEntry->getBalance () >= rspEntry->getLimitPeer ()
|| (bAuthRequired && !rspEntry->getAuth ())))
@@ -657,7 +657,7 @@ void Pathfinder::addLink(
if ((uEndCurrency == rspEntry.getLimit().getCurrency()) &&
!currentPath.hasSeen(acctID, uEndCurrency, acctID))
{ // path is for correct currency and has not been seen
if (!rspEntry.getBalance().isPositive()
if (rspEntry.getBalance() <= zero
&& (!rspEntry.getLimitPeer()
|| -rspEntry.getBalance() >= rspEntry.getLimitPeer()
|| (bRequireAuth && !rspEntry.getAuth())))

View File

@@ -226,7 +226,7 @@ TER RippleCalc::calcNodeAdvance (
musUnfundedFound.insert(uOfferIndex);
continue;
}
else if (!saTakerPays.isPositive () || !saTakerGets.isPositive ())
else if (saTakerPays <= zero || saTakerGets <= zero)
{
// Offer has bad amounts. Offers should never have a bad amounts.
@@ -301,7 +301,7 @@ TER RippleCalc::calcNodeAdvance (
saOfferFunds = lesActive.accountFunds (uOfrOwnerID, saTakerGets); // Funds held.
if (!saOfferFunds.isPositive ())
if (saOfferFunds <= zero)
{
// Offer is unfunded.
WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: unfunded offer";
@@ -388,7 +388,7 @@ TER RippleCalc::calcNodeDeliverRev (
bDirectRestart = true; // Restart at same quality.
// YYY Note this gets zeroed on each increment, ideally only on first increment, then it could be a limit on the forward pass.
saOutAct.zero (saOutReq);
saOutAct.clear (saOutReq);
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeDeliverRev> saOutAct=%s saOutReq=%s saPrvDlvReq=%s")
% saOutAct
@@ -421,7 +421,8 @@ TER RippleCalc::calcNodeDeliverRev (
STAmount& saTakerGets = pnCur.saTakerGets;
STAmount& saRateMax = pnCur.saRateMax;
terResult = calcNodeAdvance (uNode, psCur, bMultiQuality || saOutAct.isZero(), true); // If needed, advance to next funded offer.
terResult = calcNodeAdvance (uNode, psCur, bMultiQuality || saOutAct == zero, true);
// If needed, advance to next funded offer.
if (tesSUCCESS != terResult || !uOfferIndex)
{
@@ -595,7 +596,7 @@ TER RippleCalc::calcNodeDeliverRev (
STAmount saTakerGetsNew = saTakerGets - saOutPassAct;
STAmount saTakerPaysNew = saTakerPays - saInPassAct;
if (saTakerPaysNew.isNegative () || saTakerGetsNew.isNegative ())
if (saTakerPaysNew < zero || saTakerGetsNew < zero)
{
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeDeliverRev: NEGATIVE: saTakerPaysNew=%s saTakerGetsNew=%s")
% saTakerPaysNew % saTakerGetsNew);
@@ -683,8 +684,8 @@ TER RippleCalc::calcNodeDeliverFwd (
else
bDirectRestart = true; // Restart at same quality.
saInAct.zero (saInReq);
saInFees.zero (saInReq);
saInAct.clear (saInReq);
saInFees.clear (saInReq);
int loopCount = 0;
@@ -700,7 +701,8 @@ TER RippleCalc::calcNodeDeliverFwd (
}
// Determine values for pass to adjust saInAct, saInFees, and saCurDeliverAct
terResult = calcNodeAdvance (uNode, psCur, bMultiQuality || saInAct.isZero(), false); // If needed, advance to next funded offer.
terResult = calcNodeAdvance (uNode, psCur, bMultiQuality || saInAct == zero, false);
// If needed, advance to next funded offer.
if (tesSUCCESS != terResult)
{
@@ -738,8 +740,8 @@ TER RippleCalc::calcNodeDeliverFwd (
STAmount saInTotal = STAmount::mulRound (saInFunded, saInFeeRate, true); // Offer maximum in with fees.
STAmount saInRemaining = saInReq - saInAct - saInFees;
if (saInRemaining.isNegative())
saInRemaining.zero();
if (saInRemaining < zero)
saInRemaining.clear();
STAmount saInSum = std::min (saInTotal, saInRemaining); // In limited by remaining.
STAmount saInPassAct = std::min (saTakerPays, STAmount::divRound (saInSum, saInFeeRate, true)); // In without fees.
@@ -766,7 +768,7 @@ TER RippleCalc::calcNodeDeliverFwd (
% saInPassAct
% saOutPassMax);
if (!saTakerPays || !saInSum.isPositive()) // FIXME: We remove an offer if WE didn't want anything out of it?
if (!saTakerPays || saInSum <= zero) // FIXME: We remove an offer if WE didn't want anything out of it?
{
WriteLog (lsDEBUG, RippleCalc) << "calcNodeDeliverFwd: Microscopic offer unfunded.";
@@ -883,7 +885,7 @@ TER RippleCalc::calcNodeDeliverFwd (
STAmount saTakerGetsNew = saTakerGets - saOutPassAct;
STAmount saTakerPaysNew = saTakerPays - saInPassAct;
if (saTakerPaysNew.isNegative () || saTakerGetsNew.isNegative ())
if (saTakerPaysNew < zero || saTakerGetsNew < zero)
{
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("calcNodeDeliverFwd: NEGATIVE: saTakerPaysNew=%s saTakerGetsNew=%s")
% saTakerPaysNew % saTakerGetsNew);
@@ -899,7 +901,7 @@ TER RippleCalc::calcNodeDeliverFwd (
lesActive.entryModify (sleOffer);
if ((saOutPassAct == saOutFunded) || saTakerGetsNew.isZero())
if (saOutPassAct == saOutFunded || saTakerGetsNew == zero)
{
// Offer became unfunded.
@@ -1046,12 +1048,12 @@ void RippleCalc::calcNodeRipple (
% saPrvAct
% saCurAct);
assert (saCurReq.isPositive ()); // FIXME: saCurReq was zero
assert (saCurReq > zero); // FIXME: saCurReq was zero
assert (saPrvReq.getCurrency () == saCurReq.getCurrency ());
assert (saPrvReq.getCurrency () == saPrvAct.getCurrency ());
assert (saPrvReq.getIssuer () == saPrvAct.getIssuer ());
const bool bPrvUnlimited = saPrvReq.isNegative ();
const bool bPrvUnlimited = saPrvReq < zero;
const STAmount saPrv = bPrvUnlimited ? STAmount (saPrvReq) : saPrvReq - saPrvAct;
const STAmount saCur = saCurReq - saCurAct;
@@ -1187,11 +1189,11 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
% saPrvLimit);
// Previous can redeem the owed IOUs it holds.
const STAmount saPrvRedeemReq = saPrvOwed.isPositive () ? saPrvOwed : STAmount (saPrvOwed.getCurrency (), saPrvOwed.getIssuer ());
const STAmount saPrvRedeemReq = (saPrvOwed > zero) ? saPrvOwed : STAmount (saPrvOwed.getCurrency (), saPrvOwed.getIssuer ());
STAmount& saPrvRedeemAct = pnPrv.saRevRedeem;
// Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount).
const STAmount saPrvIssueReq = saPrvOwed.isNegative () ? saPrvLimit + saPrvOwed : saPrvLimit;
const STAmount saPrvIssueReq = (saPrvOwed < zero) ? saPrvLimit + saPrvOwed : saPrvLimit;
STAmount& saPrvIssueAct = pnPrv.saRevIssue;
// For !bPrvAccount
@@ -1222,7 +1224,7 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
assert (!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand.
assert (!saCurIssueReq // If not issuing, fine.
|| !saNxtOwed.isNegative () // saNxtOwed >= 0: Sender not holding next IOUs, saNxtOwed < 0: Sender holding next IOUs.
|| saNxtOwed >= zero // saNxtOwed >= 0: Sender not holding next IOUs, saNxtOwed < 0: Sender holding next IOUs.
|| -saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed.
if (!uNode)
@@ -1262,11 +1264,11 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
}
else
{
saPrvRedeemAct.zero (saPrvRedeemReq);
saPrvRedeemAct.clear (saPrvRedeemReq);
}
// Calculate issuing.
saPrvIssueAct.zero (saPrvIssueReq);
saPrvIssueAct.clear (saPrvIssueReq);
if (saCurWantedReq != saCurWantedAct // Need more.
&& saPrvIssueReq) // Will accept IOUs from prevous.
@@ -1290,8 +1292,8 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
else
{
// ^|account --> ACCOUNT --> account
saPrvRedeemAct.zero (saPrvRedeemReq);
saPrvIssueAct.zero (saPrvIssueReq);
saPrvRedeemAct.clear (saPrvRedeemReq);
saPrvIssueAct.clear (saPrvIssueReq);
// redeem (part 1) -> redeem
if (saCurRedeemReq // Next wants IOUs redeemed.
@@ -1364,12 +1366,12 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
// Note: deliver is always issue as ACCOUNT is the issuer for the offer input.
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAccountRev: account --> ACCOUNT --> offer"));
saPrvRedeemAct.zero (saPrvRedeemReq);
saPrvIssueAct.zero (saPrvIssueReq);
saPrvRedeemAct.clear (saPrvRedeemReq);
saPrvIssueAct.clear (saPrvIssueReq);
// redeem -> deliver/issue.
if (saPrvOwed.isPositive () // Previous has IOUs to redeem.
&& saCurDeliverReq) // Need some issued.
if (saPrvOwed > zero // Previous has IOUs to redeem.
&& saCurDeliverReq) // Need some issued.
{
// Rate : 1.0 : transfer_rate
calcNodeRipple (QUALITY_ONE, lesActive.rippleTransferRate (uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax);
@@ -1407,14 +1409,15 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
% psCur.saOutAct
% psCur.saOutReq);
if (!saCurWantedReq.isPositive ())
if (saCurWantedReq <= zero)
{
// TEMPORARY emergency fix
WriteLog (lsFATAL, RippleCalc) << "CurWantReq was not positive";
return tefEXCEPTION;
}
assert (saCurWantedReq.isPositive ()); // FIXME: We got one of these
assert (saCurWantedReq > zero); // FIXME: We got one of these
// TR notes: can only be a race condition if true!
// Rate: quality in : 1.0
calcNodeRipple (uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct, uRateMax);
@@ -1576,7 +1579,7 @@ TER RippleCalc::calcNodeAccountFwd (
saCurRedeemAct = saCurRedeemReq;
if (!psCur.saInReq.isNegative ())
if (psCur.saInReq >= zero)
{
// Limit by send max.
saCurRedeemAct = std::min (saCurRedeemAct, psCur.saInReq - psCur.saInAct);
@@ -1588,7 +1591,7 @@ TER RippleCalc::calcNodeAccountFwd (
? saCurIssueReq
: STAmount (saCurIssueReq);
if (!!saCurIssueAct && !psCur.saInReq.isNegative ())
if (!!saCurIssueAct && psCur.saInReq >= zero)
{
// Limit by send max.
saCurIssueAct = std::min (saCurIssueAct, psCur.saInReq - psCur.saInAct - saCurRedeemAct);
@@ -1640,8 +1643,8 @@ TER RippleCalc::calcNodeAccountFwd (
// account --> ACCOUNT --> account
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAccountFwd: account --> ACCOUNT --> account"));
saCurRedeemAct.zero (saCurRedeemReq);
saCurIssueAct.zero (saCurIssueReq);
saCurRedeemAct.clear (saCurRedeemReq);
saCurIssueAct.clear (saCurIssueReq);
// Previous redeem part 1: redeem -> redeem
if (saPrvRedeemReq && saCurRedeemReq) // Previous wants to redeem.
@@ -1696,7 +1699,7 @@ TER RippleCalc::calcNodeAccountFwd (
// Non-XRP, current node is the issuer.
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAccountFwd: account --> ACCOUNT --> offer"));
saCurDeliverAct.zero (saCurDeliverReq);
saCurDeliverAct.clear (saCurDeliverReq);
// redeem -> issue/deliver.
// Previous wants to redeem.
@@ -1727,7 +1730,7 @@ TER RippleCalc::calcNodeAccountFwd (
saCurDeliverAct = saCurDeliverReq;
// If limited, then limit by send max and available.
if (!psCur.saInReq.isNegative ())
if (psCur.saInReq >= zero)
{
// Limit by send max.
saCurDeliverAct = std::min (saCurDeliverAct, psCur.saInReq - psCur.saInAct);
@@ -1784,8 +1787,8 @@ TER RippleCalc::calcNodeAccountFwd (
// offer --> ACCOUNT --> account
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAccountFwd: offer --> ACCOUNT --> account"));
saCurRedeemAct.zero (saCurRedeemReq);
saCurIssueAct.zero (saCurIssueReq);
saCurRedeemAct.clear (saCurRedeemReq);
saCurIssueAct.clear (saCurIssueReq);
// deliver -> redeem
if (saPrvDeliverReq && saCurRedeemReq) // Previous wants to deliver and can current redeem.
@@ -1817,7 +1820,7 @@ TER RippleCalc::calcNodeAccountFwd (
// deliver/redeem -> deliver/issue.
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("calcNodeAccountFwd: offer --> ACCOUNT --> offer"));
saCurDeliverAct.zero (saCurDeliverReq);
saCurDeliverAct.clear (saCurDeliverReq);
if (saPrvDeliverReq // Previous wants to deliver
&& saCurIssueReq) // Current wants issue.
@@ -1937,10 +1940,10 @@ void RippleCalc::pathNext (PathState::ref psrCur, const bool bMultiQuality, cons
{
PathState::Node& pnCur = psrCur->vpnNodes[uIndex];
pnCur.saRevRedeem.zero ();
pnCur.saRevIssue.zero ();
pnCur.saRevDeliver.zero ();
pnCur.saFwdDeliver.zero ();
pnCur.saRevRedeem.clear ();
pnCur.saRevIssue.clear ();
pnCur.saRevDeliver.clear ();
pnCur.saFwdDeliver.clear ();
}
psrCur->terStatus = calcNodeRev (uLast, *psrCur, bMultiQuality);
@@ -2139,12 +2142,12 @@ TER RippleCalc::rippleCalc (
pspCur->saInAct = saMaxAmountAct; // Update to current amount processed.
pspCur->saOutAct = saDstAmountAct;
CondLog (pspCur->saInReq.isPositive () && pspCur->saInAct >= pspCur->saInReq, lsWARNING, RippleCalc)
CondLog (pspCur->saInReq > zero && pspCur->saInAct >= pspCur->saInReq, lsWARNING, RippleCalc)
<< boost::str (boost::format ("rippleCalc: DONE: saInAct=%s saInReq=%s")
% pspCur->saInAct
% pspCur->saInReq);
assert (pspCur->saInReq.isNegative () || pspCur->saInAct < pspCur->saInReq); // Error if done.
assert (pspCur->saInReq < zero || pspCur->saInAct < pspCur->saInReq); // Error if done.
CondLog (pspCur->saOutAct >= pspCur->saOutReq, lsWARNING, RippleCalc)
<< boost::str (boost::format ("rippleCalc: ALREADY DONE: saOutAct=%s saOutReq=%s")

View File

@@ -1674,7 +1674,7 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value params, Resource::Charge&
// Parse saDstAmount.
!params.isMember ("destination_amount")
|| !saDstAmount.bSetJson (params["destination_amount"])
|| !saDstAmount.isPositive()
|| saDstAmount <= zero
|| (!!saDstAmount.getCurrency () && (!saDstAmount.getIssuer () || ACCOUNT_ONE == saDstAmount.getIssuer ())))
{
WriteLog (lsINFO, RPCHandler) << "Bad destination_amount.";

View File

@@ -53,7 +53,7 @@ bool OfferCreateTransactor::isValidOffer (
return false;
}
if (!saOfferGets.isPositive () || !saOfferPays.isPositive ())
if (saOfferGets <= zero || saOfferPays <= zero)
{
// Offer has bad amounts. Consider offer expired. Delete it.
m_journal.warning << "isValidOffer: BAD OFFER:" <<
@@ -70,7 +70,7 @@ bool OfferCreateTransactor::isValidOffer (
saOfferFunds = mEngine->view ().accountFunds (uOfferOwnerID, saOfferPays);
if (!saOfferFunds.isPositive ())
if (saOfferFunds <= zero)
{
// Offer is unfunded, possibly due to previous balance action.
m_journal.debug << "isValidOffer: offer unfunded: delete";
@@ -107,7 +107,7 @@ bool OfferCreateTransactor::canCross (
bool& isUnfunded,
TER& terResult) const
{
if (!saTakerFunds.isPositive ())
if (saTakerFunds <= zero)
{
// Taker is out of funds. Don't create the offer.
isUnfunded = true;
@@ -115,7 +115,7 @@ bool OfferCreateTransactor::canCross (
return false;
}
if (!saSubTakerPays.isPositive() || !saSubTakerGets.isPositive())
if (saSubTakerPays <= zero || saSubTakerGets <= zero)
{
// Offer is completely consumed
terResult = tesSUCCESS;
@@ -201,8 +201,8 @@ bool OfferCreateTransactor::applyOffer (
{
saOfferGets.throwComparable (saTakerFunds);
assert (saOfferFunds.isPositive () && saTakerFunds.isPositive ()); // Both must have funds.
assert (saOfferGets.isPositive () && saOfferPays.isPositive ()); // Must not be a null offer.
assert (saOfferFunds > zero && saTakerFunds > zero); // Both must have funds.
assert (saOfferGets > zero && saOfferPays > zero); // Must not be a null offer.
// Available = limited by funds.
// Limit offerer funds available, by transfer fees.
@@ -292,7 +292,7 @@ bool OfferCreateTransactor::applyOffer (
? saTakerFunds - saTakerPaid // Not enough funds to cover fee, stiff issuer the rounding error.
: saTakerCost - saTakerPaid;
WriteLog (lsINFO, STAmount) << "applyOffer: saTakerIssuerFee=" << saTakerIssuerFee.getFullText ();
assert (!saTakerIssuerFee.isNegative ());
assert (saTakerIssuerFee >= zero);
}
if (uOfferPaysRate == QUALITY_ONE)
@@ -600,7 +600,7 @@ TER OfferCreateTransactor::takeOffers (
// TODO check the synthetic case here (to ensure there
// is no corruption)
if (!saOfferPays.isPositive () || !saOfferGets.isPositive ())
if (saOfferPays <= zero || saOfferGets <= zero)
{
m_journal.warning <<
"takeOffers: ILLEGAL OFFER RESULT.";
@@ -811,7 +811,7 @@ TER OfferCreateTransactor::doApply ()
terResult = temBAD_OFFER;
}
else if (!saTakerPays.isPositive () || !saTakerGets.isPositive ())
else if (saTakerPays <= zero || saTakerGets <= zero)
{
m_journal.warning <<
"Malformed offer: bad amount";
@@ -840,7 +840,7 @@ TER OfferCreateTransactor::doApply ()
terResult = temBAD_ISSUER;
}
else if (!lesActive.accountFunds (mTxnAccountID, saTakerGets).isPositive ())
else if (lesActive.accountFunds (mTxnAccountID, saTakerGets) <= zero)
{
m_journal.warning <<
"delay: Offers must be at least partially funded.";
@@ -1019,7 +1019,7 @@ TER OfferCreateTransactor::doApply ()
// nothing to do
nothing ();
}
else if (saTakerPays.isNegative () || saTakerGets.isNegative ())
else if (saTakerPays < zero || saTakerGets < zero)
{
// If ledger is not final, can vote no.
// When we are processing an open ledger, failures are local and we charge no fee;
@@ -1033,11 +1033,11 @@ TER OfferCreateTransactor::doApply ()
lesActive.swapWith (lesCheckpoint); // Restore with just fees paid.
}
else if (
!saTakerPays.isPositive() // Wants nothing more.
|| !saTakerGets.isPositive() // Offering nothing more.
|| bImmediateOrCancel // Do not persist.
|| !lesActive.accountFunds (mTxnAccountID, saTakerGets).isPositive () // Not funded.
|| bUnfunded) // Consider unfunded.
saTakerPays <= zero // Wants nothing more.
|| saTakerGets <= zero // Offering nothing more.
|| bImmediateOrCancel // Do not persist.
|| lesActive.accountFunds (mTxnAccountID, saTakerGets) <= zero // Not funded.
|| bUnfunded) // Consider unfunded.
{
// Complete as is.
nothing ();

View File

@@ -38,7 +38,7 @@ TER PaymentTransactor::doApply ()
mTxnAccountID,
saDstAmount.getMantissa (),
saDstAmount.getExponent (),
saDstAmount.isNegative ());
saDstAmount < zero);
uint160 const uSrcCurrency = saMaxAmount.getCurrency ();
uint160 const uDstCurrency = saDstAmount.getCurrency ();
bool const bXRPDirect = uSrcCurrency.isZero () && uDstCurrency.isZero ();
@@ -64,14 +64,14 @@ TER PaymentTransactor::doApply ()
return temDST_NEEDED;
}
else if (bMax && !saMaxAmount.isPositive ())
else if (bMax && saMaxAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad max amount: " << saMaxAmount.getFullText ();
return temBAD_AMOUNT;
}
else if (!saDstAmount.isPositive ())
else if (saDstAmount <= zero)
{
m_journal.trace <<
"Malformed transaction: bad dst amount: " << saDstAmount.getFullText ();

View File

@@ -45,7 +45,7 @@ TER RegularKeySetTransactor::doApply ()
return temINVALID_FLAG;
}
if (mFeeDue.isZero ())
if (mFeeDue == zero)
{
mTxnAccount->setFlag (lsfPasswordSpent);
}

View File

@@ -116,7 +116,7 @@ TER Transactor::payFee ()
return telINSUF_FEE_P;
}
if (saPaid.isNegative () || !saPaid.isNative ())
if (saPaid < zero || !saPaid.isNative ())
return temBAD_FEE;
if (!saPaid) return tesSUCCESS;

View File

@@ -73,7 +73,7 @@ TER TrustSetTransactor::doApply ()
return temBAD_LIMIT;
}
if (saLimitAmount.isNegative ())
if (saLimitAmount < zero)
{
m_journal.trace <<
"Malformed transaction: Negative credit limit.";
@@ -233,7 +233,7 @@ TER TrustSetTransactor::doApply ()
std::uint32_t const uFlagsIn (sleRippleState->getFieldU32 (sfFlags));
std::uint32_t uFlagsOut (uFlagsIn);
if (bSetNoRipple && !bClearNoRipple && (bHigh ? saHighBalance : saLowBalance).isGEZero())
if (bSetNoRipple && !bClearNoRipple && (bHigh ? saHighBalance : saLowBalance) >= zero)
{
uFlagsOut |= (bHigh ? lsfHighNoRipple : lsfLowNoRipple);
}
@@ -249,12 +249,12 @@ TER TrustSetTransactor::doApply ()
bool const bLowReserveSet = uLowQualityIn || uLowQualityOut ||
isSetBit (uFlagsOut, lsfLowNoRipple) ||
!!saLowLimit || saLowBalance.isPositive ();
!!saLowLimit || saLowBalance > zero;
bool const bLowReserveClear = !bLowReserveSet;
bool const bHighReserveSet = uHighQualityIn || uHighQualityOut ||
isSetBit (uFlagsOut, lsfHighNoRipple) ||
!!saHighLimit || saHighBalance.isPositive ();
!!saHighLimit || saHighBalance > zero;
bool const bHighReserveClear = !bHighReserveSet;
bool const bDefault = bLowReserveClear && bHighReserveClear;

View File

@@ -27,6 +27,10 @@
#include <atomic>
#include "../../beast/beast/cxx14/memory.h"
#include "../../beast/beast/utility/Zero.h"
using beast::zero;
using beast::Zero;
#ifndef RIPPLE_TRACK_MUTEXES
# define RIPPLE_TRACK_MUTEXES 0

View File

@@ -482,7 +482,7 @@ void STAmount::add (Serializer& s) const
}
else
{
if (isZero ())
if (*this == zero)
s.add64 (cNotNative);
else if (mIsNegative) // 512 = not native
s.add64 (mValue | (static_cast<std::uint64_t> (mOffset + 512 + 97) << (64 - 10)));
@@ -625,7 +625,8 @@ std::string STAmount::getRaw () const
std::string STAmount::getText () const
{
// keep full internal accuracy, but make more human friendly if posible
if (isZero ()) return "0";
if (*this == zero)
return "0";
if (mIsNative)
{
@@ -821,9 +822,10 @@ STAmount operator+ (const STAmount& v1, const STAmount& v2)
{
v1.throwComparable (v2);
if (v2.isZero ()) return v1;
if (v2 == zero)
return v1;
if (v1.isZero ())
if (v1 == zero)
{
// Result must be in terms of v1 currency and issuer.
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, v2.mIsNegative);
@@ -867,7 +869,8 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
{
v1.throwComparable (v2);
if (v2.isZero ()) return v1;
if (v2 == zero)
return v1;
if (v2.mIsNative)
{
@@ -908,10 +911,10 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
STAmount STAmount::divide (const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (den.isZero ())
if (den == zero)
throw std::runtime_error ("division by zero");
if (num.isZero ())
if (num == zero)
return STAmount (uCurrencyID, uIssuerID);
std::uint64_t numVal = num.mValue, denVal = den.mValue;
@@ -951,7 +954,7 @@ STAmount STAmount::divide (const STAmount& num, const STAmount& den, const uint1
STAmount STAmount::multiply (const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID)
{
if (v1.isZero () || v2.isZero ())
if (v1 == zero || v2 == zero)
return STAmount (uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative && uCurrencyID.isZero ())
@@ -1018,14 +1021,14 @@ STAmount STAmount::multiply (const STAmount& v1, const STAmount& v2, const uint1
// Zero is returned if the offer is worthless.
std::uint64_t STAmount::getRate (const STAmount& offerOut, const STAmount& offerIn)
{
if (offerOut.isZero ())
if (offerOut == zero)
return 0;
try
{
STAmount r = divide (offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE);
if (r.isZero ()) // offer is too good
if (r == zero) // offer is too good
return 0;
assert ((r.getExponent () >= -100) && (r.getExponent () <= 155));
@@ -1055,7 +1058,7 @@ STAmount STAmount::setRate (std::uint64_t rate)
STAmount STAmount::getPay (const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
{
// Someone wants to get (needed) out of the offer, how much should they pay in?
if (offerOut.isZero ())
if (offerOut == zero)
return STAmount (offerIn.getCurrency (), offerIn.getIssuer ());
if (needed >= offerOut)
@@ -1289,127 +1292,127 @@ public:
{
testcase ("native currency");
STAmount zero, one (1), hundred (100);
STAmount zeroSt, one (1), hundred (100);
unexpected (serializeAndDeserialize (zero) != zero, "STAmount fail");
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (!zero.isNative (), "STAmount fail");
unexpected (!zeroSt.isNative (), "STAmount fail");
unexpected (!hundred.isNative (), "STAmount fail");
unexpected (!zero.isZero (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one.isZero (), "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred.isZero (), "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zero < zero), "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zero < one), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zero < hundred), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zero), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zero), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zero > zero), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zero > one), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zero > hundred), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zero), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zero), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zero <= zero), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zero <= one), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zero <= hundred), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zero), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zero), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zero >= zero), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zero >= one), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zero >= hundred), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zero), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zero), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zero == zero), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zero == one), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zero == hundred), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zero), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zero), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zero != zero), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zero != one), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zero != hundred), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zero), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zero), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
@@ -1439,129 +1442,129 @@ public:
{
testcase ("custom currency");
STAmount zero (CURRENCY_ONE, ACCOUNT_ONE), one (CURRENCY_ONE, ACCOUNT_ONE, 1), hundred (CURRENCY_ONE, ACCOUNT_ONE, 100);
STAmount zeroSt (CURRENCY_ONE, ACCOUNT_ONE), one (CURRENCY_ONE, ACCOUNT_ONE, 1), hundred (CURRENCY_ONE, ACCOUNT_ONE, 100);
serializeAndDeserialize (one).getRaw ();
unexpected (serializeAndDeserialize (zero) != zero, "STAmount fail");
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
unexpected (serializeAndDeserialize (one) != one, "STAmount fail");
unexpected (serializeAndDeserialize (hundred) != hundred, "STAmount fail");
unexpected (zero.isNative (), "STAmount fail");
unexpected (zeroSt.isNative (), "STAmount fail");
unexpected (hundred.isNative (), "STAmount fail");
unexpected (!zero.isZero (), "STAmount fail");
unexpected (zeroSt != zero, "STAmount fail");
unexpected (one.isZero (), "STAmount fail");
unexpected (one == zero, "STAmount fail");
unexpected (hundred.isZero (), "STAmount fail");
unexpected (hundred == zero, "STAmount fail");
unexpected ((zero < zero), "STAmount fail");
unexpected ((zeroSt < zeroSt), "STAmount fail");
unexpected (! (zero < one), "STAmount fail");
unexpected (! (zeroSt < one), "STAmount fail");
unexpected (! (zero < hundred), "STAmount fail");
unexpected (! (zeroSt < hundred), "STAmount fail");
unexpected ((one < zero), "STAmount fail");
unexpected ((one < zeroSt), "STAmount fail");
unexpected ((one < one), "STAmount fail");
unexpected (! (one < hundred), "STAmount fail");
unexpected ((hundred < zero), "STAmount fail");
unexpected ((hundred < zeroSt), "STAmount fail");
unexpected ((hundred < one), "STAmount fail");
unexpected ((hundred < hundred), "STAmount fail");
unexpected ((zero > zero), "STAmount fail");
unexpected ((zeroSt > zeroSt), "STAmount fail");
unexpected ((zero > one), "STAmount fail");
unexpected ((zeroSt > one), "STAmount fail");
unexpected ((zero > hundred), "STAmount fail");
unexpected ((zeroSt > hundred), "STAmount fail");
unexpected (! (one > zero), "STAmount fail");
unexpected (! (one > zeroSt), "STAmount fail");
unexpected ((one > one), "STAmount fail");
unexpected ((one > hundred), "STAmount fail");
unexpected (! (hundred > zero), "STAmount fail");
unexpected (! (hundred > zeroSt), "STAmount fail");
unexpected (! (hundred > one), "STAmount fail");
unexpected ((hundred > hundred), "STAmount fail");
unexpected (! (zero <= zero), "STAmount fail");
unexpected (! (zeroSt <= zeroSt), "STAmount fail");
unexpected (! (zero <= one), "STAmount fail");
unexpected (! (zeroSt <= one), "STAmount fail");
unexpected (! (zero <= hundred), "STAmount fail");
unexpected (! (zeroSt <= hundred), "STAmount fail");
unexpected ((one <= zero), "STAmount fail");
unexpected ((one <= zeroSt), "STAmount fail");
unexpected (! (one <= one), "STAmount fail");
unexpected (! (one <= hundred), "STAmount fail");
unexpected ((hundred <= zero), "STAmount fail");
unexpected ((hundred <= zeroSt), "STAmount fail");
unexpected ((hundred <= one), "STAmount fail");
unexpected (! (hundred <= hundred), "STAmount fail");
unexpected (! (zero >= zero), "STAmount fail");
unexpected (! (zeroSt >= zeroSt), "STAmount fail");
unexpected ((zero >= one), "STAmount fail");
unexpected ((zeroSt >= one), "STAmount fail");
unexpected ((zero >= hundred), "STAmount fail");
unexpected ((zeroSt >= hundred), "STAmount fail");
unexpected (! (one >= zero), "STAmount fail");
unexpected (! (one >= zeroSt), "STAmount fail");
unexpected (! (one >= one), "STAmount fail");
unexpected ((one >= hundred), "STAmount fail");
unexpected (! (hundred >= zero), "STAmount fail");
unexpected (! (hundred >= zeroSt), "STAmount fail");
unexpected (! (hundred >= one), "STAmount fail");
unexpected (! (hundred >= hundred), "STAmount fail");
unexpected (! (zero == zero), "STAmount fail");
unexpected (! (zeroSt == zeroSt), "STAmount fail");
unexpected ((zero == one), "STAmount fail");
unexpected ((zeroSt == one), "STAmount fail");
unexpected ((zero == hundred), "STAmount fail");
unexpected ((zeroSt == hundred), "STAmount fail");
unexpected ((one == zero), "STAmount fail");
unexpected ((one == zeroSt), "STAmount fail");
unexpected (! (one == one), "STAmount fail");
unexpected ((one == hundred), "STAmount fail");
unexpected ((hundred == zero), "STAmount fail");
unexpected ((hundred == zeroSt), "STAmount fail");
unexpected ((hundred == one), "STAmount fail");
unexpected (! (hundred == hundred), "STAmount fail");
unexpected ((zero != zero), "STAmount fail");
unexpected ((zeroSt != zeroSt), "STAmount fail");
unexpected (! (zero != one), "STAmount fail");
unexpected (! (zeroSt != one), "STAmount fail");
unexpected (! (zero != hundred), "STAmount fail");
unexpected (! (zeroSt != hundred), "STAmount fail");
unexpected (! (one != zero), "STAmount fail");
unexpected (! (one != zeroSt), "STAmount fail");
unexpected ((one != one), "STAmount fail");
unexpected (! (one != hundred), "STAmount fail");
unexpected (! (hundred != zero), "STAmount fail");
unexpected (! (hundred != zeroSt), "STAmount fail");
unexpected (! (hundred != one), "STAmount fail");
@@ -1708,27 +1711,27 @@ public:
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1);
STAmount smallValue (CURRENCY_ONE, ACCOUNT_ONE,
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1);
STAmount zero (CURRENCY_ONE, ACCOUNT_ONE, 0);
STAmount zeroSt (CURRENCY_ONE, ACCOUNT_ONE, 0);
STAmount smallXsmall = STAmount::multiply (smallValue, smallValue, CURRENCY_ONE, ACCOUNT_ONE);
expect (smallXsmall.isZero (), "smallXsmall != 0");
expect (smallXsmall == zero, "smallXsmall != 0");
STAmount bigDsmall = STAmount::divide (smallValue, bigValue, CURRENCY_ONE, ACCOUNT_ONE);
expect (bigDsmall.isZero (), beast::String ("small/big != 0: ") + bigDsmall.getText ());
expect (bigDsmall == zero, beast::String ("small/big != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigNative, CURRENCY_ONE, uint160 ());
expect (bigDsmall.isZero (), beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
expect (bigDsmall == zero, beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigValue, uint160 (), uint160 ());
expect (bigDsmall.isZero (), beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
expect (bigDsmall == zero, beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigNative, uint160 (), uint160 ());
expect (bigDsmall.isZero (), beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
expect (bigDsmall == zero, beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
// very bad offer
std::uint64_t r = STAmount::getRate (smallValue, bigValue);

View File

@@ -203,7 +203,7 @@ STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundU
STAmount STAmount::mulRound (const STAmount& v1, const STAmount& v2,
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
{
if (v1.isZero () || v2.isZero ())
if (v1 == zero || v2 == zero)
return STAmount (uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative && uCurrencyID.isZero ())
@@ -267,10 +267,10 @@ STAmount STAmount::mulRound (const STAmount& v1, const STAmount& v2,
STAmount STAmount::divRound (const STAmount& num, const STAmount& den,
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
{
if (den.isZero ())
if (den == zero)
throw std::runtime_error ("division by zero");
if (num.isZero ())
if (num == zero)
return STAmount (uCurrencyID, uIssuerID);
std::uint64_t numVal = num.mValue, denVal = den.mValue;

View File

@@ -574,6 +574,11 @@ public:
return mValue;
}
int signum () const
{
return mValue ? (mIsNegative ? -1 : 1) : 0;
}
// When the currency is XRP, the value in raw units. S=signed
std::uint64_t getNValue () const
{
@@ -596,30 +601,6 @@ public:
{
return mIsNative;
}
bool isZero () const
{
return mValue == 0;
}
bool isNonZero () const
{
return mValue != 0;
}
bool isNegative () const
{
return mIsNegative && !isZero ();
}
bool isPositive () const
{
return !mIsNegative && !isZero ();
}
bool isLEZero () const
{
return mIsNegative || isZero ();
}
bool isGEZero () const
{
return !mIsNegative;
}
bool isLegalNet () const
{
return !mIsNative || (mValue <= cMaxNativeN);
@@ -628,15 +609,16 @@ public:
explicit
operator bool () const noexcept
{
return !isZero ();
return *this != zero;
}
void negate ()
{
if (!isZero ()) mIsNegative = !mIsNegative;
if (*this != zero)
mIsNegative = !mIsNegative;
}
void zero ()
void clear ()
{
// VFALCO: Why -100?
mOffset = mIsNative ? 0 : -100;
@@ -645,19 +627,25 @@ public:
}
// Zero while copying currency and issuer.
void zero (const STAmount& saTmpl)
void clear (const STAmount& saTmpl)
{
mCurrency = saTmpl.mCurrency;
mIssuer = saTmpl.mIssuer;
mIsNative = saTmpl.mIsNative;
zero ();
clear ();
}
void zero (const uint160& uCurrencyID, const uint160& uIssuerID)
void clear (const uint160& uCurrencyID, const uint160& uIssuerID)
{
mCurrency = uCurrencyID;
mIssuer = uIssuerID;
mIsNative = !uCurrencyID;
zero ();
clear ();
}
STAmount& operator=(beast::Zero)
{
clear ();
return *this;
}
int compare (const STAmount&) const;