Skip to content

Commit 2fa59f1

Browse files
HowardHinnantgregtatcam
authored andcommitted
[FOLD] Merge with the latest Number
1 parent dd7f8db commit 2fa59f1

File tree

11 files changed

+1291
-841
lines changed

11 files changed

+1291
-841
lines changed

src/ripple/basics/IOUAmount.h

-4
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,6 @@ mulRatio(
186186
std::uint32_t den,
187187
bool roundUp);
188188

189-
// Since IOUAmount and STAmount do not have access to a ledger, this
190-
// is needed to put low-level routines on an amendment switch. Only
191-
// transactions need to use this switchover. Outside of a transaction
192-
// it's safe to unconditionally use the new behavior.
193189
extern LocalValue<bool> stNumberSwitchover;
194190

195191
/** RAII class to set and restore the Number switchover.

src/ripple/basics/Number.h

+19
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <ripple/basics/XRPAmount.h>
2424
#include <cstdint>
25+
#include <limits>
2526
#include <ostream>
2627
#include <string>
2728

@@ -336,6 +337,24 @@ squelch(Number const& x, Number const& limit) noexcept
336337
return x;
337338
}
338339

340+
class saveNumberRoundMode
341+
{
342+
Number::rounding_mode mode_;
343+
344+
public:
345+
~saveNumberRoundMode()
346+
{
347+
Number::setround(mode_);
348+
}
349+
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
350+
: mode_{mode}
351+
{
352+
}
353+
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
354+
saveNumberRoundMode&
355+
operator=(saveNumberRoundMode const&) = delete;
356+
};
357+
339358
} // namespace ripple
340359

341360
#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED

src/ripple/basics/impl/IOUAmount.cpp

+37-38
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ IOUAmount::minPositiveAmount()
4545
void
4646
IOUAmount::normalize()
4747
{
48+
if (mantissa_ == 0)
49+
{
50+
*this = beast::zero;
51+
return;
52+
}
53+
4854
if (*stNumberSwitchover)
4955
{
5056
Number v{mantissa_, exponent_};
@@ -56,11 +62,6 @@ IOUAmount::normalize()
5662
*this = beast::zero;
5763
return;
5864
}
59-
if (mantissa_ == 0)
60-
{
61-
*this = beast::zero;
62-
return;
63-
}
6465

6566
bool const negative = (mantissa_ < 0);
6667

@@ -107,48 +108,46 @@ IOUAmount::IOUAmount(Number const& other)
107108
IOUAmount&
108109
IOUAmount::operator+=(IOUAmount const& other)
109110
{
111+
if (other == beast::zero)
112+
return *this;
113+
114+
if (*this == beast::zero)
115+
{
116+
*this = other;
117+
return *this;
118+
}
119+
110120
if (*stNumberSwitchover)
111121
{
112122
*this = IOUAmount{Number{*this} + Number{other}};
123+
return *this;
113124
}
114-
else
115-
{
116-
if (other == beast::zero)
117-
return *this;
118-
119-
if (*this == beast::zero)
120-
{
121-
*this = other;
122-
return *this;
123-
}
125+
auto m = other.mantissa_;
126+
auto e = other.exponent_;
124127

125-
auto m = other.mantissa_;
126-
auto e = other.exponent_;
127-
128-
while (exponent_ < e)
129-
{
130-
mantissa_ /= 10;
131-
++exponent_;
132-
}
133-
134-
while (e < exponent_)
135-
{
136-
m /= 10;
137-
++e;
138-
}
128+
while (exponent_ < e)
129+
{
130+
mantissa_ /= 10;
131+
++exponent_;
132+
}
139133

140-
// This addition cannot overflow an std::int64_t but we may throw from
141-
// normalize if the result isn't representable.
142-
mantissa_ += m;
134+
while (e < exponent_)
135+
{
136+
m /= 10;
137+
++e;
138+
}
143139

144-
if (mantissa_ >= -10 && mantissa_ <= 10)
145-
{
146-
*this = beast::zero;
147-
return *this;
148-
}
140+
// This addition cannot overflow an std::int64_t but we may throw from
141+
// normalize if the result isn't representable.
142+
mantissa_ += m;
149143

150-
normalize();
144+
if (mantissa_ >= -10 && mantissa_ <= 10)
145+
{
146+
*this = beast::zero;
147+
return *this;
151148
}
149+
150+
normalize();
152151
return *this;
153152
}
154153

src/ripple/basics/impl/Number.cpp

+32-27
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include <type_traits>
2626
#include <utility>
2727

28-
#ifdef _MSVC_LANG
28+
#ifdef BOOST_COMP_MSVC
2929
#include <boost/multiprecision/cpp_int.hpp>
3030
using uint128_t = boost::multiprecision::uint128_t;
3131
#else // !defined(_MSVC_LANG)
@@ -130,32 +130,37 @@ int
130130
Number::Guard::round() noexcept
131131
{
132132
auto mode = Number::getround();
133-
switch (mode)
133+
134+
if (mode == towards_zero)
135+
return -1;
136+
137+
if (mode == downward)
134138
{
135-
case to_nearest:
136-
if (digits_ > 0x5000'0000'0000'0000)
137-
return 1;
138-
if (digits_ < 0x5000'0000'0000'0000)
139-
return -1;
140-
if (xbit_)
141-
return 1;
142-
return 0;
143-
case towards_zero:
144-
return -1;
145-
case downward:
146-
if (sbit_)
147-
{
148-
if (digits_ > 0 || xbit_)
149-
return 1;
150-
}
151-
return -1;
152-
case upward:
153-
if (sbit_)
154-
return -1;
139+
if (sbit_)
140+
{
155141
if (digits_ > 0 || xbit_)
156142
return 1;
143+
}
144+
return -1;
145+
}
146+
147+
if (mode == upward)
148+
{
149+
if (sbit_)
157150
return -1;
151+
if (digits_ > 0 || xbit_)
152+
return 1;
153+
return -1;
158154
}
155+
156+
// assume round to nearest if mode is not one of the predefined values
157+
if (digits_ > 0x5000'0000'0000'0000)
158+
return 1;
159+
if (digits_ < 0x5000'0000'0000'0000)
160+
return -1;
161+
if (xbit_)
162+
return 1;
163+
return 0;
159164
}
160165

161166
// Number
@@ -171,9 +176,9 @@ Number::normalize()
171176
return;
172177
}
173178
bool const negative = (mantissa_ < 0);
174-
if (negative)
175-
mantissa_ = -mantissa_;
176179
auto m = static_cast<std::make_unsigned_t<rep>>(mantissa_);
180+
if (negative)
181+
m = -m;
177182
while ((m < minMantissa) && (exponent_ > minExponent))
178183
{
179184
m *= 10;
@@ -506,8 +511,8 @@ to_string(Number const& amount)
506511

507512
assert(exponent + 43 > 0);
508513

509-
size_t const pad_prefix = 27;
510-
size_t const pad_suffix = 23;
514+
ptrdiff_t const pad_prefix = 27;
515+
ptrdiff_t const pad_suffix = 23;
511516

512517
std::string const raw_value(std::to_string(mantissa));
513518
std::string val;
@@ -517,7 +522,7 @@ to_string(Number const& amount)
517522
val.append(raw_value);
518523
val.append(pad_suffix, '0');
519524

520-
size_t const offset(exponent + 43);
525+
ptrdiff_t const offset(exponent + 43);
521526

522527
auto pre_from(val.begin());
523528
auto const pre_to(val.begin() + offset);

src/ripple/protocol/impl/STAmount.cpp

+25-13
Original file line numberDiff line numberDiff line change
@@ -725,24 +725,36 @@ STAmount::canonicalize()
725725
"Native currency amount out of range");
726726
}
727727

728-
while (mOffset < 0)
728+
if (*stNumberSwitchover && *stAmountCanonicalizeSwitchover)
729729
{
730-
mValue /= 10;
731-
++mOffset;
730+
Number num(
731+
mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{});
732+
XRPAmount xrp{num};
733+
mIsNegative = xrp.drops() < 0;
734+
mValue = mIsNegative ? -xrp.drops() : xrp.drops();
735+
mOffset = 0;
732736
}
733-
734-
while (mOffset > 0)
737+
else
735738
{
736-
if (*stAmountCanonicalizeSwitchover)
739+
while (mOffset < 0)
740+
{
741+
mValue /= 10;
742+
++mOffset;
743+
}
744+
745+
while (mOffset > 0)
737746
{
738-
// N.B. do not move the overflow check to after the
739-
// multiplication
740-
if (mValue > cMaxNativeN)
741-
Throw<std::runtime_error>(
742-
"Native currency amount out of range");
747+
if (*stAmountCanonicalizeSwitchover)
748+
{
749+
// N.B. do not move the overflow check to after the
750+
// multiplication
751+
if (mValue > cMaxNativeN)
752+
Throw<std::runtime_error>(
753+
"Native currency amount out of range");
754+
}
755+
mValue *= 10;
756+
--mOffset;
743757
}
744-
mValue *= 10;
745-
--mOffset;
746758
}
747759

748760
if (mValue > cMaxNativeN)

src/test/app/NFToken_test.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -2335,7 +2335,13 @@ class NFToken_test : public beast::unit_test::suite
23352335

23362336
// See the impact of rounding when the nft is sold for small amounts
23372337
// of drops.
2338+
for (auto NumberSwitchOver : {true})
23382339
{
2340+
if (NumberSwitchOver)
2341+
env.enableFeature(fixUniversalNumber);
2342+
else
2343+
env.disableFeature(fixUniversalNumber);
2344+
23392345
// An nft with a transfer fee of 1 basis point.
23402346
uint256 const nftID =
23412347
token::getNextID(env, alice, 0u, tfTransferable, 1);
@@ -2360,16 +2366,16 @@ class NFToken_test : public beast::unit_test::suite
23602366

23612367
// minter sells to carol. The payment is just small enough that
23622368
// alice does not get any transfer fee.
2369+
auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
23632370
STAmount carolBalance = env.balance(carol);
23642371
uint256 const minterSellOfferIndex =
23652372
keylet::nftoffer(minter, env.seq(minter)).key;
2366-
env(token::createOffer(minter, nftID, drops(99999)),
2367-
txflags(tfSellNFToken));
2373+
env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken));
23682374
env.close();
23692375
env(token::acceptSellOffer(carol, minterSellOfferIndex));
23702376
env.close();
2371-
minterBalance += drops(99999) - fee;
2372-
carolBalance -= drops(99999) + fee;
2377+
minterBalance += pmt - fee;
2378+
carolBalance -= pmt + fee;
23732379
BEAST_EXPECT(env.balance(alice) == aliceBalance);
23742380
BEAST_EXPECT(env.balance(minter) == minterBalance);
23752381
BEAST_EXPECT(env.balance(carol) == carolBalance);
@@ -2379,13 +2385,13 @@ class NFToken_test : public beast::unit_test::suite
23792385
STAmount beckyBalance = env.balance(becky);
23802386
uint256 const beckyBuyOfferIndex =
23812387
keylet::nftoffer(becky, env.seq(becky)).key;
2382-
env(token::createOffer(becky, nftID, drops(100000)),
2383-
token::owner(carol));
2388+
pmt = NumberSwitchOver ? drops(50001) : drops(100000);
2389+
env(token::createOffer(becky, nftID, pmt), token::owner(carol));
23842390
env.close();
23852391
env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
23862392
env.close();
2387-
carolBalance += drops(99999) - fee;
2388-
beckyBalance -= drops(100000) + fee;
2393+
carolBalance += pmt - drops(1) - fee;
2394+
beckyBalance -= pmt + fee;
23892395
aliceBalance += drops(1);
23902396

23912397
BEAST_EXPECT(env.balance(alice) == aliceBalance);

0 commit comments

Comments
 (0)