/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef builtin_temporal_Duration_h #define builtin_temporal_Duration_h #include #include "builtin/temporal/TemporalTypes.h" #include "builtin/temporal/Wrapped.h" #include "js/RootingAPI.h" #include "js/TypeDecls.h" #include "js/Value.h" #include "vm/NativeObject.h" namespace js { struct ClassSpec; } namespace js::temporal { class DurationObject : public NativeObject { public: static const JSClass class_; static const JSClass& protoClass_; static constexpr uint32_t YEARS_SLOT = 0; static constexpr uint32_t MONTHS_SLOT = 1; static constexpr uint32_t WEEKS_SLOT = 2; static constexpr uint32_t DAYS_SLOT = 3; static constexpr uint32_t HOURS_SLOT = 4; static constexpr uint32_t MINUTES_SLOT = 5; static constexpr uint32_t SECONDS_SLOT = 6; static constexpr uint32_t MILLISECONDS_SLOT = 7; static constexpr uint32_t MICROSECONDS_SLOT = 8; static constexpr uint32_t NANOSECONDS_SLOT = 9; static constexpr uint32_t SLOT_COUNT = 10; double years() const { return getFixedSlot(YEARS_SLOT).toNumber(); } double months() const { return getFixedSlot(MONTHS_SLOT).toNumber(); } double weeks() const { return getFixedSlot(WEEKS_SLOT).toNumber(); } double days() const { return getFixedSlot(DAYS_SLOT).toNumber(); } double hours() const { return getFixedSlot(HOURS_SLOT).toNumber(); } double minutes() const { return getFixedSlot(MINUTES_SLOT).toNumber(); } double seconds() const { return getFixedSlot(SECONDS_SLOT).toNumber(); } double milliseconds() const { return getFixedSlot(MILLISECONDS_SLOT).toNumber(); } double microseconds() const { return getFixedSlot(MICROSECONDS_SLOT).toNumber(); } double nanoseconds() const { return getFixedSlot(NANOSECONDS_SLOT).toNumber(); } private: static const ClassSpec classSpec_; }; /** * Extract the duration fields from the Duration object. */ inline Duration ToDuration(const DurationObject* duration) { return { duration->years(), duration->months(), duration->weeks(), duration->days(), duration->hours(), duration->minutes(), duration->seconds(), duration->milliseconds(), duration->microseconds(), duration->nanoseconds(), }; } class Increment; class CalendarRecord; class PlainDateObject; class TimeZoneRecord; class ZonedDateTime; class ZonedDateTimeObject; enum class TemporalRoundingMode; enum class TemporalUnit; /** * DurationSign ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ int32_t DurationSign(const Duration& duration); /** * DurationSign ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ int32_t DurationSign(const DateDuration& duration); /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ bool IsValidDuration(const Duration& duration); #ifdef DEBUG /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ bool IsValidDuration(const DateDuration& duration); /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ bool IsValidDuration(const NormalizedDuration& duration); #endif /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ bool ThrowIfInvalidDuration(JSContext* cx, const Duration& duration); /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ bool ThrowIfInvalidDuration(JSContext* cx, const DateDuration& duration); /** * IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds ) */ inline bool IsValidNormalizedTimeDuration( const NormalizedTimeDuration& duration) { MOZ_ASSERT(0 <= duration.nanoseconds && duration.nanoseconds <= 999'999'999); // Step 4. // // The absolute value of the seconds part of normalized time duration must be // less-or-equal to `2**53 - 1` and the nanoseconds part must be less or equal // to `999'999'999`. return NormalizedTimeDuration::min() <= duration && duration <= NormalizedTimeDuration::max(); } /** * NormalizeTimeDuration ( hours, minutes, seconds, milliseconds, microseconds, * nanoseconds ) */ NormalizedTimeDuration NormalizeTimeDuration(int32_t hours, int32_t minutes, int32_t seconds, int32_t milliseconds, int32_t microseconds, int32_t nanoseconds); /** * NormalizeTimeDuration ( hours, minutes, seconds, milliseconds, microseconds, * nanoseconds ) */ NormalizedTimeDuration NormalizeTimeDuration(const Duration& duration); /** * CompareNormalizedTimeDuration ( one, two ) */ inline int32_t CompareNormalizedTimeDuration( const NormalizedTimeDuration& one, const NormalizedTimeDuration& two) { MOZ_ASSERT(IsValidNormalizedTimeDuration(one)); MOZ_ASSERT(IsValidNormalizedTimeDuration(two)); // Step 1. if (one > two) { return 1; } // Step 2. if (one < two) { return -1; } // Step 3. return 0; } /** * NormalizedTimeDurationSign ( d ) */ inline int32_t NormalizedTimeDurationSign(const NormalizedTimeDuration& d) { MOZ_ASSERT(IsValidNormalizedTimeDuration(d)); // Steps 1-3. return CompareNormalizedTimeDuration(d, NormalizedTimeDuration{}); } /** * Add24HourDaysToNormalizedTimeDuration ( d, days ) */ bool Add24HourDaysToNormalizedTimeDuration(JSContext* cx, const NormalizedTimeDuration& d, int64_t days, NormalizedTimeDuration* result); /** * CreateNormalizedDurationRecord ( years, months, weeks, days, norm ) */ inline NormalizedDuration CreateNormalizedDurationRecord( const DateDuration& date, const NormalizedTimeDuration& time) { MOZ_ASSERT(IsValidDuration(date)); MOZ_ASSERT(IsValidNormalizedTimeDuration(time)); #ifdef DEBUG int64_t dateValues = date.years | date.months | date.weeks | date.days; int32_t dateSign = dateValues ? dateValues < 0 ? -1 : 1 : 0; int32_t timeSign = NormalizedTimeDurationSign(time); MOZ_ASSERT((dateSign * timeSign) >= 0); #endif return {date, time}; } /** * CreateNormalizedDurationRecord ( years, months, weeks, days, norm ) */ inline NormalizedDuration CreateNormalizedDurationRecord( const Duration& duration) { return CreateNormalizedDurationRecord(duration.toDateDuration(), NormalizeTimeDuration(duration)); } /** * CombineDateAndNormalizedTimeDuration ( dateDurationRecord, norm ) */ bool CombineDateAndNormalizedTimeDuration(JSContext* cx, const DateDuration& date, const NormalizedTimeDuration& time, NormalizedDuration* result); /** * CreateNormalizedDurationRecord ( years, months, weeks, days, norm ) */ inline bool CreateNormalizedDurationRecord(JSContext* cx, const DateDuration& date, const NormalizedTimeDuration& time, NormalizedDuration* result) { return CombineDateAndNormalizedTimeDuration(cx, date, time, result); } /** * NormalizedTimeDurationFromEpochNanosecondsDifference ( one, two ) */ NormalizedTimeDuration NormalizedTimeDurationFromEpochNanosecondsDifference( const Instant& one, const Instant& two); /** * CreateTemporalDuration ( years, months, weeks, days, hours, minutes, seconds, * milliseconds, microseconds, nanoseconds [ , newTarget ] ) */ DurationObject* CreateTemporalDuration(JSContext* cx, const Duration& duration); /** * ToTemporalDuration ( item ) */ Wrapped ToTemporalDuration(JSContext* cx, JS::Handle item); /** * ToTemporalDuration ( item ) */ bool ToTemporalDuration(JSContext* cx, JS::Handle item, Duration* result); /** * ToTemporalDurationRecord ( temporalDurationLike ) */ bool ToTemporalDurationRecord(JSContext* cx, JS::Handle temporalDurationLike, Duration* result); /** * BalanceTimeDuration ( norm, largestUnit ) */ TimeDuration BalanceTimeDuration(const NormalizedTimeDuration& duration, TemporalUnit largestUnit); /** * BalanceTimeDuration ( norm, largestUnit ) */ bool BalanceTimeDuration(JSContext* cx, const NormalizedTimeDuration& duration, TemporalUnit largestUnit, TimeDuration* result); /** * BalanceDateDurationRelative ( years, months, weeks, days, largestUnit, * smallestUnit, plainRelativeTo, calendarRec ) */ bool BalanceDateDurationRelative( JSContext* cx, const DateDuration& duration, TemporalUnit largestUnit, TemporalUnit smallestUnit, JS::Handle> plainRelativeTo, JS::Handle calendar, DateDuration* result); /** * AdjustRoundedDurationDays ( years, months, weeks, days, norm, increment, * unit, roundingMode, zonedRelativeTo, calendarRec, timeZoneRec, * precalculatedPlainDateTime ) */ bool AdjustRoundedDurationDays(JSContext* cx, const NormalizedDuration& duration, Increment increment, TemporalUnit unit, TemporalRoundingMode roundingMode, JS::Handle relativeTo, JS::Handle calendar, JS::Handle timeZone, const PlainDateTime& precalculatedPlainDateTime, NormalizedDuration* result); /** * RoundDuration ( years, months, weeks, days, norm, increment, unit, * roundingMode [ , plainRelativeTo [ , calendarRec [ , zonedRelativeTo [ , * timeZoneRec [ , precalculatedPlainDateTime ] ] ] ] ] ) */ NormalizedTimeDuration RoundDuration(const NormalizedTimeDuration& duration, Increment increment, TemporalUnit unit, TemporalRoundingMode roundingMode); /** * RoundDuration ( years, months, weeks, days, norm, increment, unit, * roundingMode [ , plainRelativeTo [ , calendarRec [ , zonedRelativeTo [ , * timeZoneRec [ , precalculatedPlainDateTime ] ] ] ] ] ) */ bool RoundDuration(JSContext* cx, const NormalizedTimeDuration& duration, Increment increment, TemporalUnit unit, TemporalRoundingMode roundingMode, NormalizedTimeDuration* result); /** * RoundDuration ( years, months, weeks, days, norm, increment, unit, * roundingMode [ , plainRelativeTo [ , calendarRec [ , zonedRelativeTo [ , * timeZoneRec [ , precalculatedPlainDateTime ] ] ] ] ] ) */ bool RoundDuration(JSContext* cx, const NormalizedDuration& duration, Increment increment, TemporalUnit unit, TemporalRoundingMode roundingMode, JS::Handle> plainRelativeTo, JS::Handle calendar, NormalizedDuration* result); /** * RoundDuration ( years, months, weeks, days, norm, increment, unit, * roundingMode [ , plainRelativeTo [ , calendarRec [ , zonedRelativeTo [ , * timeZoneRec [ , precalculatedPlainDateTime ] ] ] ] ] ) */ bool RoundDuration(JSContext* cx, const NormalizedDuration& duration, Increment increment, TemporalUnit unit, TemporalRoundingMode roundingMode, JS::Handle plainRelativeTo, JS::Handle calendar, JS::Handle zonedRelativeTo, JS::Handle timeZone, const PlainDateTime& precalculatedPlainDateTime, NormalizedDuration* result); /** * DaysUntil ( earlier, later ) */ int32_t DaysUntil(const PlainDate& earlier, const PlainDate& later); } /* namespace js::temporal */ #endif /* builtin_temporal_Duration_h */