2021-07-15 23:20:43 +01:00
/*
2023-04-13 15:41:29 +02:00
* Copyright ( c ) 2021 - 2023 , Linus Groh < linusg @ serenityos . org >
2021-11-23 23:09:01 +00:00
* Copyright ( c ) 2021 , Luke Wilde < lukew @ serenityos . org >
2024-01-05 13:28:39 +13:00
* Copyright ( c ) 2024 , Shannon Booth < shannon @ serenityos . org >
2021-07-15 23:20:43 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-08-13 12:36:06 -04:00
# include <AK/Math.h>
2024-11-16 12:51:53 -05:00
# include <AK/NumericLimits.h>
# include <LibCrypto/BigInt/SignedBigInteger.h>
2021-07-15 23:20:43 +01:00
# include <LibJS/Runtime/Temporal/Duration.h>
2024-11-16 12:51:53 -05:00
# include <LibJS/Runtime/Value.h>
# include <math.h>
2021-07-15 23:20:43 +01:00
namespace JS : : Temporal {
2022-03-10 16:52:25 +01:00
// 7.5.10 DurationSign ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-durationsign
2021-07-15 23:20:43 +01:00
i8 duration_sign ( double years , double months , double weeks , double days , double hours , double minutes , double seconds , double milliseconds , double microseconds , double nanoseconds )
{
// 1. For each value v of ยซ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ยป, do
for ( auto & v : { years , months , weeks , days , hours , minutes , seconds , milliseconds , microseconds , nanoseconds } ) {
2022-04-29 21:09:10 +02:00
// a. If v < 0, return -1.
2021-07-15 23:20:43 +01:00
if ( v < 0 )
return - 1 ;
// b. If v > 0, return 1.
if ( v > 0 )
return 1 ;
}
// 2. Return 0.
return 0 ;
}
2022-03-10 16:52:25 +01:00
// 7.5.11 IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidduration
2021-07-15 23:20:43 +01:00
bool is_valid_duration ( double years , double months , double weeks , double days , double hours , double minutes , double seconds , double milliseconds , double microseconds , double nanoseconds )
{
// 1. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
auto sign = duration_sign ( years , months , weeks , days , hours , minutes , seconds , milliseconds , microseconds , nanoseconds ) ;
// 2. For each value v of ยซ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ยป, do
for ( auto & v : { years , months , weeks , days , hours , minutes , seconds , milliseconds , microseconds , nanoseconds } ) {
2022-05-07 16:26:32 +02:00
// a. If ๐ฝ (v) is not finite, return false.
2021-07-15 23:20:43 +01:00
if ( ! isfinite ( v ) )
return false ;
// b. If v < 0 and sign > 0, return false.
if ( v < 0 & & sign > 0 )
return false ;
// c. If v > 0 and sign < 0, return false.
if ( v > 0 & & sign < 0 )
return false ;
}
2024-08-13 12:36:06 -04:00
// 3. If abs(years) โฅ 2**32, return false.
if ( AK : : fabs ( years ) > NumericLimits < u32 > : : max ( ) )
return false ;
// 4. If abs(months) โฅ 2**32, return false.
if ( AK : : fabs ( months ) > NumericLimits < u32 > : : max ( ) )
return false ;
// 5. If abs(weeks) โฅ 2**32, return false.
if ( AK : : fabs ( weeks ) > NumericLimits < u32 > : : max ( ) )
return false ;
// 6. Let normalizedSeconds be days ร 86,400 + hours ร 3600 + minutes ร 60 + seconds + โ (๐ฝ (milliseconds)) ร 10**-3 + โ (๐ฝ (microseconds)) ร 10**-6 + โ (๐ฝ (nanoseconds)) ร 10**-9.
// 7. 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.
static Crypto : : SignedBigInteger days_to_nanoseconds { 8.64e13 } ;
static Crypto : : SignedBigInteger hours_to_nanoseconds { 3.6e12 } ;
static Crypto : : SignedBigInteger minutes_to_nanoseconds { 6e10 } ;
static Crypto : : SignedBigInteger seconds_to_nanoseconds { 1e9 } ;
static Crypto : : SignedBigInteger milliseconds_to_nanoseconds { 1e6 } ;
static Crypto : : SignedBigInteger microseconds_to_nanoseconds { 1e3 } ;
auto normalized_nanoseconds = Crypto : : SignedBigInteger { days } . multiplied_by ( days_to_nanoseconds ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { hours } . multiplied_by ( hours_to_nanoseconds ) ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { minutes } . multiplied_by ( minutes_to_nanoseconds ) ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { seconds } . multiplied_by ( seconds_to_nanoseconds ) ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { milliseconds } . multiplied_by ( milliseconds_to_nanoseconds ) ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { microseconds } . multiplied_by ( microseconds_to_nanoseconds ) ) ;
normalized_nanoseconds = normalized_nanoseconds . plus ( Crypto : : SignedBigInteger { nanoseconds } ) ;
// 8. If abs(normalizedSeconds) โฅ 2**53, return false.
static auto maximum_time = Crypto : : SignedBigInteger { MAX_ARRAY_LIKE_INDEX } . plus ( Crypto : : SignedBigInteger { 1 } ) . multiplied_by ( seconds_to_nanoseconds ) ;
if ( normalized_nanoseconds . is_negative ( ) )
normalized_nanoseconds . negate ( ) ;
if ( normalized_nanoseconds > = maximum_time )
return false ;
2021-07-15 23:20:43 +01:00
// 3. Return true.
return true ;
}
}