mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Introduce Int128 library
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
6175024ffc
commit
06e356f15a
14 changed files with 1103 additions and 97 deletions
|
|
@ -86,8 +86,9 @@ static Value builtinTemporalInstantConstructor(ExecutionState& state, Value this
|
|||
// Let epochNanoseconds be ? ToBigInt(epochNanoseconds).
|
||||
BigInt* epochNanoseconds = argv[0].toBigInt(state);
|
||||
|
||||
auto mayInt128 = epochNanoseconds->toInt128();
|
||||
// If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
|
||||
if (!Temporal::isValidEpochNanoseconds(epochNanoseconds)) {
|
||||
if (!mayInt128 || !Temporal::isValidEpochNanoseconds(mayInt128.value())) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid epoch value");
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +97,7 @@ static Value builtinTemporalInstantConstructor(ExecutionState& state, Value this
|
|||
});
|
||||
|
||||
// Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).
|
||||
return new TemporalInstantObject(state, proto, epochNanoseconds);
|
||||
return new TemporalInstantObject(state, proto, mayInt128.value());
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_INSTANT(NAME, BUILT_IN_METHOD) \
|
||||
|
|
@ -114,7 +115,8 @@ static Value builtinTemporalInstantGetEpochMilliseconds(ExecutionState& state, V
|
|||
static Value builtinTemporalInstantGetEpochNanoseconds(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||||
{
|
||||
RESOLVE_THIS_BINDING_TO_INSTANT(instant, GetEpochNanoseconds);
|
||||
return instant->epochNanoseconds();
|
||||
auto s = std::to_string(instant->epochNanoseconds());
|
||||
return BigInt::parseString(s.data(), s.length()).value();
|
||||
}
|
||||
|
||||
#define RESOLVE_THIS_BINDING_TO_PLAINDATE(NAME, BUILT_IN_METHOD) \
|
||||
|
|
|
|||
|
|
@ -404,6 +404,54 @@ static bool isValidDurationWork(double v, int& sign)
|
|||
return true;
|
||||
}
|
||||
|
||||
static BigIntData totalNanoseconds(const DurationRecord& record)
|
||||
{
|
||||
BigIntData resultNs;
|
||||
constexpr int64_t nanoMultiplier = 1000000000ULL;
|
||||
constexpr int64_t milliMultiplier = 1000000ULL;
|
||||
constexpr int64_t microMultiplier = 1000ULL;
|
||||
|
||||
{
|
||||
BigIntData s(record.days());
|
||||
s = s.multiply(86400);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.hours());
|
||||
s = s.multiply(3600);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.minutes());
|
||||
s = s.multiply(60);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.seconds());
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.milliseconds());
|
||||
s = s.multiply(milliMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.microseconds());
|
||||
s = s.multiply(microMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
{
|
||||
BigIntData s(record.nanoseconds());
|
||||
resultNs = resultNs.addition(s);
|
||||
}
|
||||
|
||||
return resultNs;
|
||||
}
|
||||
|
||||
// https://tc39.es/ecma402/#sec-isvalidduration
|
||||
static bool isValidDuration(const DurationRecord& record)
|
||||
{
|
||||
|
|
@ -431,15 +479,14 @@ static bool isValidDuration(const DurationRecord& record)
|
|||
|
||||
// Let normalizedSeconds be days × 86,400 + hours × 3600 + minutes × 60 + seconds + ℝ(𝔽(milliseconds)) × 10**-3 + ℝ(𝔽(microseconds)) × 10**-6 + ℝ(𝔽(nanoseconds)) × 10**-9.
|
||||
// NOTE: The above step cannot be implemented directly using floating-point arithmetic. Multiplying by 10**-3, 10**-6, and 10**-9 respectively may be imprecise when milliseconds, microseconds, or nanoseconds is an unsafe integer. This multiplication can be implemented in C++ with an implementation of std::remquo() with sufficient bits in the quotient. String manipulation will also give an exact result, since the multiplication is by a power of 10.
|
||||
BigIntData normalizedNanoSeconds = record.totalNanoseconds(DurationRecord::Type::Years);
|
||||
BigIntData normalizedNanoSeconds = totalNanoseconds(record);
|
||||
// If abs(normalizedSeconds) ≥ 2**53, return false.
|
||||
BigIntData limit(int64_t(1ULL << 53));
|
||||
limit = limit.multiply(1000000000ULL);
|
||||
if (normalizedNanoSeconds.greaterThanEqual(limit)) {
|
||||
return false;
|
||||
}
|
||||
limit = BigIntData(int64_t(1ULL << 53));
|
||||
limit = limit.multiply(-1000000000ULL);
|
||||
limit = limit.multiply(-1);
|
||||
if (normalizedNanoSeconds.lessThanEqual(limit)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -552,7 +599,7 @@ inline double purifyNaN(double value)
|
|||
return value;
|
||||
}
|
||||
|
||||
static std::string buildDecimalFormat(DurationRecord::Type unit, BigIntData ns)
|
||||
static std::string buildDecimalFormat(DurationRecord::Type unit, Int128 ns)
|
||||
{
|
||||
ASSERT(unit == DurationRecord::Type::Seconds || unit == DurationRecord::Type::Milliseconds || unit == DurationRecord::Type::Microseconds);
|
||||
|
||||
|
|
@ -570,19 +617,19 @@ static std::string buildDecimalFormat(DurationRecord::Type unit, BigIntData ns)
|
|||
exponent = 1000;
|
||||
}
|
||||
|
||||
BigIntData integerPart = ns;
|
||||
integerPart = integerPart.division(exponent);
|
||||
Int128 integerPart = ns;
|
||||
integerPart /= exponent;
|
||||
|
||||
BigIntData fractionalPart(ns);
|
||||
fractionalPart = fractionalPart.remainder(exponent);
|
||||
Int128 fractionalPart = ns;
|
||||
fractionalPart %= exponent;
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
auto integerPartString = integerPart.toNonGCStdString();
|
||||
auto integerPartString = std::to_string(integerPart);
|
||||
builder.appendString(integerPartString.data(), integerPartString.size());
|
||||
builder.appendChar('.');
|
||||
|
||||
auto fractionalString = fractionalPart.toNonGCStdString();
|
||||
auto fractionalString = std::to_string(fractionalPart);
|
||||
if (fractionalString.size() && fractionalString[0] == '-') {
|
||||
fractionalString.erase(fractionalString.begin());
|
||||
}
|
||||
|
|
@ -648,7 +695,7 @@ std::vector<IntlDurationFormatObject::Element> IntlDurationFormatObject::collect
|
|||
DurationRecord::Type unit = static_cast<DurationRecord::Type>(index);
|
||||
auto unitData = durationFormat->data(index);
|
||||
double value = duration[unit];
|
||||
Optional<BigIntData> totalNanosecondsValue;
|
||||
Optional<Int128> totalNanosecondsValue;
|
||||
|
||||
UTF16StringDataNonGCStd skeletonBuilder;
|
||||
|
||||
|
|
|
|||
|
|
@ -765,4 +765,39 @@ bool BigInt::isNegative() const
|
|||
return m_bf.sign;
|
||||
}
|
||||
|
||||
Optional<Int128> BigInt::toInt128()
|
||||
{
|
||||
auto s = std::to_string(std::numeric_limits<Int128>::min());
|
||||
BigIntData test(s.data(), s.length());
|
||||
if (lessThan(test)) {
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
s = std::to_string(std::numeric_limits<Int128>::max());
|
||||
BigIntData test2(s.data(), s.length());
|
||||
if (greaterThan(test2)) {
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
BigIntData big(this);
|
||||
s = big.toNonGCStdString();
|
||||
|
||||
bool sign = s.length() && s[0] == '-';
|
||||
if (sign) {
|
||||
s.erase(s.begin());
|
||||
}
|
||||
|
||||
Int128 ret = 0;
|
||||
for (char c : s) {
|
||||
ret *= 10;
|
||||
ret += c - '0';
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
ret *= -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define __EscargotBigInt__
|
||||
|
||||
#include "runtime/PointerValue.h"
|
||||
#include "util/Int128.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
|
|
@ -127,6 +128,8 @@ public:
|
|||
BigInt* negativeValue(ExecutionState& state);
|
||||
BigInt* negativeValue();
|
||||
|
||||
Optional<Int128> toInt128();
|
||||
|
||||
bool isZero() const;
|
||||
bool isNaN() const;
|
||||
bool isInfinity() const;
|
||||
|
|
|
|||
|
|
@ -23,17 +23,17 @@
|
|||
|
||||
namespace Escargot {
|
||||
|
||||
TemporalInstantObject::TemporalInstantObject(ExecutionState& state, Object* proto, BigInt* n)
|
||||
TemporalInstantObject::TemporalInstantObject(ExecutionState& state, Object* proto, Int128 n)
|
||||
: DerivedObject(state, proto)
|
||||
, m_nanoseconds(n)
|
||||
, m_nanoseconds(new(PointerFreeGC) Int128(n))
|
||||
{
|
||||
}
|
||||
|
||||
Value TemporalInstantObject::epochMilliseconds() const
|
||||
{
|
||||
BigIntData s(m_nanoseconds);
|
||||
s = s.division(1000000);
|
||||
return Value(s.toInt64());
|
||||
Int128 s = *m_nanoseconds;
|
||||
s /= 1000000;
|
||||
return Value(static_cast<int64_t>(s));
|
||||
}
|
||||
|
||||
TemporalInstantObject* TemporalInstantObject::addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Escargot {
|
|||
|
||||
class TemporalInstantObject : public DerivedObject {
|
||||
public:
|
||||
TemporalInstantObject(ExecutionState& state, Object* proto, BigInt* nanoseconds);
|
||||
TemporalInstantObject(ExecutionState& state, Object* proto, Int128 nanoseconds);
|
||||
|
||||
virtual bool isTemporalInstantObject() const override
|
||||
{
|
||||
|
|
@ -35,9 +35,9 @@ public:
|
|||
}
|
||||
|
||||
Value epochMilliseconds() const;
|
||||
BigInt* epochNanoseconds() const
|
||||
Int128 epochNanoseconds() const
|
||||
{
|
||||
return m_nanoseconds;
|
||||
return *m_nanoseconds;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -48,7 +48,7 @@ private:
|
|||
};
|
||||
TemporalInstantObject* addDurationToInstant(AddDurationOperation operation, const Value& temporalDurationLike);
|
||||
|
||||
BigInt* m_nanoseconds; // [[EpochNanoseconds]]
|
||||
Int128* m_nanoseconds; // [[EpochNanoseconds]]
|
||||
};
|
||||
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "runtime/BigInt.h"
|
||||
#include "runtime/DateObject.h"
|
||||
#include "runtime/TemporalDurationObject.h"
|
||||
#include "runtime/TemporalInstantObject.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
|
|
@ -338,46 +339,16 @@ bool Temporal::ISODateTimeWithinLimits(ExecutionState& state, const ISODateTime&
|
|||
// Z(R(ms) × 10**6 + isoDateTime.[[Time]].[[Microsecond]] × 10**3 + isoDateTime.[[Time]].[[Nanosecond]]).
|
||||
int64_t ns = static_cast<int64_t>(ms) * 1000000 + dateTime.time.microsecond * 1000 + dateTime.time.nanosecond;
|
||||
|
||||
BigIntData nsData(ns);
|
||||
|
||||
if (nsData.lessThanEqual(Temporal::nsMinConstant())) {
|
||||
if (ns <= Temporal::nsMinConstant()) {
|
||||
return false;
|
||||
}
|
||||
if (nsData.greaterThanEqual(Temporal::nsMaxConstant())) {
|
||||
if (ns >= Temporal::nsMaxConstant()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const BigIntData& Temporal::nsMaxInstant()
|
||||
{
|
||||
const char* str = "8640000000000000000000";
|
||||
static MAY_THREAD_LOCAL BigIntData constant(str, strlen(str), 10);
|
||||
return constant;
|
||||
}
|
||||
|
||||
const BigIntData& Temporal::nsMinInstant()
|
||||
{
|
||||
const char* str = "-8640000000000000000000";
|
||||
static MAY_THREAD_LOCAL BigIntData constant(str, strlen(str), 10);
|
||||
return constant;
|
||||
}
|
||||
|
||||
const BigIntData& Temporal::nsMaxConstant()
|
||||
{
|
||||
const char* str = "8640000086400000000000";
|
||||
static MAY_THREAD_LOCAL BigIntData constant(str, strlen(str), 10);
|
||||
return constant;
|
||||
}
|
||||
|
||||
const BigIntData& Temporal::nsMinConstant()
|
||||
{
|
||||
const char* str = "-8640000086400000000000";
|
||||
static MAY_THREAD_LOCAL BigIntData constant(str, strlen(str), 10);
|
||||
return constant;
|
||||
}
|
||||
|
||||
int64_t Temporal::nsPerDay()
|
||||
{
|
||||
return 86400000000000;
|
||||
|
|
@ -417,25 +388,24 @@ Value Temporal::toTemporalDate(ExecutionState& state, Value item, Value options)
|
|||
return Value();
|
||||
}
|
||||
|
||||
BigInt* Temporal::systemUTCEpochNanoseconds()
|
||||
Int128 Temporal::systemUTCEpochNanoseconds()
|
||||
{
|
||||
std::chrono::system_clock::duration d = std::chrono::system_clock::now().time_since_epoch();
|
||||
|
||||
auto microSecondsSinceEpoch = std::chrono::duration_cast<std::chrono::microseconds>(d).count();
|
||||
unsigned long nano = std::chrono::duration_cast<std::chrono::nanoseconds>(d - std::chrono::duration_cast<std::chrono::microseconds>(d)).count();
|
||||
|
||||
BigIntData ret = BigIntData(microSecondsSinceEpoch);
|
||||
ret = ret.multiply(1000);
|
||||
ret = ret.addition(nano);
|
||||
Int128 ret = Int128(microSecondsSinceEpoch);
|
||||
ret *= 1000;
|
||||
ret += nano;
|
||||
|
||||
return new BigInt(std::move(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Temporal::isValidEpochNanoseconds(BigInt* s)
|
||||
bool Temporal::isValidEpochNanoseconds(Int128 epochNanoseconds)
|
||||
{
|
||||
BigIntData epochNanoseconds(s);
|
||||
// If ℝ(epochNanoseconds) < nsMinInstant or ℝ(epochNanoseconds) > nsMaxInstant, then
|
||||
if (epochNanoseconds.lessThan(Temporal::nsMinInstant()) || epochNanoseconds.greaterThan(Temporal::nsMaxInstant())) {
|
||||
if (epochNanoseconds < Temporal::nsMinInstant() || epochNanoseconds > Temporal::nsMaxInstant()) {
|
||||
// Return false.
|
||||
return false;
|
||||
}
|
||||
|
|
@ -452,7 +422,7 @@ TemporalDurationObject* Temporal::toTemporalDuration(ExecutionState& state, cons
|
|||
return new TemporalDurationObject(state, item.asPointerValue()->asTemporalDurationObject()->duration());
|
||||
}
|
||||
|
||||
constexpr auto msg = "The value you gave for toTemporalDuration is invalid";
|
||||
constexpr auto msg = "The value you gave for ToTemporalDuration is invalid";
|
||||
if (!item.isObject()) {
|
||||
// If item is not an Object, then
|
||||
// If item is not a String, throw a TypeError exception.
|
||||
|
|
@ -493,7 +463,41 @@ TemporalDurationObject* Temporal::toTemporalDuration(ExecutionState& state, cons
|
|||
// Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
|
||||
return new TemporalDurationObject(state, duration);
|
||||
}
|
||||
/*
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-totemporalinstant
|
||||
TemporalInstantObject* Temporal::toTemporalInstant(ExecutionState& state, Value item)
|
||||
{
|
||||
// If item is an Object, then
|
||||
if (item.isObject()) {
|
||||
// If item has an [[InitializedTemporalInstant]] or [[InitializedTemporalZonedDateTime]] internal slot, then
|
||||
// TODO [[InitializedTemporalZonedDateTime]]
|
||||
if (item.asObject()->isTemporalInstantObject()) {
|
||||
// Return ! CreateTemporalInstant(item.[[EpochNanoseconds]]).
|
||||
return new TemporalInstantObject(state, state.context()->globalObject()->temporalInstantPrototype(),
|
||||
item.asObject()->asTemporalInstantObject()->epochNanoseconds());
|
||||
}
|
||||
// NOTE: This use of ToPrimitive allows Instant-like objects to be converted.
|
||||
// Set item to ? ToPrimitive(item, string).
|
||||
item = item.toPrimitive(state, Value::PrimitiveTypeHint::PreferString);
|
||||
}
|
||||
constexpr auto msg = "The value you gave for ToTemporalInstant is invalid";
|
||||
if (!item.isString()) {
|
||||
// If item is not a String, throw a TypeError exception.
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, msg);
|
||||
}
|
||||
|
||||
// Let parsed be ? ParseISODateTime(item, « TemporalInstantString »).
|
||||
// Assert: Either parsed.[[TimeZone]].[[OffsetString]] is not empty or parsed.[[TimeZone]].[[Z]] is true, but not both.
|
||||
// If parsed.[[TimeZone]].[[Z]] is true, let offsetNanoseconds be 0; otherwise, let offsetNanoseconds be ! ParseDateTimeUTCOffset(parsed.[[TimeZone]].[[OffsetString]]).
|
||||
// If parsed.[[Time]] is start-of-day, let time be MidnightTimeRecord(); else let time be parsed.[[Time]].
|
||||
// Let balanced be BalanceISODateTime(parsed.[[Year]], parsed.[[Month]], parsed.[[Day]], time.[[Hour]], time.[[Minute]], time.[[Second]], time.[[Millisecond]], time.[[Microsecond]], time.[[Nanosecond]] - offsetNanoseconds).
|
||||
// Perform ? CheckISODaysRange(balanced.[[ISODate]]).
|
||||
// Let epochNanoseconds be GetUTCEpochNanoseconds(balanced).
|
||||
// If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
|
||||
// Return ! CreateTemporalInstant(epochNanoseconds).
|
||||
return nullptr;
|
||||
}
|
||||
*/
|
||||
TemporalObject::TemporalObject(ExecutionState& state)
|
||||
: TemporalObject(state, state.context()->globalObject()->objectPrototype())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "runtime/GlobalObject.h"
|
||||
#include "runtime/DateObject.h"
|
||||
#include "intl/Intl.h"
|
||||
#include "util/Int128.h"
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
|
|
@ -210,22 +211,45 @@ public:
|
|||
static bool ISODateWithinLimits(ExecutionState& state, const ISODate& date);
|
||||
static bool ISODateTimeWithinLimits(ExecutionState& state, const ISODateTime& dateTime);
|
||||
|
||||
static const BigIntData& nsMaxInstant();
|
||||
static const BigIntData& nsMinInstant();
|
||||
static const BigIntData& nsMaxConstant();
|
||||
static const BigIntData& nsMinConstant();
|
||||
static Int128 nsMaxInstant()
|
||||
{
|
||||
Int128 ret = 864000000;
|
||||
ret *= 10000000000000;
|
||||
return ret;
|
||||
}
|
||||
static Int128 nsMinInstant()
|
||||
{
|
||||
Int128 ret = -864000000;
|
||||
ret *= 10000000000000;
|
||||
return ret;
|
||||
}
|
||||
static Int128 nsMaxConstant()
|
||||
{
|
||||
Int128 ret = 86400000864;
|
||||
ret *= 100000000000;
|
||||
return ret;
|
||||
}
|
||||
static Int128 nsMinConstant()
|
||||
{
|
||||
Int128 ret = -86400000864;
|
||||
ret *= 100000000000;
|
||||
return ret;
|
||||
}
|
||||
static int64_t nsPerDay();
|
||||
|
||||
static Value createTemporalDate(ExecutionState& state, const ISODate& isoDate, String* calendar, Optional<Object*> newTarget);
|
||||
static Value toTemporalDate(ExecutionState& state, Value item, Value options = Value());
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-systemutcepochnanoseconds
|
||||
static BigInt* systemUTCEpochNanoseconds();
|
||||
static Int128 systemUTCEpochNanoseconds();
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-isvalidepochnanoseconds
|
||||
static bool isValidEpochNanoseconds(BigInt* s);
|
||||
static bool isValidEpochNanoseconds(Int128 s);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-totemporalduration
|
||||
static TemporalDurationObject* toTemporalDuration(ExecutionState& state, const Value& item);
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-totemporalinstant
|
||||
static TemporalInstantObject* toTemporalInstant(ExecutionState& state, Value item);
|
||||
};
|
||||
|
||||
class TemporalObject : public DerivedObject {
|
||||
|
|
|
|||
|
|
@ -274,50 +274,54 @@ String* Duration::typeName(ExecutionState& state, Type t)
|
|||
return String::emptyString();
|
||||
}
|
||||
|
||||
BigIntData Duration::totalNanoseconds(Duration::Type unit) const
|
||||
Int128 Duration::totalNanoseconds(Duration::Type unit) const
|
||||
{
|
||||
BigIntData resultNs;
|
||||
ASSERT(unit != Duration::Type::Years);
|
||||
ASSERT(unit != Duration::Type::Months);
|
||||
ASSERT(unit != Duration::Type::Weeks);
|
||||
|
||||
Int128 resultNs = 0;
|
||||
|
||||
constexpr int64_t nanoMultiplier = 1000000000ULL;
|
||||
constexpr int64_t milliMultiplier = 1000000ULL;
|
||||
constexpr int64_t microMultiplier = 1000ULL;
|
||||
|
||||
if (unit <= Duration::Type::Days) {
|
||||
BigIntData s(days());
|
||||
s = s.multiply(86400);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(days());
|
||||
s *= 86400;
|
||||
s *= nanoMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Hours) {
|
||||
BigIntData s(hours());
|
||||
s = s.multiply(3600);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(hours());
|
||||
s *= 3600;
|
||||
s *= nanoMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Minutes) {
|
||||
BigIntData s(minutes());
|
||||
s = s.multiply(60);
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(minutes());
|
||||
s *= 60;
|
||||
s *= nanoMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Seconds) {
|
||||
BigIntData s(seconds());
|
||||
s = s.multiply(nanoMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(seconds());
|
||||
s *= nanoMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Milliseconds) {
|
||||
BigIntData s(milliseconds());
|
||||
s = s.multiply(milliMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(milliseconds());
|
||||
s *= milliMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Microseconds) {
|
||||
BigIntData s(microseconds());
|
||||
s = s.multiply(microMultiplier);
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(microseconds());
|
||||
s *= microMultiplier;
|
||||
resultNs += s;
|
||||
}
|
||||
if (unit <= Duration::Type::Nanoseconds) {
|
||||
BigIntData s(nanoseconds());
|
||||
resultNs = resultNs.addition(s);
|
||||
Int128 s(nanoseconds());
|
||||
resultNs += s;
|
||||
}
|
||||
|
||||
return resultNs;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "runtime/BigInt.h"
|
||||
#include "runtime/String.h"
|
||||
#include "util/Int128.h"
|
||||
|
||||
namespace Escargot {
|
||||
class ExecutionState;
|
||||
|
|
@ -64,7 +65,7 @@ public:
|
|||
}
|
||||
|
||||
static String* typeName(ExecutionState& state, Type t);
|
||||
BigIntData totalNanoseconds(Duration::Type type) const;
|
||||
Int128 totalNanoseconds(Duration::Type type) const;
|
||||
|
||||
double operator[](size_t idx) const
|
||||
{
|
||||
|
|
|
|||
43
src/util/Int128.h
Normal file
43
src/util/Int128.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2025-present Samsung Electronics Co., Ltd
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA
|
||||
*/
|
||||
#ifndef __EscargotInt128__
|
||||
#define __EscargotInt128__
|
||||
|
||||
#define INT128_SPECIALIZATION
|
||||
#include "int128.h"
|
||||
#undef INT128_SPECIALIZATION
|
||||
|
||||
namespace Escargot {
|
||||
|
||||
using Int128 = large_int::int128_t;
|
||||
|
||||
} // namespace Escargot
|
||||
|
||||
namespace std {
|
||||
|
||||
inline string to_string(const Escargot::Int128& val)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << val;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
21
third_party/int128/LICENSE
vendored
Normal file
21
third_party/int128/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 zhanhb
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
13
third_party/int128/README.md
vendored
Normal file
13
third_party/int128/README.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
https://github.com/zhanhb/int128/
|
||||
|
||||
# int128
|
||||
int128 with divide/stream support, require C++ 11
|
||||
|
||||
```cpp
|
||||
uint128_t a = 2'000'000'000'000'000'000'000_U128; // single quotes requires C++ 14
|
||||
int128_t b = 1'000'000'000'000'000'000'000_L128;
|
||||
cout << setw(40) << setfill('0') << hex << uppercase << a / b << endl;
|
||||
setlocale(LC_ALL, "zh_CN.UTF-8");
|
||||
cout.imbue(locale());
|
||||
cout << a / b << endl;
|
||||
```
|
||||
809
third_party/int128/int128.h
vendored
Normal file
809
third_party/int128/int128.h
vendored
Normal file
|
|
@ -0,0 +1,809 @@
|
|||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef __BYTE_ORDER__
|
||||
#error __BYTE_ORDER__ not defined
|
||||
#endif
|
||||
|
||||
namespace large_int {
|
||||
template<class, class>
|
||||
class int128_base;
|
||||
|
||||
typedef int128_base<int64_t, uint64_t> int128_t;
|
||||
typedef int128_base<uint64_t, uint64_t> uint128_t;
|
||||
|
||||
template<class _Tp>
|
||||
struct half_mask : std::integral_constant<_Tp, (_Tp(1) << (4 * sizeof(_Tp))) - _Tp(1)> {
|
||||
};
|
||||
|
||||
template<bool= true>
|
||||
struct detail_delegate;
|
||||
|
||||
constexpr bool operator<(int128_t, int128_t);
|
||||
|
||||
constexpr bool operator<(uint128_t, uint128_t);
|
||||
|
||||
constexpr uint128_t operator>>(uint128_t, int);
|
||||
|
||||
constexpr int128_t operator>>(int128_t, int);
|
||||
|
||||
constexpr int128_t operator*(int128_t, int128_t);
|
||||
|
||||
constexpr uint128_t operator*(uint128_t, uint128_t);
|
||||
|
||||
constexpr uint128_t operator<<(uint128_t, int);
|
||||
|
||||
constexpr int128_t operator<<(int128_t, int);
|
||||
|
||||
inline uint128_t operator/(uint128_t, uint128_t);
|
||||
|
||||
inline int128_t operator/(int128_t, int128_t);
|
||||
|
||||
inline uint128_t operator%(uint128_t, uint128_t);
|
||||
|
||||
inline int128_t operator%(int128_t, int128_t);
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
class alignas(sizeof(_Hi) * 2) int128_base final {
|
||||
static_assert(sizeof(_Hi) == sizeof(_Low), "low type, high type should have same size");
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
_Low low_{};
|
||||
_Hi high_{};
|
||||
|
||||
constexpr int128_base(_Hi high, _Low low) : low_(low), high_(high) {}
|
||||
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
_Hi high_{};
|
||||
_Low low_{};
|
||||
|
||||
constexpr int128_base(_Hi high, _Low low) : high_(high), low_(low) {}
|
||||
|
||||
#else
|
||||
#error endian not support
|
||||
#endif
|
||||
|
||||
struct integral_tag {
|
||||
};
|
||||
struct signed_integral_tag : integral_tag {
|
||||
};
|
||||
struct unsigned_integral_tag : integral_tag {
|
||||
};
|
||||
struct float_tag {
|
||||
};
|
||||
template<size_t>
|
||||
struct size_constant {
|
||||
};
|
||||
|
||||
private:
|
||||
template<class _Tp>
|
||||
constexpr int128_base(_Tp value_, signed_integral_tag, size_constant<8>) :
|
||||
int128_base(-(value_ < 0), value_) {}
|
||||
|
||||
template<class _Tp>
|
||||
constexpr int128_base(_Tp value_, unsigned_integral_tag, size_constant<8>) : int128_base(0, _Low(value_)) {}
|
||||
|
||||
template<class _Tp>
|
||||
constexpr int128_base(_Tp value_, integral_tag, size_constant<16>) : // NOLINT explicit
|
||||
int128_base(_Hi(value_ >> 64U), _Low(value_)) {} // NOLINT signed shift
|
||||
|
||||
public:
|
||||
|
||||
constexpr int128_base() noexcept = default;
|
||||
|
||||
constexpr int128_base(const int128_base &) noexcept = default;
|
||||
|
||||
constexpr int128_base(int128_base &&) noexcept = default;
|
||||
|
||||
int128_base &operator=(const int128_base &) noexcept = default;
|
||||
|
||||
int128_base &operator=(int128_base &&) noexcept = default;
|
||||
|
||||
template<class _Tp>
|
||||
constexpr explicit int128_base(int128_base<_Tp, _Low> val_) : int128_base(val_.high_, val_.low_) {}
|
||||
|
||||
template<class _Tp>
|
||||
constexpr int128_base(_Tp val_, float_tag) :
|
||||
int128_base(_Hi(std::ldexp(val_, -64)) - (val_ < 0), _Low(val_)) {}
|
||||
|
||||
constexpr explicit int128_base(float val_) : int128_base(val_, float_tag()) {}
|
||||
|
||||
constexpr explicit int128_base(double val_) : int128_base(val_, float_tag()) {}
|
||||
|
||||
constexpr explicit int128_base(long double val_) : int128_base(val_, float_tag()) {}
|
||||
|
||||
constexpr int128_base(long long val_) : // NOLINT explicit
|
||||
int128_base(val_, signed_integral_tag(), size_constant<sizeof(val_)>()) {}
|
||||
|
||||
constexpr int128_base(long val_) : int128_base(static_cast<long long>(val_)) {} // NOLINT explicit
|
||||
|
||||
constexpr int128_base(int val_) : int128_base(long(val_)) {} // NOLINT explicit
|
||||
|
||||
constexpr int128_base(unsigned long long val_) : // NOLINT explicit
|
||||
int128_base(val_, unsigned_integral_tag(), size_constant<sizeof(val_)>()) {}
|
||||
|
||||
constexpr int128_base(unsigned long val_) : // NOLINT explicit
|
||||
int128_base(static_cast<unsigned long long>(val_)) {}
|
||||
|
||||
constexpr int128_base(unsigned val_) : int128_base(static_cast<unsigned long>(val_)) {} // NOLINT explicit
|
||||
|
||||
constexpr explicit operator bool() const { return high_ || low_; }
|
||||
|
||||
constexpr explicit operator char() const { return char(low_); }
|
||||
|
||||
constexpr explicit operator signed char() const { return static_cast<signed char>(low_); }
|
||||
|
||||
constexpr explicit operator unsigned char() const { return static_cast<unsigned char>(low_); }
|
||||
|
||||
constexpr explicit operator short() const { return short(low_); }
|
||||
|
||||
constexpr explicit operator unsigned short() const { return static_cast<unsigned short>(low_); }
|
||||
|
||||
constexpr explicit operator int() const { return int(low_); }
|
||||
|
||||
constexpr explicit operator unsigned() const { return unsigned(low_); }
|
||||
|
||||
constexpr explicit operator long() const { return long(low_); }
|
||||
|
||||
constexpr explicit operator unsigned long() const { return static_cast<unsigned long>(low_); }
|
||||
|
||||
constexpr explicit operator long long() const { return static_cast<long long>(low_); }
|
||||
|
||||
constexpr explicit operator unsigned long long() const { return static_cast<unsigned long long>(low_); }
|
||||
|
||||
constexpr explicit operator wchar_t() const { return wchar_t(low_); }
|
||||
|
||||
constexpr explicit operator char16_t() const { return char16_t(low_); }
|
||||
|
||||
constexpr explicit operator char32_t() const { return char32_t(low_); }
|
||||
|
||||
#if __SIZEOF_INT128__ == 16
|
||||
|
||||
constexpr explicit int128_base(__int128 val_) :
|
||||
int128_base(val_, signed_integral_tag(), size_constant<sizeof(val_)>()) {}
|
||||
|
||||
constexpr explicit int128_base(unsigned __int128 val_) :
|
||||
int128_base(val_, unsigned_integral_tag(), size_constant<sizeof(val_)>()) {}
|
||||
|
||||
constexpr explicit operator unsigned __int128() const {
|
||||
return static_cast<unsigned __int128>(high_) << 64U | static_cast<unsigned __int128>(low_);
|
||||
}
|
||||
|
||||
constexpr explicit operator __int128() const {
|
||||
return static_cast<__int128>(static_cast<unsigned __int128>(*this));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
template<class _Tp>
|
||||
constexpr _Tp cast_to_float() const;
|
||||
|
||||
public:
|
||||
constexpr explicit operator float() const { return cast_to_float<float>(); }
|
||||
|
||||
constexpr explicit operator double() const { return cast_to_float<double>(); }
|
||||
|
||||
constexpr explicit operator long double() const { return cast_to_float<long double>(); }
|
||||
|
||||
constexpr int128_base operator+() const { return *this; }
|
||||
|
||||
constexpr int128_base operator-() const { return int128_base(-high_ - (low_ != 0), -low_); }
|
||||
|
||||
constexpr int128_base operator~() const { return int128_base(~high_, ~low_); }
|
||||
|
||||
constexpr bool operator!() const { return !high_ && !low_; }
|
||||
|
||||
// avoid self plus on rvalue
|
||||
int128_base &operator++() &{ return *this = *this + int128_base(1); }
|
||||
|
||||
int128_base &operator--() &{ return *this = *this - int128_base(1); }
|
||||
|
||||
int128_base operator++(int) &{ // NOLINT returns non constant
|
||||
int128_base tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int128_base operator--(int) &{ // NOLINT returns non constant
|
||||
int128_base tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend constexpr int128_base operator+(int128_base lhs_, int128_base rhs_) {
|
||||
// no worry for unsigned type, won't be optimized if overflow
|
||||
return {_Hi(lhs_.high_ + rhs_.high_ + (lhs_.low_ + rhs_.low_ < lhs_.low_)), lhs_.low_ + rhs_.low_};
|
||||
}
|
||||
|
||||
friend constexpr int128_base operator-(int128_base lhs_, int128_base rhs_) {
|
||||
return {_Hi(lhs_.high_ - rhs_.high_ - (lhs_.low_ < rhs_.low_)), lhs_.low_ - rhs_.low_};
|
||||
}
|
||||
|
||||
friend constexpr int128_base operator&(int128_base lhs_, int128_base rhs_) {
|
||||
return {lhs_.high_ & rhs_.high_, lhs_.low_ & rhs_.low_};
|
||||
}
|
||||
|
||||
friend constexpr int128_base operator|(int128_base lhs_, int128_base rhs_) {
|
||||
return {lhs_.high_ | rhs_.high_, lhs_.low_ | rhs_.low_};
|
||||
}
|
||||
|
||||
friend constexpr int128_base operator^(int128_base lhs_, int128_base rhs_) {
|
||||
return {lhs_.high_ ^ rhs_.high_, lhs_.low_ ^ rhs_.low_};
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(int128_base lhs_, int128_base rhs_) {
|
||||
return lhs_.high_ == rhs_.high_ && lhs_.low_ == rhs_.low_;
|
||||
}
|
||||
|
||||
friend constexpr bool operator>(int128_base lhs_, int128_base rhs_) { return rhs_ < lhs_; }
|
||||
|
||||
friend constexpr bool operator>=(int128_base lhs_, int128_base rhs_) { return !(lhs_ < rhs_); }
|
||||
|
||||
friend constexpr bool operator<=(int128_base lhs_, int128_base rhs_) { return !(rhs_ < lhs_); }
|
||||
|
||||
friend constexpr bool operator!=(int128_base lhs_, int128_base rhs_) { return !(lhs_ == rhs_); }
|
||||
|
||||
friend constexpr int128_base operator<<(int128_base lhs_, int128_base rhs_) { return lhs_ << (int) rhs_.low_; }
|
||||
|
||||
friend constexpr int128_base operator>>(int128_base lhs_, int128_base rhs_) { return lhs_ >> (int) rhs_.low_; }
|
||||
|
||||
int128_base &operator+=(int128_base rhs_) &{ return *this = *this + rhs_; }
|
||||
|
||||
int128_base &operator-=(int128_base rhs_) &{ return *this = *this - rhs_; }
|
||||
|
||||
int128_base &operator*=(int128_base rhs_) &{ return *this = *this * rhs_; }
|
||||
|
||||
int128_base &operator/=(int128_base rhs_) &{ return *this = *this / rhs_; }
|
||||
|
||||
int128_base &operator%=(int128_base rhs_) &{ return *this = *this % rhs_; }
|
||||
|
||||
int128_base &operator<<=(int128_base rhs_) &{ return *this = *this << rhs_; }
|
||||
|
||||
int128_base &operator>>=(int128_base rhs_) &{ return *this = *this >> rhs_; }
|
||||
|
||||
int128_base &operator<<=(int rhs_) &{ return *this = *this << rhs_; }
|
||||
|
||||
int128_base &operator>>=(int rhs_) &{ return *this = *this >> rhs_; }
|
||||
|
||||
int128_base &operator&=(int128_base rhs_) &{ return *this = *this & rhs_; }
|
||||
|
||||
int128_base &operator|=(int128_base rhs_) &{ return *this = *this | rhs_; }
|
||||
|
||||
int128_base &operator^=(int128_base rhs_) &{ return *this = *this ^ rhs_; }
|
||||
|
||||
template<class, class>
|
||||
friend
|
||||
class int128_base;
|
||||
|
||||
template<class>
|
||||
friend
|
||||
struct clz_helper;
|
||||
|
||||
template<bool>
|
||||
friend
|
||||
struct detail_delegate;
|
||||
};
|
||||
|
||||
inline namespace literals {
|
||||
namespace impl_ {
|
||||
template<char _Ch, int _Rad>
|
||||
struct static_digit : std::integral_constant<int,
|
||||
'0' <= _Ch && _Ch <= '9' ? _Ch - '0' :
|
||||
'a' <= _Ch && _Ch <= 'z' ? _Ch - 'a' + 10 :
|
||||
'A' <= _Ch && _Ch <= 'Z' ? _Ch - 'A' + 10 : _Rad> {
|
||||
static_assert(_Rad > static_digit::value, "character not a digit");
|
||||
};
|
||||
|
||||
template<class, int, char ...>
|
||||
struct int128_literal_radix;
|
||||
|
||||
template<class _Tp, int _Rad, char _Ch>
|
||||
struct int128_literal_radix<_Tp, _Rad, _Ch> {
|
||||
constexpr operator _Tp() const { return _Tp(static_digit<_Ch, _Rad>::value); } // NOLINT explicit
|
||||
|
||||
constexpr _Tp operator()(_Tp v) const { return v * _Tp(_Rad) + *this; }
|
||||
};
|
||||
|
||||
template<class _Tp, int _Rad, char _Ch, char ..._Args>
|
||||
struct int128_literal_radix<_Tp, _Rad, _Ch, _Args...> {
|
||||
int128_literal_radix<_Tp, _Rad, _Ch> _Cur;
|
||||
int128_literal_radix<_Tp, _Rad, _Args...> _Tgt;
|
||||
|
||||
constexpr operator _Tp() const { return _Tgt(_Cur); }; // NOLINT explicit
|
||||
|
||||
constexpr _Tp operator()(_Tp v) const { return _Tgt(_Cur(v)); };
|
||||
};
|
||||
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal : int128_literal_radix<_Tp, 10, _Args...> {
|
||||
};
|
||||
template<class _Tp>
|
||||
struct int128_literal<_Tp, '0'> : int128_literal_radix<_Tp, 10, '0'> {
|
||||
};
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal<_Tp, '0', _Args...> : int128_literal_radix<_Tp, 8, _Args...> {
|
||||
};
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal<_Tp, '0', 'x', _Args...> : int128_literal_radix<_Tp, 16, _Args...> {
|
||||
};
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal<_Tp, '0', 'X', _Args...> : int128_literal_radix<_Tp, 16, _Args...> {
|
||||
};
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal<_Tp, '0', 'b', _Args...> : int128_literal_radix<_Tp, 2, _Args...> {
|
||||
};
|
||||
template<class _Tp, char ..._Args>
|
||||
struct int128_literal<_Tp, '0', 'B', _Args...> : int128_literal_radix<_Tp, 2, _Args...> {
|
||||
};
|
||||
}
|
||||
|
||||
template<char ..._Args>
|
||||
constexpr uint128_t operator "" _u128() { return impl_::int128_literal<uint128_t, _Args...>(); }
|
||||
|
||||
template<char ..._Args>
|
||||
constexpr int128_t operator "" _l128() { return impl_::int128_literal<int128_t, _Args...>(); }
|
||||
|
||||
template<char ..._Args>
|
||||
constexpr uint128_t operator "" _U128() { return impl_::int128_literal<uint128_t, _Args...>(); }
|
||||
|
||||
template<char ..._Args>
|
||||
constexpr int128_t operator "" _L128() { return impl_::int128_literal<int128_t, _Args...>(); }
|
||||
}
|
||||
|
||||
template<class>
|
||||
struct clz_helper;
|
||||
|
||||
template<>
|
||||
struct clz_helper<unsigned long> {
|
||||
static constexpr int clz(unsigned long val_) { return __builtin_clzl(val_); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct clz_helper<unsigned long long> {
|
||||
static constexpr int clz(unsigned long long val_) { return __builtin_clzll(val_); }
|
||||
};
|
||||
|
||||
template<class _High, class _Low>
|
||||
struct clz_helper<int128_base<_High, _Low> > {
|
||||
static constexpr int clz(int128_base<_High, _Low> val_) {
|
||||
return val_.high_ ? clz_helper<_Low>::clz(val_.high_) : 4 * sizeof(val_) + clz_helper<_Low>::clz(val_.low_);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool>
|
||||
struct detail_delegate {
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr bool cmp(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return lhs_.high_ < rhs_.high_ || (lhs_.high_ == rhs_.high_ && lhs_.low_ < rhs_.low_);
|
||||
}
|
||||
|
||||
static constexpr uint128_t shr(uint128_t lhs_, unsigned rhs_) {
|
||||
return rhs_ & 64U ? uint128_t(0, lhs_.high_ >> (rhs_ & 63U)) :
|
||||
rhs_ & 63U ? uint128_t(lhs_.high_ >> (rhs_ & 63U),
|
||||
(lhs_.high_ << (64 - (rhs_ & 63U)) | (lhs_.low_ >> (rhs_ & 63U)))) : lhs_;
|
||||
}
|
||||
|
||||
static constexpr int128_t sar(int128_t lhs_, unsigned rhs_) {
|
||||
return rhs_ & 64U ? int128_t(-(lhs_.high_ < 0), uint64_t(lhs_.high_ >> (rhs_ & 63U))) : // NOLINT
|
||||
rhs_ & 63U ? int128_t(
|
||||
lhs_.high_ >> (rhs_ & 63U), // NOLINT signed shift
|
||||
(uint64_t(lhs_.high_) << (64 - (rhs_ & 63U)) | (lhs_.low_ >> (rhs_ & 63U)))) : lhs_;
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> imul(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return int128_base<_Hi, _Low>(
|
||||
_Hi(lhs_.low_ * rhs_.high_ + rhs_.low_ * lhs_.high_) + (lhs_.low_ >> 32U) * (rhs_.low_ >> 32U),
|
||||
(lhs_.low_ & half_mask<_Low>::value) * (rhs_.low_ & half_mask<_Low>::value))
|
||||
+ (int128_base<_Hi, _Low>((lhs_.low_ >> 32U) * (rhs_.low_ & half_mask<_Low>::value)) << 32U)
|
||||
+ (int128_base<_Hi, _Low>((rhs_.low_ >> 32U) * (lhs_.low_ & half_mask<_Low>::value)) << 32U);
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> shl(int128_base<_Hi, _Low> lhs_, unsigned rhs_) {
|
||||
// [64,127], 64 {low_ << 0, 0}
|
||||
return rhs_ & 64U ? int128_base<_Hi, _Low>(_Hi(lhs_.low_ << (rhs_ & 63U)), _Low(0)) :
|
||||
rhs_ & 63U ? int128_base<_Hi, _Low>(
|
||||
_Hi((_Low(lhs_.high_) << (rhs_ & 63U)) | (lhs_.low_ >> (64U - (rhs_ & 63U)))),
|
||||
lhs_.low_ << (rhs_ & 63U)) : lhs_;
|
||||
}
|
||||
|
||||
static uint128_t &slow_div_(uint128_t ÷nd_, uint128_t divisor_, uint128_t "_) {
|
||||
// assert(divisor != uint128_t(0));
|
||||
quot_ = uint128_t(0);
|
||||
if (cmp(dividend_, divisor_)) return dividend_;
|
||||
if (dividend_.high_ == 0) { // (0,x) / ???
|
||||
quot_.low_ = dividend_.low_ / divisor_.low_;
|
||||
dividend_.low_ %= divisor_.low_;
|
||||
return dividend_;
|
||||
}
|
||||
auto zend_ = clz_helper<uint128_t>::clz(dividend_), zsor_ = clz_helper<uint128_t>::clz(divisor_);
|
||||
if (zend_ > zsor_) return dividend_;
|
||||
for (zsor_ -= zend_, divisor_ <<= zsor_;; divisor_ >>= 1, quot_ <<= 1) {
|
||||
if (dividend_ >= divisor_) {
|
||||
dividend_ -= divisor_;
|
||||
quot_ |= uint128_t(1);
|
||||
}
|
||||
if (!zsor_--) return dividend_;
|
||||
}
|
||||
}
|
||||
|
||||
static uint128_t div(uint128_t dividend_, uint128_t divisor_) {
|
||||
if (!divisor_) return {!!dividend_ / !!divisor_}; // raise signal SIGFPE
|
||||
uint128_t quot_(0);
|
||||
slow_div_(dividend_, divisor_, quot_);
|
||||
return quot_;
|
||||
}
|
||||
|
||||
static int128_t div(int128_t dividend_, int128_t divisor_) {
|
||||
bool nneg_ = dividend_.high_ < 0, dneg_ = divisor_.high_ < 0;
|
||||
auto res_ = div(uint128_t(nneg_ ? -dividend_ : dividend_), uint128_t(dneg_ ? -divisor_ : divisor_));
|
||||
return int128_t(nneg_ ^ dneg_ ? -res_ : res_);
|
||||
}
|
||||
|
||||
static uint128_t mod(uint128_t dividend_, uint128_t divisor_) {
|
||||
if (!divisor_) return {!!dividend_ % !!divisor_}; // raise signal SIGFPE
|
||||
uint128_t quot_(0);
|
||||
return slow_div_(dividend_, divisor_, quot_);
|
||||
}
|
||||
|
||||
static int128_t mod(int128_t dividend_, int128_t divisor_) {
|
||||
bool neg_ = dividend_.high_ < 0;
|
||||
auto res_ = mod(uint128_t(neg_ ? -dividend_ : dividend_),
|
||||
uint128_t(divisor_.high_ < 0 ? -divisor_ : divisor_));
|
||||
return int128_t(neg_ ? -res_ : res_);
|
||||
}
|
||||
|
||||
static void part_div(uint128_t value_, uint64_t div_, uint64_t &high_, uint64_t &mid_, uint64_t &low_) {
|
||||
uint128_t hh_(0), md_(0);
|
||||
low_ = static_cast<uint64_t>(slow_div_(value_, div_, md_));
|
||||
mid_ = static_cast<uint64_t>(slow_div_(md_, div_, hh_));
|
||||
high_ = static_cast<uint64_t>(hh_);
|
||||
}
|
||||
|
||||
template<class _Tp>
|
||||
constexpr static _Tp cast_to_float(uint128_t val_) { return std::ldexp(_Tp(val_.high_), 64) + _Tp(val_.low_); }
|
||||
|
||||
template<class _Tp>
|
||||
constexpr static _Tp cast_to_float(int128_t val_) {
|
||||
return val_.high_ < 0 ? -cast_to_float<_Tp>(uint128_t(-val_)) : cast_to_float<_Tp>(uint128_t(val_));
|
||||
}
|
||||
};
|
||||
|
||||
#if __SIZEOF_INT128__ == 16
|
||||
|
||||
template<>
|
||||
struct detail_delegate<true> {
|
||||
typedef __int128 ti_int_;
|
||||
typedef unsigned __int128 tu_int_;
|
||||
|
||||
static constexpr ti_int_ to_native(int128_t val_) { return static_cast<ti_int_>(val_); }
|
||||
|
||||
static constexpr tu_int_ to_native(uint128_t val_) { return static_cast<tu_int_>(val_); }
|
||||
|
||||
static constexpr int128_t from_native(ti_int_ val_) { return int128_t(val_); }
|
||||
|
||||
static constexpr uint128_t from_native(tu_int_ val_) { return uint128_t(val_); }
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr bool cmp(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return to_native(lhs_) < to_native(rhs_);
|
||||
}
|
||||
|
||||
static constexpr uint128_t shr(uint128_t lhs_, unsigned rhs_) {
|
||||
return from_native(to_native(lhs_) >> static_cast<decltype(to_native(lhs_))>(rhs_));
|
||||
}
|
||||
|
||||
static constexpr int128_t sar(int128_t lhs_, unsigned rhs_) {
|
||||
return from_native(to_native(lhs_) >> static_cast<decltype(to_native(lhs_))>(rhs_)); // NOLINT signed shift
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> imul(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return from_native(to_native(lhs_) * to_native(rhs_));
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> shl(int128_base<_Hi, _Low> lhs_, unsigned rhs_) {
|
||||
return from_native(to_native(lhs_) << static_cast<decltype(to_native(lhs_))>(rhs_)); // NOLINT signed shift
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> div(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return from_native(to_native(lhs_) / to_native(rhs_));
|
||||
}
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
static constexpr int128_base<_Hi, _Low> mod(int128_base<_Hi, _Low> lhs_, int128_base<_Hi, _Low> rhs_) {
|
||||
return from_native(to_native(lhs_) % to_native(rhs_));
|
||||
}
|
||||
|
||||
static void part_div(uint128_t value_, uint64_t div_, uint64_t &high_, uint64_t &mid_, uint64_t &low_) {
|
||||
// on some cpu, compiler won't do optimize for us
|
||||
auto vv_ = to_native(value_);
|
||||
auto rest_ = vv_ / div_;
|
||||
low_ = static_cast<uint64_t>(vv_) - div_ * static_cast<uint64_t>(rest_);
|
||||
high_ = static_cast<uint64_t>(rest_ / div_);
|
||||
mid_ = static_cast<uint64_t>(rest_) - div_ * high_;
|
||||
}
|
||||
|
||||
template<class _Tp, class _Hi, class _Low>
|
||||
static constexpr _Tp cast_to_float(int128_base<_Hi, _Low> value_) {
|
||||
return static_cast<_Tp>(to_native(value_));
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
constexpr bool operator<(int128_t lhs_, int128_t rhs_) { return detail_delegate<>::cmp(lhs_, rhs_); }
|
||||
|
||||
constexpr bool operator<(uint128_t lhs_, uint128_t rhs_) { return detail_delegate<>::cmp(lhs_, rhs_); }
|
||||
|
||||
constexpr uint128_t operator>>(uint128_t lhs_, int rhs_) {
|
||||
return detail_delegate<>::shr(lhs_, static_cast<unsigned>(rhs_));
|
||||
}
|
||||
|
||||
constexpr int128_t operator>>(int128_t lhs_, int rhs_) {
|
||||
return detail_delegate<>::sar(lhs_, static_cast<unsigned>(rhs_));
|
||||
}
|
||||
|
||||
constexpr int128_t operator*(int128_t lhs_, int128_t rhs_) { return detail_delegate<>::imul(lhs_, rhs_); }
|
||||
|
||||
constexpr uint128_t operator*(uint128_t lhs_, uint128_t rhs_) { return detail_delegate<>::imul(lhs_, rhs_); }
|
||||
|
||||
constexpr uint128_t operator<<(uint128_t lhs_, int rhs_) {
|
||||
return detail_delegate<>::shl(lhs_, static_cast<unsigned>(rhs_));
|
||||
}
|
||||
|
||||
constexpr int128_t operator<<(int128_t lhs_, int rhs_) {
|
||||
return detail_delegate<>::shl(lhs_, static_cast<unsigned>(rhs_));
|
||||
}
|
||||
|
||||
inline uint128_t operator/(uint128_t lhs_, uint128_t rhs_) { return detail_delegate<>::div(lhs_, rhs_); };
|
||||
|
||||
inline int128_t operator/(int128_t lhs_, int128_t rhs_) { return detail_delegate<>::div(lhs_, rhs_); };
|
||||
|
||||
inline uint128_t operator%(uint128_t lhs_, uint128_t rhs_) { return detail_delegate<>::mod(lhs_, rhs_); };
|
||||
|
||||
inline int128_t operator%(int128_t lhs_, int128_t rhs_) { return detail_delegate<>::mod(lhs_, rhs_); }
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
template<class _Tp>
|
||||
constexpr _Tp int128_base<_Hi, _Low>::cast_to_float() const {
|
||||
return detail_delegate<>::cast_to_float<_Tp>(*this);
|
||||
}
|
||||
|
||||
template<class _CharT, class _Traits>
|
||||
inline std::basic_ostream<_CharT, _Traits> &
|
||||
print_value(std::basic_ostream<_CharT, _Traits> &out_, bool signed_integral_, uint128_t value_) {
|
||||
constexpr std::size_t buf_size_ = 45;
|
||||
|
||||
typename std::basic_ostream<_CharT, _Traits>::sentry sentry_(out_);
|
||||
if (!sentry_) return out_;
|
||||
auto flags_ = out_.flags(), base_flag_ = flags_ & std::ios::basefield;
|
||||
auto adjust_field_ = flags_ & std::ios::adjustfield;
|
||||
auto show_base_ = bool(flags_ & std::ios::showbase); // work not dec
|
||||
auto show_pos_ = bool(flags_ & std::ios::showpos); // work only dec
|
||||
auto upper_case_ = bool(flags_ & std::ios::uppercase); // work only hex
|
||||
auto ns_ = out_.width(0);
|
||||
auto fl_ = out_.fill();
|
||||
|
||||
char buf_[buf_size_];
|
||||
char const *prefix_ = nullptr;
|
||||
int offset_ = 0;
|
||||
|
||||
switch (base_flag_) {
|
||||
case std::ios::hex: {
|
||||
if (show_base_ && value_) prefix_ = upper_case_ ? "0X" : "0x";
|
||||
if (value_ >> 64) {
|
||||
offset_ = snprintf(buf_, buf_size_,
|
||||
upper_case_ ? "%" PRIX64 "%016" PRIX64 : "%" PRIx64 "%016" PRIx64,
|
||||
(uint64_t) (value_ >> 64), (uint64_t) value_);
|
||||
} else {
|
||||
offset_ = snprintf(buf_, buf_size_,
|
||||
upper_case_ ? "%" PRIX64 : "%" PRIx64, (uint64_t) value_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case std::ios::oct: {
|
||||
constexpr uint64_t mask_ = (UINT64_C(1) << 63U) - 1;
|
||||
if (show_base_ && value_) buf_[offset_++] = '0';
|
||||
auto x_ = (uint64_t) (value_ >> 126U);
|
||||
auto y_ = (uint64_t) (value_ >> 63U) & mask_;
|
||||
auto z_ = (uint64_t) (value_) & mask_;
|
||||
if (x_) {
|
||||
offset_ += snprintf(buf_ + offset_, buf_size_ - offset_, "%" PRIo64 "%021" PRIo64 "%021" PRIo64,
|
||||
x_, y_, z_);
|
||||
} else if (y_) {
|
||||
offset_ += snprintf(buf_ + offset_, buf_size_ - offset_, "%" PRIo64 "%021" PRIo64, y_, z_);
|
||||
} else {
|
||||
offset_ += snprintf(buf_ + offset_, buf_size_ - offset_, "%" PRIo64, z_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (signed_integral_) {
|
||||
if (value_ >> 127) { // negative
|
||||
prefix_ = "-";
|
||||
value_ = -value_;
|
||||
} else if (show_pos_) {
|
||||
prefix_ = "+";
|
||||
}
|
||||
}
|
||||
uint64_t high_, mid_, low_;
|
||||
detail_delegate<>::part_div(value_, UINT64_C(10000000000000000000), high_, mid_, low_);
|
||||
if (high_) {
|
||||
offset_ = snprintf(buf_, buf_size_, "%" PRIu64 "%019" PRIu64 "%019" PRIu64,
|
||||
high_, mid_, low_);
|
||||
} else if (mid_) {
|
||||
offset_ = snprintf(buf_, buf_size_, "%" PRIu64 "%019" PRIu64,
|
||||
mid_, low_);
|
||||
} else {
|
||||
offset_ = snprintf(buf_, buf_size_, "%" PRIu64, low_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_CharT o_[2 * buf_size_ - 3];
|
||||
_CharT *os_;
|
||||
_CharT *op_; // prefix here
|
||||
_CharT *oe_ = o_ + (sizeof(o_) / sizeof(o_[0])); // end of output
|
||||
|
||||
auto loc_ = out_.getloc();
|
||||
auto &ct_ = std::use_facet<std::ctype<_CharT> >(loc_);
|
||||
auto &npt_ = std::use_facet<std::numpunct<_CharT> >(loc_);
|
||||
std::string grouping_ = npt_.grouping();
|
||||
|
||||
// no worry group is not empty
|
||||
auto limit_ = grouping_.size();
|
||||
if (limit_ == 0) {
|
||||
op_ = oe_ - offset_;
|
||||
ct_.widen(buf_, buf_ + offset_, op_);
|
||||
} else {
|
||||
auto thousands_sep_ = npt_.thousands_sep();
|
||||
decltype(limit_) dg_ = 0;
|
||||
auto cnt_ = static_cast<unsigned char>(grouping_[dg_]);
|
||||
unsigned char dc_ = 0;
|
||||
--limit_;
|
||||
op_ = oe_;
|
||||
for (char *p_ = buf_ + offset_; p_ != buf_; ++dc_) {
|
||||
if (cnt_ > 0 && dc_ == cnt_) {
|
||||
*--op_ = thousands_sep_;
|
||||
dc_ = 0;
|
||||
if (dg_ < limit_) cnt_ = static_cast<unsigned char>(grouping_[++dg_]);
|
||||
}
|
||||
*--op_ = ct_.widen(*--p_);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix_) {
|
||||
auto prefix_len_ = strlen(prefix_);
|
||||
os_ = op_ - prefix_len_;
|
||||
ct_.widen(prefix_, prefix_ + prefix_len_, os_);
|
||||
} else {
|
||||
os_ = op_;
|
||||
}
|
||||
|
||||
auto sz_ = static_cast<std::streamsize>(oe_ - os_);
|
||||
// assert(sz_ <= (sizeof(o_) / sizeof(o_[0])));
|
||||
|
||||
if (ns_ > sz_) {
|
||||
ns_ -= sz_;
|
||||
std::basic_string<_CharT, _Traits> sp_(ns_, fl_);
|
||||
switch (adjust_field_) {
|
||||
case std::ios::left:
|
||||
return out_.write(os_, sz_).write(sp_.data(), ns_);
|
||||
case std::ios::internal:
|
||||
return out_.write(os_, static_cast<std::streamsize>(op_ - os_))
|
||||
.write(sp_.data(), ns_)
|
||||
.write(op_, static_cast<std::streamsize>(oe_ - op_));
|
||||
default:
|
||||
return out_.write(sp_.data(), ns_).write(os_, sz_);
|
||||
}
|
||||
}
|
||||
return out_.write(os_, sz_);
|
||||
}
|
||||
|
||||
template<class _CharT, class _Traits>
|
||||
inline std::basic_ostream<_CharT, _Traits> &operator<<(std::basic_ostream<_CharT, _Traits> &out, uint128_t _Val) {
|
||||
return print_value(out, false, _Val);
|
||||
}
|
||||
|
||||
template<class _CharT, class _Traits>
|
||||
inline std::basic_ostream<_CharT, _Traits> &operator<<(std::basic_ostream<_CharT, _Traits> &out, int128_t _Val) {
|
||||
return print_value(out, true, uint128_t(_Val));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INT128_SPECIALIZATION
|
||||
namespace std {
|
||||
#pragma push_macro("MAKE_TYPE")
|
||||
#define MAKE_TYPE(outter, inner, parent) \
|
||||
template<> struct outter<large_int::inner> : std::parent {}; \
|
||||
template<> struct outter<const large_int::inner> : std::parent {}; \
|
||||
template<> struct outter<volatile large_int::inner> : std::parent {}; \
|
||||
template<> struct outter<const volatile large_int::inner> : std::parent {};
|
||||
MAKE_TYPE(is_integral, uint128_t, true_type)
|
||||
MAKE_TYPE(is_integral, int128_t, true_type)
|
||||
MAKE_TYPE(is_signed, uint128_t, false_type)
|
||||
MAKE_TYPE(is_signed, int128_t, true_type)
|
||||
#undef MAKE_TYPE
|
||||
#define MAKE_TYPE(outter, inner, target) \
|
||||
template<> struct outter<large_int::inner> { typedef large_int::target type; }; \
|
||||
template<> struct outter<const large_int::inner> { typedef const large_int::target type; }; \
|
||||
template<> struct outter<volatile large_int::inner> { typedef volatile large_int::target type; }; \
|
||||
template<> struct outter<const volatile large_int::inner> { typedef const volatile large_int::target type; };
|
||||
MAKE_TYPE(make_signed, uint128_t, int128_t)
|
||||
MAKE_TYPE(make_unsigned, int128_t, uint128_t)
|
||||
#pragma pop_macro("MAKE_TYPE")
|
||||
|
||||
template<class _Hi, class _Low>
|
||||
struct numeric_limits<large_int::int128_base<_Hi, _Low> > {
|
||||
private:
|
||||
typedef large_int::int128_base<_Hi, _Low> _Tp;
|
||||
public:
|
||||
static constexpr const bool is_specialized = true;
|
||||
static constexpr const bool is_signed = numeric_limits<_Hi>::is_signed;
|
||||
static constexpr const bool is_integer = true;
|
||||
static constexpr const bool is_exact = true;
|
||||
static constexpr const bool has_infinity = false;
|
||||
static constexpr const bool has_quiet_NaN = false;
|
||||
static constexpr const bool has_signaling_NaN = false;
|
||||
static constexpr const std::float_denorm_style has_denorm = std::denorm_absent;
|
||||
static constexpr const bool has_denorm_loss = false;
|
||||
static constexpr const std::float_round_style round_style = std::round_toward_zero;
|
||||
static constexpr const bool is_iec559 = false;
|
||||
static constexpr const bool is_bounded = true;
|
||||
static constexpr const bool is_modulo = numeric_limits<_Hi>::is_modulo;
|
||||
static constexpr const int digits = static_cast<int>(sizeof(_Tp) * 8 - is_signed);
|
||||
static constexpr const int digits10 = digits * 3 / 10;
|
||||
static constexpr const int max_digits10 = 0;
|
||||
static constexpr const int radix = 2;
|
||||
static constexpr const int min_exponent = 0;
|
||||
static constexpr const int min_exponent10 = 0;
|
||||
static constexpr const int max_exponent = 0;
|
||||
static constexpr const int max_exponent10 = 0;
|
||||
static constexpr const bool traps = numeric_limits<_Hi>::traps;
|
||||
static constexpr const bool tinyness_before = false;
|
||||
|
||||
static constexpr _Tp min() { return is_signed ? _Tp(1) << digits : _Tp(0); }
|
||||
|
||||
static constexpr _Tp lowest() { return min(); }
|
||||
|
||||
static constexpr _Tp max() { return ~min(); }
|
||||
|
||||
static constexpr _Tp epsilon() { return _Tp(0); }
|
||||
|
||||
static constexpr _Tp round_error() { return _Tp(0); }
|
||||
|
||||
static constexpr _Tp infinity() { return _Tp(0); }
|
||||
|
||||
static constexpr _Tp quiet_NaN() { return _Tp(0); }
|
||||
|
||||
static constexpr _Tp signaling_NaN() { return _Tp(0); }
|
||||
|
||||
static constexpr _Tp denorm_min() { return _Tp(0); }
|
||||
};
|
||||
}
|
||||
#endif /* INT128_SPECIALIZATION */
|
||||
|
||||
#ifndef INT128_NO_EXPORT
|
||||
#define INT128_C(val) val##_L128
|
||||
#define UINT128_C(val) val##_U128
|
||||
// add space between ‘""’ and suffix identifier, or may compile failed
|
||||
using namespace large_int::literals;
|
||||
using large_int::uint128_t;
|
||||
using large_int::int128_t;
|
||||
#endif /* INT128_NO_EXPORT */
|
||||
Loading…
Add table
Add a link
Reference in a new issue