rippled
Loading...
Searching...
No Matches
STAmount.h
1#pragma once
2
3#include <xrpl/basics/CountedObject.h>
4#include <xrpl/basics/LocalValue.h>
5#include <xrpl/basics/Number.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/protocol/Asset.h>
8#include <xrpl/protocol/IOUAmount.h>
9#include <xrpl/protocol/Issue.h>
10#include <xrpl/protocol/MPTAmount.h>
11#include <xrpl/protocol/SField.h>
12#include <xrpl/protocol/STBase.h>
13#include <xrpl/protocol/Serializer.h>
14#include <xrpl/protocol/XRPAmount.h>
15#include <xrpl/protocol/json_get_or_throw.h>
16
17namespace xrpl {
18
19// Internal form:
20// 1: If amount is zero, then value is zero and offset is -100
21// 2: Otherwise:
22// legal offset range is -96 to +80 inclusive
23// value range is 10^15 to (10^16 - 1) inclusive
24// amount = value * [10 ^ offset]
25
26// Wire form:
27// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
28// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
29class STAmount final : public STBase, public CountedObject<STAmount>
30{
31public:
33 using exponent_type = int;
35
36private:
41
42public:
44
45 static int const cMinOffset = -96;
46 static int const cMaxOffset = 80;
47
48 // Maximum native value supported by the code
49 constexpr static std::uint64_t cMinValue = 1'000'000'000'000'000ull;
50 static_assert(isPowerOfTen(cMinValue));
51 constexpr static std::uint64_t cMaxValue = cMinValue * 10 - 1;
52 static_assert(cMaxValue == 9'999'999'999'999'999ull);
53 constexpr static std::uint64_t cMaxNative = 9'000'000'000'000'000'000ull;
54
55 // Max native value on network.
56 constexpr static std::uint64_t cMaxNativeN = 100'000'000'000'000'000ull;
57 constexpr static std::uint64_t cIssuedCurrency = 0x8'000'000'000'000'000ull;
58 constexpr static std::uint64_t cPositive = 0x4'000'000'000'000'000ull;
59 constexpr static std::uint64_t cMPToken = 0x2'000'000'000'000'000ull;
60 constexpr static std::uint64_t cValueMask = ~(cPositive | cMPToken);
61
62 static std::uint64_t const uRateOne;
63
64 //--------------------------------------------------------------------------
65 STAmount(SerialIter& sit, SField const& name);
66
67 struct unchecked
68 {
69 explicit unchecked() = default;
70 };
71
72 // Do not call canonicalize
73 template <AssetType A>
75 SField const& name,
76 A const& asset,
79 bool negative,
80 unchecked);
81
82 template <AssetType A>
84 A const& asset,
87 bool negative,
88 unchecked);
89
90 // Call canonicalize
91 template <AssetType A>
93 SField const& name,
94 A const& asset,
97 bool negative = false);
98
100
101 STAmount(SField const& name, std::uint64_t mantissa = 0, bool negative = false);
102
103 explicit STAmount(std::uint64_t mantissa = 0, bool negative = false);
104
105 explicit STAmount(SField const& name, STAmount const& amt);
106
107 template <AssetType A>
108 STAmount(A const& asset, std::uint64_t mantissa = 0, int exponent = 0, bool negative = false)
110 {
111 canonicalize();
112 }
113
114 // VFALCO Is this needed when we have the previous signature?
115 template <AssetType A>
116 STAmount(A const& asset, std::uint32_t mantissa, int exponent = 0, bool negative = false);
117
118 template <AssetType A>
119 STAmount(A const& asset, std::int64_t mantissa, int exponent = 0);
120
121 template <AssetType A>
122 STAmount(A const& asset, int mantissa, int exponent = 0);
123
124 template <AssetType A>
125 STAmount(A const& asset, Number const& number) : STAmount(fromNumber(asset, number))
126 {
127 }
128
129 // Legacy support for new-style amounts
130 STAmount(IOUAmount const& amount, Issue const& issue);
131 STAmount(XRPAmount const& amount);
132 STAmount(MPTAmount const& amount, MPTIssue const& mptIssue);
133 operator Number() const;
134
135 //--------------------------------------------------------------------------
136 //
137 // Observers
138 //
139 //--------------------------------------------------------------------------
140
141 int
142 exponent() const noexcept;
143
144 bool
145 integral() const noexcept;
146
147 bool
148 native() const noexcept;
149
150 template <ValidIssueType TIss>
151 constexpr bool
152 holds() const noexcept;
153
154 bool
155 negative() const noexcept;
156
157 std::uint64_t
158 mantissa() const noexcept;
159
160 Asset const&
161 asset() const;
162
163 template <ValidIssueType TIss>
164 constexpr TIss const&
165 get() const;
166
167 Issue const&
168 issue() const;
169
170 // These three are deprecated
171 Currency const&
172 getCurrency() const;
173
174 AccountID const&
175 getIssuer() const;
176
177 int
178 signum() const noexcept;
179
182 zeroed() const;
183
184 void
185 setJson(Json::Value&) const;
186
187 STAmount const&
188 value() const noexcept;
189
190 //--------------------------------------------------------------------------
191 //
192 // Operators
193 //
194 //--------------------------------------------------------------------------
195
196 explicit
197 operator bool() const noexcept;
198
199 STAmount&
200 operator+=(STAmount const&);
201 STAmount&
202 operator-=(STAmount const&);
203
204 STAmount& operator=(beast::Zero);
205
206 STAmount&
207 operator=(XRPAmount const& amount);
208
209 STAmount&
210 operator=(Number const&);
211
212 //--------------------------------------------------------------------------
213 //
214 // Modification
215 //
216 //--------------------------------------------------------------------------
217
218 void
219 negate();
220
221 void
222 clear();
223
224 // Zero while copying currency and issuer.
225 void
226 clear(Asset const& asset);
227
228 void
229 setIssuer(AccountID const& uIssuer);
230
232 void
233 setIssue(Asset const& asset);
234
235 //--------------------------------------------------------------------------
236 //
237 // STBase
238 //
239 //--------------------------------------------------------------------------
240
242 getSType() const override;
243
244 std::string
245 getFullText() const override;
246
247 std::string
248 getText() const override;
249
250 Json::Value getJson(JsonOptions = JsonOptions::none) const override;
251
252 void
253 add(Serializer& s) const override;
254
255 bool
256 isEquivalent(STBase const& t) const override;
257
258 bool
259 isDefault() const override;
260
262 xrp() const;
264 iou() const;
266 mpt() const;
267
268private:
269 template <AssetType A>
270 static STAmount
271 fromNumber(A const& asset, Number const& number);
272
273 static std::unique_ptr<STAmount>
274 construct(SerialIter&, SField const& name);
275
276 void
277 set(std::int64_t v);
278 void
279 canonicalize();
280
281 STBase*
282 copy(std::size_t n, void* buf) const override;
283 STBase*
284 move(std::size_t n, void* buf) override;
285
286 STAmount&
287 operator=(IOUAmount const& iou);
288
289 friend class detail::STVar;
290
291 friend STAmount
292 operator+(STAmount const& v1, STAmount const& v2);
293};
294
295template <AssetType A>
297 SField const& name,
298 A const& asset,
301 bool negative,
302 unchecked)
304{
305}
306
307template <AssetType A>
317
318template <AssetType A>
320 SField const& name,
321 A const& asset,
322 std::uint64_t mantissa,
323 int exponent,
324 bool negative)
325 : STBase(name), mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative)
326{
327 // mValue is uint64, but needs to fit in the range of int64
329 {
330 XRPL_ASSERT(
332 "xrpl::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : "
333 "maximum mantissa input");
334 }
335 else
336 {
338 throw std::overflow_error("STAmount mantissa is too large " + std::to_string(mantissa));
339 }
340 canonicalize();
341}
342
343template <AssetType A>
344STAmount::STAmount(A const& asset, std::int64_t mantissa, int exponent)
345 : mAsset(asset), mOffset(exponent)
346{
347 set(mantissa);
348 canonicalize();
349}
350
351template <AssetType A>
352STAmount::STAmount(A const& asset, std::uint32_t mantissa, int exponent, bool negative)
353 : STAmount(asset, safe_cast<std::uint64_t>(mantissa), exponent, negative)
354{
355}
356
357template <AssetType A>
358STAmount::STAmount(A const& asset, int mantissa, int exponent)
359 : STAmount(asset, safe_cast<std::int64_t>(mantissa), exponent)
360{
361}
362
363// Legacy support for new-style amounts
364inline STAmount::STAmount(IOUAmount const& amount, Issue const& issue)
365 : mAsset(issue), mOffset(amount.exponent()), mIsNegative(amount < beast::zero)
366{
367 if (mIsNegative)
368 mValue = unsafe_cast<std::uint64_t>(-amount.mantissa());
369 else
370 mValue = unsafe_cast<std::uint64_t>(amount.mantissa());
371
372 canonicalize();
373}
374
375inline STAmount::STAmount(MPTAmount const& amount, MPTIssue const& mptIssue)
376 : mAsset(mptIssue), mOffset(0), mIsNegative(amount < beast::zero)
377{
378 if (mIsNegative)
379 mValue = unsafe_cast<std::uint64_t>(-amount.value());
380 else
381 mValue = unsafe_cast<std::uint64_t>(amount.value());
382
383 canonicalize();
384}
385
386//------------------------------------------------------------------------------
387//
388// Creation
389//
390//------------------------------------------------------------------------------
391
392// VFALCO TODO The parameter type should be Quality not uint64_t
395
397amountFromString(Asset const& asset, std::string const& amount);
398
400amountFromJson(SField const& name, Json::Value const& v);
401
402bool
403amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource);
404
405// IOUAmount and XRPAmount define toSTAmount, defining this
406// trivial conversion here makes writing generic code easier
407inline STAmount const&
409{
410 return a;
411}
412
413//------------------------------------------------------------------------------
414//
415// Observers
416//
417//------------------------------------------------------------------------------
418
419inline int
420STAmount::exponent() const noexcept
421{
422 return mOffset;
423}
424
425inline bool
426STAmount::integral() const noexcept
427{
428 return mAsset.integral();
429}
430
431inline bool
432STAmount::native() const noexcept
433{
434 return mAsset.native();
435}
436
437template <ValidIssueType TIss>
438constexpr bool
439STAmount::holds() const noexcept
440{
441 return mAsset.holds<TIss>();
442}
443
444inline bool
445STAmount::negative() const noexcept
446{
447 return mIsNegative;
448}
449
450inline std::uint64_t
451STAmount::mantissa() const noexcept
452{
453 return mValue;
454}
455
456inline Asset const&
458{
459 return mAsset;
460}
461
462template <ValidIssueType TIss>
463constexpr TIss const&
465{
466 return mAsset.get<TIss>();
467}
468
469inline Issue const&
471{
472 return get<Issue>();
473}
474
475inline Currency const&
477{
478 return mAsset.get<Issue>().currency;
479}
480
481inline AccountID const&
483{
484 return mAsset.getIssuer();
485}
486
487inline int
488STAmount::signum() const noexcept
489{
490 return mValue ? (mIsNegative ? -1 : 1) : 0;
491}
492
493inline STAmount
495{
496 return STAmount(mAsset);
497}
498
499inline STAmount::
500operator bool() const noexcept
501{
502 return *this != beast::zero;
503}
504
505inline STAmount::
506operator Number() const
507{
508 if (native())
509 return xrp();
510 if (mAsset.holds<MPTIssue>())
511 return mpt();
512 return iou();
513}
514
515inline STAmount&
517{
518 clear();
519 return *this;
520}
521
522inline STAmount&
524{
525 *this = STAmount(amount);
526 return *this;
527}
528
529template <AssetType A>
530inline STAmount
531STAmount::fromNumber(A const& a, Number const& number)
532{
533 bool const negative = number.mantissa() < 0;
534 Number const working{negative ? -number : number};
535 Asset const asset{a};
536 if (asset.integral())
537 {
538 std::uint64_t const intValue = static_cast<std::int64_t>(working);
539 return STAmount{asset, intValue, 0, negative};
540 }
541
542 auto const [mantissa, exponent] = working.normalizeToRange(cMinValue, cMaxValue);
543
545}
546
547inline void
549{
550 if (*this != beast::zero)
552}
553
554inline void
556{
557 // The -100 is used to allow 0 to sort less than a small positive values
558 // which have a negative exponent.
559 mOffset = integral() ? 0 : -100;
560 mValue = 0;
561 mIsNegative = false;
562}
563
564inline void
566{
568 clear();
569}
570
571inline void
573{
574 mAsset.get<Issue>().account = uIssuer;
575}
576
577inline STAmount const&
578STAmount::value() const noexcept
579{
580 return *this;
581}
582
583inline bool
584isLegalNet(STAmount const& value)
585{
586 return !value.native() || (value.mantissa() <= STAmount::cMaxNativeN);
587}
588
589//------------------------------------------------------------------------------
590//
591// Operators
592//
593//------------------------------------------------------------------------------
594
595bool
596operator==(STAmount const& lhs, STAmount const& rhs);
597bool
598operator<(STAmount const& lhs, STAmount const& rhs);
599
600inline bool
601operator!=(STAmount const& lhs, STAmount const& rhs)
602{
603 return !(lhs == rhs);
604}
605
606inline bool
607operator>(STAmount const& lhs, STAmount const& rhs)
608{
609 return rhs < lhs;
610}
611
612inline bool
613operator<=(STAmount const& lhs, STAmount const& rhs)
614{
615 return !(rhs < lhs);
616}
617
618inline bool
619operator>=(STAmount const& lhs, STAmount const& rhs)
620{
621 return !(lhs < rhs);
622}
623
624STAmount
625operator-(STAmount const& value);
626
627//------------------------------------------------------------------------------
628//
629// Arithmetic
630//
631//------------------------------------------------------------------------------
632
633STAmount
634operator+(STAmount const& v1, STAmount const& v2);
635STAmount
636operator-(STAmount const& v1, STAmount const& v2);
637
638STAmount
639divide(STAmount const& v1, STAmount const& v2, Asset const& asset);
640
641STAmount
642multiply(STAmount const& v1, STAmount const& v2, Asset const& asset);
643
644// multiply rounding result in specified direction
645STAmount
646mulRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp);
647
648// multiply following the rounding directions more precisely.
649STAmount
650mulRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp);
651
652// divide rounding result in specified direction
653STAmount
654divRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp);
655
656// divide following the rounding directions more precisely.
657STAmount
658divRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp);
659
660// Someone is offering X for Y, what is the rate?
661// Rate: smaller is better, the taker wants the most out: in/out
662// VFALCO TODO Return a Quality object
664getRate(STAmount const& offerOut, STAmount const& offerIn);
665
678[[nodiscard]] STAmount
680 STAmount const& value,
681 std::int32_t scale,
683
693template <AssetType A>
694void
695roundToAsset(A const& asset, Number& value)
696{
697 value = STAmount{asset, value};
698}
699
711template <AssetType A>
712[[nodiscard]] Number
714 A const& asset,
715 Number const& value,
716 std::int32_t scale,
718{
719 NumberRoundModeGuard const mg(rounding);
720 STAmount const ret{asset, value};
721 if (ret.integral())
722 return ret;
723 // Note that the ctor will round integral types (XRP, MPT) via canonicalize,
724 // so no extra work is needed for those.
725 return roundToScale(ret, scale);
726}
727
728//------------------------------------------------------------------------------
729
730inline bool
731isXRP(STAmount const& amount)
732{
733 return amount.native();
734}
735
736bool
737canAdd(STAmount const& amt1, STAmount const& amt2);
738
739bool
740canSubtract(STAmount const& amt1, STAmount const& amt2);
741
742} // namespace xrpl
743
744//------------------------------------------------------------------------------
745namespace Json {
746template <>
747inline xrpl::STAmount
748getOrThrow(Json::Value const& v, xrpl::SField const& field)
749{
750 using namespace xrpl;
751 Json::StaticString const& key = field.getJsonName();
752 if (!v.isMember(key))
753 Throw<JsonMissingKeyError>(key);
754 Json::Value const& inner = v[key];
755 return amountFromJson(field, inner);
756}
757} // namespace Json
Lightweight wrapper to tag static string.
Definition json_value.h:44
Represents a JSON value.
Definition json_value.h:130
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr TIss const & get() const
AccountID const & getIssuer() const
Definition Asset.cpp:17
bool integral() const
Definition Asset.h:92
bool native() const
Definition Asset.h:79
constexpr bool holds() const
Definition Asset.h:130
Tracks the number of instances of an object.
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:25
A currency issued by an account.
Definition Issue.h:13
Number is a floating point type that can represent a wide range of values.
Definition Number.h:207
static rounding_mode getround()
Definition Number.cpp:33
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
Definition Number.h:552
static MantissaRange::mantissa_scale getMantissaScale()
Returns which mantissa scale is currently in use for normalization.
Definition Number.cpp:45
Identifies fields.
Definition SField.h:126
void set(std::int64_t v)
Definition STAmount.cpp:958
constexpr bool holds() const noexcept
Definition STAmount.h:439
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition STAmount.cpp:744
constexpr TIss const & get() const
void setIssue(Asset const &asset)
Set the Issue for this amount.
Definition STAmount.cpp:435
std::string getFullText() const override
Definition STAmount.cpp:646
static constexpr std::uint64_t cMaxValue
Definition STAmount.h:51
Issue const & issue() const
Definition STAmount.h:470
static std::uint64_t const uRateOne
Definition STAmount.h:62
static STAmount fromNumber(A const &asset, Number const &number)
Definition STAmount.h:531
void add(Serializer &s) const override
Definition STAmount.cpp:752
void setIssuer(AccountID const &uIssuer)
Definition STAmount.h:572
void negate()
Definition STAmount.h:548
void canonicalize()
Definition STAmount.cpp:827
std::uint64_t mantissa() const noexcept
Definition STAmount.h:451
int signum() const noexcept
Definition STAmount.h:488
friend class detail::STVar
Definition STAmount.h:289
bool isEquivalent(STBase const &t) const override
Definition STAmount.cpp:796
STBase * copy(std::size_t n, void *buf) const override
Definition STAmount.cpp:244
exponent_type mOffset
Definition STAmount.h:39
static constexpr std::uint64_t cValueMask
Definition STAmount.h:60
std::string getText() const override
Definition STAmount.cpp:656
bool mIsNegative
Definition STAmount.h:40
void setJson(Json::Value &) const
Definition STAmount.cpp:616
SerializedTypeID getSType() const override
Definition STAmount.cpp:640
IOUAmount iou() const
Definition STAmount.cpp:276
bool negative() const noexcept
Definition STAmount.h:445
STAmount zeroed() const
Returns a zero value with the same issuer and currency.
Definition STAmount.h:494
static int const cMaxOffset
Definition STAmount.h:46
bool isDefault() const override
Definition STAmount.cpp:803
bool integral() const noexcept
Definition STAmount.h:426
mantissa_type mValue
Definition STAmount.h:38
STAmount & operator=(beast::Zero)
Definition STAmount.h:516
Currency const & getCurrency() const
Definition STAmount.h:476
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition STAmount.cpp:238
static constexpr std::uint64_t cIssuedCurrency
Definition STAmount.h:57
bool native() const noexcept
Definition STAmount.h:432
static constexpr std::uint64_t cMinValue
Definition STAmount.h:49
Asset const & asset() const
Definition STAmount.h:457
static int const cMinOffset
Definition STAmount.h:45
static constexpr std::uint64_t cMaxNative
Definition STAmount.h:53
int exponent_type
Definition STAmount.h:33
STAmount(A const &asset, Number const &number)
Definition STAmount.h:125
MPTAmount mpt() const
Definition STAmount.cpp:291
static constexpr std::uint64_t cMPToken
Definition STAmount.h:59
int exponent() const noexcept
Definition STAmount.h:420
AccountID const & getIssuer() const
Definition STAmount.h:482
static constexpr std::uint64_t cMaxNativeN
Definition STAmount.h:56
STBase * move(std::size_t n, void *buf) override
Definition STAmount.cpp:250
XRPAmount xrp() const
Definition STAmount.cpp:261
static constexpr std::uint64_t cPositive
Definition STAmount.h:58
STAmount const & value() const noexcept
Definition STAmount.h:578
STAmount(SerialIter &sit, SField const &name)
Definition STAmount.cpp:102
STAmount(A const &asset, std::uint64_t mantissa=0, int exponent=0, bool negative=false)
Definition STAmount.h:108
A type which can be exported to a well known binary format.
Definition STBase.h:115
JSON (JavaScript Object Notation).
Definition json_errors.h:5
xrpl::AccountID getOrThrow(Json::Value const &v, xrpl::SField const &field)
Definition AccountID.h:111
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
STAmount divide(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:69
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
Definition Slice.h:199
bool operator>=(STAmount const &lhs, STAmount const &rhs)
Definition STAmount.h:619
bool isXRP(AccountID const &c)
Definition AccountID.h:70
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:594
Number operator-(Number const &x, Number const &y)
Definition Number.h:648
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition STAmount.cpp:996
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
bool isLegalNet(STAmount const &value)
Definition STAmount.h:584
STAmount amountFromString(Asset const &asset, std::string const &amount)
Definition STAmount.cpp:987
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
STAmount roundToScale(STAmount const &value, std::int32_t scale, Number::rounding_mode rounding=Number::getround())
Round an arbitrary precision Amount to the precision of an STAmount that has a given exponent.
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:557
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
Definition STAmount.cpp:492
STAmount amountFromQuality(std::uint64_t rate)
Definition STAmount.cpp:975
SerializedTypeID
Definition SField.h:90
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition STAmount.cpp:450
constexpr bool isPowerOfTen(T value)
Definition Number.h:36
bool operator!=(Buffer const &lhs, Buffer const &rhs) noexcept
Definition Buffer.h:209
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Definition STAmount.h:695
bool operator<=(STAmount const &lhs, STAmount const &rhs)
Definition STAmount.h:613
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
Definition STAmount.cpp:560
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
bool operator>(STAmount const &lhs, STAmount const &rhs)
Definition STAmount.h:607
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safe_cast(Src s) noexcept
Definition safe_cast.h:21
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
Note, should be treated as flags that can be | and &.
Definition STBase.h:17
T to_string(T... args)