15#ifndef IOX2_BB_DURATION_HPP
16#define IOX2_BB_DURATION_HPP
28namespace duration_literals {
31constexpr auto operator""_ns(
unsigned long long int value)
noexcept ->
Duration;
35constexpr auto operator""_us(
unsigned long long int value)
noexcept ->
Duration;
39constexpr auto operator""_ms(
unsigned long long int value)
noexcept ->
Duration;
43constexpr auto operator""_s(
unsigned long long int value)
noexcept ->
Duration;
47constexpr auto operator""_m(
unsigned long long int value)
noexcept ->
Duration;
51constexpr auto operator""_h(
unsigned long long int value)
noexcept ->
Duration;
55constexpr auto operator""_d(
unsigned long long int value)
noexcept ->
Duration;
87 static constexpr auto from_nanos(T value)
noexcept -> Duration;
95 static constexpr auto from_micros(T value)
noexcept -> Duration;
102 template <
typename T>
103 static constexpr auto from_millis(T value)
noexcept -> Duration;
110 template <
typename T>
111 static constexpr auto from_secs(T value)
noexcept -> Duration;
118 template <
typename T>
119 static constexpr auto from_mins(T value)
noexcept -> Duration;
126 template <
typename T>
127 static constexpr auto from_hours(T value)
noexcept -> Duration;
134 template <
typename T>
135 static constexpr auto from_days(T value)
noexcept -> Duration;
139 static constexpr auto max() noexcept -> Duration;
142 static constexpr auto
zero() noexcept -> Duration;
147 friend constexpr auto operator==(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
148 friend constexpr auto operator!=(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
149 friend constexpr auto operator<(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
150 friend constexpr auto operator<=(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
151 friend constexpr auto operator>(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
152 friend constexpr auto operator>=(const Duration& lhs, const Duration& rhs) noexcept ->
bool;
162 constexpr auto operator+(const Duration& rhs) const noexcept -> Duration;
168 constexpr auto operator+=(const Duration& rhs) noexcept -> Duration&;
175 constexpr auto operator-(const Duration& rhs) const noexcept -> Duration;
182 constexpr auto operator-=(const Duration& rhs) noexcept -> Duration&;
193 template <typename T>
194 constexpr auto operator*(const T& rhs) const noexcept -> Duration;
205 template <typename T>
206 constexpr auto operator*=(const T& rhs) noexcept -> Duration&;
215 constexpr auto
as_nanos() const noexcept -> uint64_t;
221 constexpr auto
as_micros() const noexcept -> uint64_t;
227 constexpr auto
as_millis() const noexcept -> uint64_t;
231 constexpr auto
as_secs() const noexcept -> uint64_t;
235 constexpr auto
as_mins() const noexcept -> uint64_t;
239 constexpr auto
as_hours() const noexcept -> uint64_t;
243 constexpr auto
as_days() const noexcept -> uint64_t;
246 constexpr auto
subsec_nanos() const noexcept -> uint32_t;
259 friend constexpr auto duration_literals::operator""_ns(
unsigned long long int value) noexcept ->
Duration;
260 friend constexpr auto duration_literals::operator""_us(
unsigned long long int value) noexcept ->
Duration;
261 friend constexpr auto duration_literals::operator""_ms(
unsigned long long int value) noexcept ->
Duration;
262 friend constexpr auto duration_literals::operator""_s(
unsigned long long int value) noexcept ->
Duration;
263 friend constexpr auto duration_literals::operator""_m(
unsigned long long int value) noexcept ->
Duration;
264 friend constexpr auto duration_literals::operator""_h(
unsigned long long int value) noexcept ->
Duration;
265 friend constexpr auto duration_literals::operator""_d(
unsigned long long int value) noexcept ->
Duration;
269 template <typename T>
270 friend constexpr auto operator*(const T& lhs, const
Duration& rhs) noexcept ->
Duration;
294 template <
typename T>
295 static constexpr auto positive_value_or_clamp_to_zero(T value)
noexcept -> uint64_t;
297 template <
typename T>
298 constexpr auto from_floating_point_seconds(T floating_point_seconds)
const noexcept ->
Duration;
299 template <
typename From,
typename To>
300 constexpr auto would_cast_from_floating_point_probably_overflow(
From floating_point)
const noexcept -> bool;
302 template <
typename T>
303 constexpr auto multiply_with(
const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs)
const noexcept
306 template <
typename T>
307 constexpr auto multiply_with(
const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs)
const noexcept
331 "Assigning the result of a Duration multiplication with 'operator*=' to an arithmetic type is not supported");
341 return (lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds == rhs.m_nanoseconds);
350 return !(lhs == rhs);
359 return (lhs.m_seconds < rhs.m_seconds)
360 || ((lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds < rhs.m_nanoseconds));
369 return (lhs.m_seconds > rhs.m_seconds)
370 || ((lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds > rhs.m_nanoseconds));
395 , m_nanoseconds(nanoseconds) {
396 if (nanoseconds >= NANOSECS_PER_SEC) {
398 /
static_cast<SecondsT>(NANOSECS_PER_SEC) };
399 if ((std::numeric_limits<SecondsT>::max() - additional_seconds) < m_seconds) {
400 m_seconds = std::numeric_limits<SecondsT>::max();
401 m_nanoseconds = NANOSECS_PER_SEC - 1U;
403 m_seconds += additional_seconds;
404 m_nanoseconds = m_nanoseconds % NANOSECS_PER_SEC;
410 return { seconds, nanoseconds };
422constexpr auto Duration::positive_value_or_clamp_to_zero(
const T value)
noexcept -> uint64_t {
423 static_assert(std::numeric_limits<T>::is_integer,
"only integer types are supported");
431 return static_cast<uint64_t
>(value);
436 const auto clamped_value = positive_value_or_clamp_to_zero(value);
439 return create_duration(seconds, nanoseconds);
443 const auto clamped_value = positive_value_or_clamp_to_zero(value);
447 return create_duration(seconds, nanoseconds);
451 const auto clamped_value = positive_value_or_clamp_to_zero(value);
455 return create_duration(seconds, nanoseconds);
459 const auto clamped_value = positive_value_or_clamp_to_zero(value);
460 constexpr Duration::SecondsT MAX_SECONDS_BEFORE_OVERFLOW { std::numeric_limits<Duration::SecondsT>::max() };
463 if (clamped_value > MAX_SECONDS_BEFORE_OVERFLOW) {
470 const auto clamped_value = positive_value_or_clamp_to_zero(value);
472 if (clamped_value > MAX_MINUTES_BEFORE_OVERFLOW) {
479 const auto clamped_value = positive_value_or_clamp_to_zero(value);
480 constexpr uint64_t MAX_HOURS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max() /
Duration::SECS_PER_HOUR };
481 if (clamped_value > MAX_HOURS_BEFORE_OVERFLOW) {
488 const auto clamped_value = positive_value_or_clamp_to_zero(value);
490 constexpr uint64_t MAX_DAYS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max() / SECS_PER_DAY };
491 if (clamped_value > MAX_DAYS_BEFORE_OVERFLOW) {
498 constexpr SecondsT MAX_SECONDS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max()
501 std::numeric_limits<uint64_t>::max() %
static_cast<uint64_t
>(
NANOSECS_PER_SEC)) };
503 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
505 if (*
this > MAX_DURATION_BEFORE_OVERFLOW) {
506 return std::numeric_limits<uint64_t>::max();
514 constexpr NanosecondsT MAX_NANOSECONDS_BEFORE_OVERFLOW {
518 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
520 if (*
this > MAX_DURATION_BEFORE_OVERFLOW) {
521 return std::numeric_limits<uint64_t>::max();
530 constexpr NanosecondsT MAX_NANOSECONDS_BEFORE_OVERFLOW {
534 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
536 if (*
this > MAX_DURATION_BEFORE_OVERFLOW) {
537 return std::numeric_limits<uint64_t>::max();
561 return m_nanoseconds;
574 SecondsT seconds { m_seconds + rhs.m_seconds };
575 NanosecondsT nanoseconds { m_nanoseconds + rhs.m_nanoseconds };
576 if (nanoseconds >= NANOSECS_PER_SEC) {
578 nanoseconds -= NANOSECS_PER_SEC;
581 const auto sum = create_duration(seconds, nanoseconds);
599 SecondsT seconds { m_seconds - rhs.m_seconds };
602 if (m_nanoseconds >= rhs.m_nanoseconds) {
603 nanoseconds = m_nanoseconds - rhs.m_nanoseconds;
606 nanoseconds = (NANOSECS_PER_SEC - rhs.m_nanoseconds) + m_nanoseconds;
609 return create_duration(seconds, nanoseconds);
619constexpr auto Duration::multiply_with(
const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs)
const noexcept
625 static_assert(
sizeof(T) <=
sizeof(SecondsT),
626 "only integer types with less or equal to size of uint64_t are allowed for multiplication");
627 const auto multiplicator =
static_cast<SecondsT
>(rhs);
629 const SecondsT max_before_overflow { std::numeric_limits<SecondsT>::max() / multiplicator };
632 if (m_seconds > max_before_overflow) {
635 const auto duration_from_seconds = Duration(m_seconds * multiplicator, 0U);
642 if (m_nanoseconds <= max_before_overflow) {
652 const uint64_t multiplicator_low {
static_cast<uint32_t
>(multiplicator) };
653 const Duration duration_from_nanos_low {
Duration::from_nanos(m_nanoseconds * multiplicator_low) };
668 constexpr uint64_t LEAST_COMMON_MULTIPLE { 8388608000000000 };
669 constexpr uint64_t NUMBER_OF_BITS_IN_UINT32 { 32 };
670 static_assert((LEAST_COMMON_MULTIPLE % (1ULL << NUMBER_OF_BITS_IN_UINT32)) == 0,
"invalid multiple");
671 static_assert((LEAST_COMMON_MULTIPLE % NANOSECS_PER_SEC) == 0,
"invalid multiple");
673 constexpr uint64_t ONE_FULL_BLOCK_OF_SECONDS_ONLY { LEAST_COMMON_MULTIPLE >> NUMBER_OF_BITS_IN_UINT32 };
674 constexpr uint64_t SECONDS_PER_FULL_BLOCK { LEAST_COMMON_MULTIPLE / NANOSECS_PER_SEC };
676 const uint64_t multiplicator_high {
static_cast<uint32_t
>(multiplicator >> NUMBER_OF_BITS_IN_UINT32) };
677 const uint64_t nanoseconds_from_high { m_nanoseconds * multiplicator_high };
678 const uint64_t full_blocks_of_seconds_only { nanoseconds_from_high / ONE_FULL_BLOCK_OF_SECONDS_ONLY };
679 const uint64_t remaining_block_with_full_and_fractional_seconds { nanoseconds_from_high
680 % ONE_FULL_BLOCK_OF_SECONDS_ONLY };
683 const auto duration_from_nanos_high =
684 Duration { full_blocks_of_seconds_only * SECONDS_PER_FULL_BLOCK, 0U }
685 +
Duration::from_nanos(remaining_block_with_full_and_fractional_seconds << NUMBER_OF_BITS_IN_UINT32);
687 return duration_from_seconds + duration_from_nanos_low + duration_from_nanos_high;
691template <
typename From,
typename To>
692constexpr auto Duration::would_cast_from_floating_point_probably_overflow(
const From floating_point)
const noexcept
694 static_assert(std::is_floating_point<From>::value,
"only floating point is allowed");
700 constexpr From SECONDS_BEFORE_LIKELY_OVERFLOW {
static_cast<From
>(std::numeric_limits<To>::max()) };
701 return floating_point >= SECONDS_BEFORE_LIKELY_OVERFLOW;
705constexpr auto Duration::from_floating_point_seconds(
const T floating_point_seconds)
const noexcept -> Duration {
706 static_assert(std::is_floating_point<T>::value,
"only floating point is allowed");
708 if (std::isinf(floating_point_seconds)) {
712 T seconds_full { 0 };
713 T seconds_fraction { std::modf(floating_point_seconds, &seconds_full) };
715 if (would_cast_from_floating_point_probably_overflow<T, SecondsT>(seconds_full)) {
719 return Duration {
static_cast<SecondsT
>(seconds_full),
720 static_cast<NanosecondsT
>(seconds_fraction * NANOSECS_PER_SEC) };
724constexpr auto Duration::multiply_with(
const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs)
const noexcept
726 if (std::isnan(rhs)) {
735 auto duration_from_seconds = from_floating_point_seconds<T>(
static_cast<T
>(m_seconds) * rhs);
737 auto result_nanoseconds =
static_cast<T
>(m_nanoseconds) * rhs;
739 if (!would_cast_from_floating_point_probably_overflow<T, uint64_t>(result_nanoseconds)) {
745 auto floating_point_seconds = result_nanoseconds / NANOSECS_PER_SEC;
746 auto duration_from_nanos = from_floating_point_seconds<T>(floating_point_seconds);
748 return duration_from_seconds + duration_from_nanos;
754 static_assert(std::is_arithmetic<T>::value,
"non arithmetic types are not supported for multiplication");
756 return multiply_with<T>(rhs);
761 static_assert(std::is_arithmetic<T>::value,
"non arithmetic types are not supported for multiplication");
763 *
this = multiply_with<T>(rhs);
768namespace duration_literals {
770constexpr auto operator""_ns(
unsigned long long int value)
noexcept ->
Duration {
775constexpr auto operator""_us(
unsigned long long int value)
noexcept ->
Duration {
780constexpr auto operator""_ms(
unsigned long long int value)
noexcept ->
Duration {
785constexpr auto operator""_s(
unsigned long long int value)
noexcept ->
Duration {
790constexpr auto operator""_m(
unsigned long long int value)
noexcept ->
Duration {
795constexpr auto operator""_h(
unsigned long long int value)
noexcept ->
Duration {
800constexpr auto operator""_d(
unsigned long long int value)
noexcept ->
Duration {
811 stream << duration.as_secs() <<
"s " << duration.subsec_nanos() <<
"ns";
817 stream << duration.as_secs() <<
"s " << duration.subsec_nanos() <<
"ns";
#define IOX2_MAYBE_UNUSED
IOX2_MAYBE_UNUSED adds the [[gnu::unused]] attribute when it is available for the current compiler or...
constexpr auto subsec_nanos() const noexcept -> uint32_t
returns the subsecond part of the duration in nanoseconds
static constexpr auto from_millis(T value) noexcept -> Duration
Constructs a new Duration object from milliseconds.
static constexpr uint32_t NANOSECS_PER_SEC
constexpr auto as_hours() const noexcept -> uint64_t
returns the duration in hours
static constexpr auto from_hours(T value) noexcept -> Duration
Constructs a new Duration object from hours.
constexpr auto as_nanos() const noexcept -> uint64_t
returns the duration in nanoseconds
static constexpr uint32_t MILLISECS_PER_SEC
constexpr auto as_micros() const noexcept -> uint64_t
returns the duration in microseconds
static constexpr auto from_secs(T value) noexcept -> Duration
Constructs a new Duration object from seconds.
static constexpr auto create_duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept -> Duration
constexpr auto operator+=(const Duration &rhs) noexcept -> Duration &
Adds a Duration to itself. On overflow duration saturates to Duration::max().
static constexpr auto max() noexcept -> Duration
Constructs a new Duration object of maximum allowed length. Useful for functions which should have an...
static constexpr auto from_days(T value) noexcept -> Duration
Constructs a new Duration object from days.
constexpr auto operator+(const Duration &rhs) const noexcept -> Duration
Creates Duration object by addition. On overflow duration saturates to Duration::max().
static constexpr uint32_t SECS_PER_MINUTE
static constexpr uint32_t MICROSECS_PER_SEC
constexpr Duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept
Constructs a Duration from seconds and nanoseconds.
static constexpr uint32_t SECS_PER_HOUR
static constexpr auto from_micros(T value) noexcept -> Duration
Constructs a new Duration object from microseconds.
constexpr auto operator-=(const Duration &rhs) noexcept -> Duration &
Subtracts a Duration from itself. On underflow duration saturates to Duration::zero().
constexpr auto subsec_millis() const noexcept -> uint32_t
returns the subsecond part of the duration in milliseconds
constexpr auto as_millis() const noexcept -> uint64_t
returns the duration in milliseconds
static constexpr auto zero() noexcept -> Duration
Constructs a new Duration object with a duration of zero.
static constexpr auto from_mins(T value) noexcept -> Duration
Constructs a new Duration object from minutes.
constexpr auto operator-(const Duration &rhs) const noexcept -> Duration
Creates Duration object by subtraction. On underflow duration saturates to Duration::zero().
constexpr auto subsec_micros() const noexcept -> uint32_t
returns the subsecond part of the duration in microseconds
constexpr auto as_mins() const noexcept -> uint64_t
returns the duration in minutes
static constexpr uint32_t HOURS_PER_DAY
static constexpr uint32_t NANOSECS_PER_MILLISEC
static constexpr uint32_t NANOSECS_PER_MICROSEC
constexpr auto as_secs() const noexcept -> uint64_t
returns the duration in seconds
static constexpr auto from_nanos(T value) noexcept -> Duration
Constructs a new Duration object from nanoseconds.
constexpr auto as_days() const noexcept -> uint64_t
returns the duration in days
constexpr auto operator*=(const T &rhs) noexcept -> Duration &
Multiplies a Duration with an arithmetic type and assigns the result to itself.
friend constexpr auto operator*(const T &lhs, const Duration &rhs) noexcept -> Duration
creates Duration object by multiplying object T with a duration. On overflow duration will saturate t...
This class provides the public interface to the logger and is used with the 'IOX2_LOG' macro....
auto operator<<(iox2::legacy::log::LogStream &stream, const iox2::bb::Duration duration) noexcept -> iox2::legacy::log::LogStream &
constexpr auto operator*=(T &lhs IOX2_MAYBE_UNUSED, const Duration &rhs IOX2_MAYBE_UNUSED) noexcept -> T &
Dummy implementation with a static assert. Assigning the result of a Duration multiplication with 'op...
constexpr auto operator*(const T &lhs, const Duration &rhs) noexcept -> Duration
creates Duration object by multiplying object T with a duration. On overflow duration will saturate t...
constexpr auto operator>(const Duration &lhs, const Duration &rhs) noexcept -> bool
Greater than operator.
constexpr auto operator<=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Less than or equal to operator.
constexpr auto operator!=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Not equal to operator.
constexpr auto operator==(const Duration &lhs, const Duration &rhs) noexcept -> bool
Equal to operator.
constexpr auto operator>=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Greater than or equal to operator.
constexpr auto operator<(const Duration &lhs, const Duration &rhs) noexcept -> bool
Less than operator.
constexpr bool always_false_v
Helper value to bind a static_assert to a type.