1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 08:27:46 +00:00

AK: Make Duration arithmetic constexpr

This is a trivial change, and since this batch of commits will make a
large-scale rebuild necessary anyways, it seems sensible. The feature is
useful for e.g. building compound constant durations at compile time in
a readable way.
This commit is contained in:
kleines Filmröllchen 2023-03-17 18:17:06 +01:00 committed by Jelle Raaijmakers
parent 213025f210
commit 0dfcaf1389
2 changed files with 76 additions and 80 deletions

View file

@ -185,77 +185,6 @@ timeval Duration::to_timeval() const
return { static_cast<sec_type>(m_seconds), static_cast<usec_type>(m_nanoseconds) / 1000 };
}
Duration Duration::operator+(Duration const& other) const
{
VERIFY(m_nanoseconds < 1'000'000'000);
VERIFY(other.m_nanoseconds < 1'000'000'000);
u32 new_nsecs = m_nanoseconds + other.m_nanoseconds;
u32 extra_secs = new_nsecs / 1'000'000'000;
new_nsecs %= 1'000'000'000;
i64 this_secs = m_seconds;
i64 other_secs = other.m_seconds;
// We would like to just add "this_secs + other_secs + extra_secs".
// However, computing this naively may overflow even though the result is in-bounds.
// Example in 8-bit: (-127) + (-2) + (+1) = (-128), which fits in an i8.
// Example in 8-bit, the other way around: (-2) + (127) + (+1) = 126.
// So we do something more sophisticated:
if (extra_secs) {
VERIFY(extra_secs == 1);
if (this_secs != 0x7fff'ffff'ffff'ffff) {
this_secs += 1;
} else if (other_secs != 0x7fff'ffff'ffff'ffff) {
other_secs += 1;
} else {
/* If *both* are INT64_MAX, then adding them will overflow in any case. */
return Duration::max();
}
}
Checked<i64> new_secs { this_secs };
new_secs += other_secs;
if (new_secs.has_overflow()) {
if (other_secs > 0)
return Duration::max();
else
return Duration::min();
}
return Duration { new_secs.value(), new_nsecs };
}
Duration& Duration::operator+=(Duration const& other)
{
*this = *this + other;
return *this;
}
Duration Duration::operator-(Duration const& other) const
{
VERIFY(m_nanoseconds < 1'000'000'000);
VERIFY(other.m_nanoseconds < 1'000'000'000);
if (other.m_nanoseconds)
return *this + Duration((i64) ~(u64)other.m_seconds, 1'000'000'000 - other.m_nanoseconds);
if (other.m_seconds != (i64)-0x8000'0000'0000'0000)
return *this + Duration(-other.m_seconds, 0);
// Only remaining case: We want to subtract -0x8000'0000'0000'0000 seconds,
// i.e. add a very large number.
if (m_seconds >= 0)
return Duration::max();
return Duration { (m_seconds + 0x4000'0000'0000'0000) + 0x4000'0000'0000'0000, m_nanoseconds };
}
Duration& Duration::operator-=(Duration const& other)
{
*this = *this - other;
return *this;
}
Duration Duration::from_half_sanitized(i64 seconds, i32 extra_seconds, u32 nanoseconds)
{
VERIFY(nanoseconds < 1'000'000'000);