mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK: Simplify Duration::from_time_units and handle remainder overflow
Overflow could happen in the multiplication of the remainder seconds back into time units. Instead, take a remainder of the time units from the division and use that for the nanoseconds.
This commit is contained in:
committed by
Gregory Bertilson
parent
586da4e610
commit
affbe61da0
Notes:
github-actions[bot]
2026-04-16 20:09:41 +00:00
Author: https://github.com/Zaggy1024 Commit: https://github.com/LadybirdBrowser/ladybird/commit/affbe61da08 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8936
23
AK/Time.cpp
23
AK/Time.cpp
@@ -73,18 +73,19 @@ Duration Duration::from_time_units(i64 time_units, u32 numerator, u32 denominato
|
||||
VERIFY(numerator != 0);
|
||||
VERIFY(denominator != 0);
|
||||
|
||||
auto seconds_checked = Checked<i64>(time_units);
|
||||
seconds_checked.mul(numerator);
|
||||
seconds_checked.div(denominator);
|
||||
if (time_units < 0)
|
||||
seconds_checked.sub(1);
|
||||
|
||||
if (seconds_checked.has_overflow())
|
||||
if (Checked<i64>::multiplication_would_overflow(time_units, numerator))
|
||||
return Duration(time_units >= 0 ? NumericLimits<i64>::max() : NumericLimits<i64>::min(), 0);
|
||||
auto seconds = seconds_checked.value_unchecked();
|
||||
auto seconds_in_time_units = seconds * denominator / numerator;
|
||||
auto remainder_in_time_units = time_units - seconds_in_time_units;
|
||||
auto nanoseconds = ((remainder_in_time_units * 1'000'000'000 * numerator) + (denominator / 2)) / denominator;
|
||||
auto time_units_product = time_units * numerator;
|
||||
auto seconds = time_units_product / denominator;
|
||||
auto time_units_remainder = time_units_product % denominator;
|
||||
if (time_units_remainder < 0) {
|
||||
if (seconds == NumericLimits<i64>::min())
|
||||
return Duration(NumericLimits<i64>::min(), 0);
|
||||
seconds--;
|
||||
time_units_remainder += denominator;
|
||||
}
|
||||
|
||||
auto nanoseconds = ((time_units_remainder * 1'000'000'000) + (denominator / 2)) / denominator;
|
||||
if (nanoseconds == 1'000'000'000) {
|
||||
seconds++;
|
||||
nanoseconds = 0;
|
||||
|
||||
@@ -961,6 +961,13 @@ TEST_CASE(time_units)
|
||||
|
||||
EXPECT_EQ(Duration::from_time_units(-43776, 1, 14592), Duration::from_seconds(-3));
|
||||
|
||||
EXPECT_EQ(Duration::from_time_units(NumericLimits<i64>::min(), 1, 2), Duration::from_seconds(NumericLimits<i64>::min() / 2));
|
||||
EXPECT_EQ(Duration::from_time_units(NumericLimits<i64>::min() + 1, 1, 2), Duration::from_seconds(NumericLimits<i64>::min() / 2) + Duration::from_milliseconds(500));
|
||||
EXPECT_EQ(Duration::from_time_units(NumericLimits<i64>::min(), 1, 3), Duration::from_seconds(NumericLimits<i64>::min() / 3) - Duration::from_nanoseconds(666'666'667));
|
||||
|
||||
EXPECT_EQ(Duration::from_time_units(-1, 1, 2'000'000'000), Duration::zero());
|
||||
EXPECT_EQ(Duration::from_time_units(-2, 1, 2'000'000'000), Duration::from_nanoseconds(-1));
|
||||
|
||||
EXPECT_EQ(Duration::from_milliseconds(999).to_time_units(1, 48'000), 47'952);
|
||||
EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500);
|
||||
EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500);
|
||||
|
||||
Reference in New Issue
Block a user