diff options
Diffstat (limited to 'js/src/builtin/temporal/TemporalTypes.h')
-rw-r--r-- | js/src/builtin/temporal/TemporalTypes.h | 240 |
1 files changed, 188 insertions, 52 deletions
diff --git a/js/src/builtin/temporal/TemporalTypes.h b/js/src/builtin/temporal/TemporalTypes.h index 654fd65a3b..b645a9a175 100644 --- a/js/src/builtin/temporal/TemporalTypes.h +++ b/js/src/builtin/temporal/TemporalTypes.h @@ -11,7 +11,9 @@ #include "mozilla/CheckedInt.h" #include <stdint.h> +#include <type_traits> +#include "builtin/temporal/Int128.h" #include "builtin/temporal/TemporalUnit.h" namespace js::temporal { @@ -181,15 +183,19 @@ struct SecondsAndNanoseconds { /** * Return the nanoseconds value. - * - * The returned nanoseconds amount can be invalid on overflow. The caller is - * responsible for handling the overflow case. */ - constexpr mozilla::CheckedInt64 toNanoseconds() const { - mozilla::CheckedInt64 nanos = seconds; - nanos *= ToNanoseconds(TemporalUnit::Second); - nanos += nanoseconds; - return nanos; + constexpr Int128 toNanoseconds() const { + return Int128{seconds} * Int128{ToNanoseconds(TemporalUnit::Second)} + + Int128{nanoseconds}; + } + + /** + * Cast to a different representation. + */ + template <class Other> + constexpr Other to() const { + static_assert(std::is_base_of_v<SecondsAndNanoseconds<Other>, Other>); + return Other{seconds, nanoseconds}; } /** @@ -209,7 +215,7 @@ struct SecondsAndNanoseconds { */ static constexpr Derived fromMilliseconds(int64_t milliseconds) { int64_t seconds = milliseconds / 1'000; - int32_t millis = milliseconds % 1'000; + int32_t millis = int32_t(milliseconds % 1'000); if (millis < 0) { seconds -= 1; millis += 1'000; @@ -222,7 +228,7 @@ struct SecondsAndNanoseconds { */ static constexpr Derived fromMicroseconds(int64_t microseconds) { int64_t seconds = microseconds / 1'000'000; - int32_t micros = microseconds % 1'000'000; + int32_t micros = int32_t(microseconds % 1'000'000); if (micros < 0) { seconds -= 1; micros += 1'000'000; @@ -235,7 +241,21 @@ struct SecondsAndNanoseconds { */ static constexpr Derived fromNanoseconds(int64_t nanoseconds) { int64_t seconds = nanoseconds / 1'000'000'000; - int32_t nanos = nanoseconds % 1'000'000'000; + int32_t nanos = int32_t(nanoseconds % 1'000'000'000); + if (nanos < 0) { + seconds -= 1; + nanos += 1'000'000'000; + } + return {seconds, nanos}; + } + + /** + * Create from a nanoseconds value. + */ + static constexpr Derived fromNanoseconds(const Int128& nanoseconds) { + auto div = nanoseconds.divrem(Int128{1'000'000'000}); + int64_t seconds = int64_t(div.first); + int32_t nanos = int32_t(div.second); if (nanos < 0) { seconds -= 1; nanos += 1'000'000'000; @@ -365,6 +385,32 @@ struct Instant final : SecondsAndNanoseconds<Instant> { static constexpr Instant min() { return -max(); } }; +// Minimum and maximum valid epoch day relative to midnight at the beginning of +// 1 January 1970 UTC. +// +// NOTE in ISODateTimeWithinLimits: +// +// Temporal.PlainDateTime objects can represent points in time within 24 hours +// (8.64 × 10**13 nanoseconds) of the Temporal.Instant boundaries. This ensures +// that a Temporal.Instant object can be converted into a Temporal.PlainDateTime +// object using any time zone. +// +// This limits the maximum valid date-time to +275760-09-13T23:59:59.999Z and +// the minimum valid date-time -271821-04-19T00:00:00.001Z. The corresponding +// maximum and minimum valid date values are therefore +275760-09-13 and +// -271821-04-19. There are exactly 100'000'000 days from 1 January 1970 UTC to +// the maximum valid date and -100'000'001 days to the minimum valid date. +constexpr inline int32_t MinEpochDay = -100'000'001; +constexpr inline int32_t MaxEpochDay = 100'000'000; + +static_assert(MinEpochDay == + Instant::min().seconds / ToSeconds(TemporalUnit::Day) - 1); +static_assert(MaxEpochDay == + Instant::max().seconds / ToSeconds(TemporalUnit::Day)); + +// Maximum number of days between two valid epoch days. +constexpr inline int32_t MaxEpochDaysDuration = MaxEpochDay - MinEpochDay; + /** * Plain date represents a date in the ISO 8601 calendar. */ @@ -437,6 +483,9 @@ struct PlainDateTime final { } }; +struct DateDuration; +struct TimeDuration; + /** * Duration represents the difference between dates or times. Each duration * component is an integer and all components must have the same sign. @@ -453,7 +502,7 @@ struct Duration final { double microseconds = 0; double nanoseconds = 0; - bool operator==(const Duration& other) const { + constexpr bool operator==(const Duration& other) const { return years == other.years && months == other.months && weeks == other.weeks && days == other.days && hours == other.hours && minutes == other.minutes && seconds == other.seconds && @@ -462,35 +511,14 @@ struct Duration final { nanoseconds == other.nanoseconds; } - bool operator!=(const Duration& other) const { return !(*this == other); } - - /** - * Return the date components of this duration. - */ - Duration date() const { return {years, months, weeks, days}; } - - /** - * Return the time components of this duration. - */ - Duration time() const { - return { - 0, - 0, - 0, - 0, - hours, - minutes, - seconds, - milliseconds, - microseconds, - nanoseconds, - }; + constexpr bool operator!=(const Duration& other) const { + return !(*this == other); } /** * Return a new duration with every component negated. */ - Duration negate() const { + constexpr Duration negate() const { // Add zero to convert -0 to +0. return { -years + (+0.0), -months + (+0.0), -weeks + (+0.0), @@ -499,6 +527,11 @@ struct Duration final { -nanoseconds + (+0.0), }; } + + /** + * Return the date components of this duration. + */ + inline DateDuration toDateDuration() const; }; /** @@ -506,41 +539,144 @@ struct Duration final { * component is an integer and all components must have the same sign. */ struct DateDuration final { - double years = 0; - double months = 0; - double weeks = 0; - double days = 0; + // abs(years) < 2**32 + int64_t years = 0; + + // abs(months) < 2**32 + int64_t months = 0; + + // abs(weeks) < 2**32 + int64_t weeks = 0; + + // abs(days) < ⌈(2**53) / (24 * 60 * 60)⌉ + int64_t days = 0; - Duration toDuration() { return {years, months, weeks, days}; } + constexpr bool operator==(const DateDuration& other) const { + return years == other.years && months == other.months && + weeks == other.weeks && days == other.days; + } + + constexpr bool operator!=(const DateDuration& other) const { + return !(*this == other); + } + + constexpr Duration toDuration() const { + return { + double(years), + double(months), + double(weeks), + double(days), + }; + } }; +inline DateDuration Duration::toDateDuration() const { + return {int64_t(years), int64_t(months), int64_t(weeks), int64_t(days)}; +} + /** * Time duration represents the difference between times. Each duration * component is an integer and all components must have the same sign. */ struct TimeDuration final { - double days = 0; - double hours = 0; - double minutes = 0; - double seconds = 0; - double milliseconds = 0; + // abs(days) < ⌈(2**53) / (24 * 60 * 60)⌉ + int64_t days = 0; + + // abs(hours) < ⌈(2**53) / (60 * 60)⌉ + int64_t hours = 0; + + // abs(minutes) < ⌈(2**53) / 60⌉ + int64_t minutes = 0; + + // abs(seconds) < (2**53) + int64_t seconds = 0; + + // abs(milliseconds) < (2**53) * (1000**1) + int64_t milliseconds = 0; + + // abs(microseconds) < (2**53) * (1000**2) double microseconds = 0; + + // abs(nanoseconds) < (2**53) * (1000**3) double nanoseconds = 0; - Duration toDuration() { + constexpr Duration toDuration() const { return {0, 0, 0, - days, - hours, - minutes, - seconds, - milliseconds, + double(days), + double(hours), + double(minutes), + double(seconds), + double(milliseconds), microseconds, nanoseconds}; } }; +/** + * Normalized time duration with a seconds value in the range + * [-9'007'199'254'740'991, +9'007'199'254'740'991] and a nanoseconds value in + * the range [0, 999'999'999]. + */ +struct NormalizedTimeDuration final + : SecondsAndNanoseconds<NormalizedTimeDuration> { + constexpr NormalizedTimeDuration& operator+=( + const NormalizedTimeDuration& other) { + *this = add(*this, other); + return *this; + } + + constexpr NormalizedTimeDuration& operator-=( + const NormalizedTimeDuration& other) { + *this = subtract(*this, other); + return *this; + } + + constexpr NormalizedTimeDuration operator+( + const NormalizedTimeDuration& other) const { + return add(*this, other); + } + + constexpr NormalizedTimeDuration operator-( + const NormalizedTimeDuration& other) const { + return subtract(*this, other); + } + + constexpr NormalizedTimeDuration operator-() const { return negate(*this); } + + /** + * Returns the maximum normalized time duration value. + */ + static constexpr NormalizedTimeDuration max() { + constexpr int64_t seconds = 0x1f'ffff'ffff'ffff; + constexpr int64_t nanos = 999'999'999; + return {seconds, nanos}; + } + + /** + * Returns the minimum normalized time duration value. + */ + static constexpr NormalizedTimeDuration min() { return -max(); } +}; + +/** + * Duration represents the difference between dates or times. Each duration + * component is an integer and all components must have the same sign. + */ +struct NormalizedDuration final { + DateDuration date; + NormalizedTimeDuration time; + + constexpr bool operator==(const NormalizedDuration& other) const { + return date == other.date && time == other.time; + } + + constexpr bool operator!=(const NormalizedDuration& other) const { + return !(*this == other); + } +}; + } /* namespace js::temporal */ #endif /* builtin_temporal_TemporalTypes_h */ |