diff options
author | kleines Filmröllchen <filmroellchen@serenityos.org> | 2023-03-17 18:17:06 +0100 |
---|---|---|
committer | Jelle Raaijmakers <jelle@gmta.nl> | 2023-05-24 23:18:07 +0200 |
commit | 0dfcaf138904b8930af7f530b398791a448a2f91 (patch) | |
tree | 283b86f3268ff689331b44241399ad1f200b2484 | |
parent | 213025f210a785ca71b7659d7dc4f5dc3c030622 (diff) | |
download | serenity-0dfcaf138904b8930af7f530b398791a448a2f91.zip |
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.
-rw-r--r-- | AK/Time.cpp | 71 | ||||
-rw-r--r-- | AK/Time.h | 85 |
2 files changed, 76 insertions, 80 deletions
diff --git a/AK/Time.cpp b/AK/Time.cpp index 369226f3df..a1c5bd973e 100644 --- a/AK/Time.cpp +++ b/AK/Time.cpp @@ -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); @@ -8,6 +8,7 @@ #include <AK/Array.h> #include <AK/Assertions.h> +#include <AK/Checked.h> #include <AK/Platform.h> #include <AK/Types.h> @@ -142,16 +143,16 @@ constexpr i64 seconds_since_epoch_to_year(i64 seconds) // You should not be using this class directly to represent absolute time. class Duration { public: - Duration() = default; - Duration(Duration const&) = default; - Duration& operator=(Duration const&) = default; + constexpr Duration() = default; + constexpr Duration(Duration const&) = default; + constexpr Duration& operator=(Duration const&) = default; - Duration(Duration&& other) + constexpr Duration(Duration&& other) : m_seconds(exchange(other.m_seconds, 0)) , m_nanoseconds(exchange(other.m_nanoseconds, 0)) { } - Duration& operator=(Duration&& other) + constexpr Duration& operator=(Duration&& other) { if (this != &other) { m_seconds = exchange(other.m_seconds, 0); @@ -255,10 +256,76 @@ public: [[nodiscard]] bool is_zero() const { return (m_seconds == 0) && (m_nanoseconds == 0); } [[nodiscard]] bool is_negative() const { return m_seconds < 0; } - Duration operator+(Duration const& other) const; - Duration& operator+=(Duration const& other); - Duration operator-(Duration const& other) const; - Duration& operator-=(Duration const& other); + constexpr 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 }; + } + + constexpr Duration& operator+=(Duration const& other) + { + *this = *this + other; + return *this; + } + + constexpr 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 }; + } + + constexpr Duration& operator-=(Duration const& other) + { + *this = *this - other; + return *this; + } constexpr bool operator==(Duration const& other) const = default; constexpr int operator<=>(Duration const& other) const |