summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2023-03-17 18:17:06 +0100
committerJelle Raaijmakers <jelle@gmta.nl>2023-05-24 23:18:07 +0200
commit0dfcaf138904b8930af7f530b398791a448a2f91 (patch)
tree283b86f3268ff689331b44241399ad1f200b2484 /AK
parent213025f210a785ca71b7659d7dc4f5dc3c030622 (diff)
downloadserenity-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.
Diffstat (limited to 'AK')
-rw-r--r--AK/Time.cpp71
-rw-r--r--AK/Time.h85
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);
diff --git a/AK/Time.h b/AK/Time.h
index 2c1af84313..7eebb43508 100644
--- a/AK/Time.h
+++ b/AK/Time.h
@@ -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