iceoryx2
C++ Language Bindings
Loading...
Searching...
No Matches
duration.hpp
Go to the documentation of this file.
1// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
2// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved.
3// Copyright (c) 2025 Contributors to the Eclipse Foundation
4//
5// See the NOTICE file(s) distributed with this work for additional
6// information regarding copyright ownership.
7//
8// This program and the accompanying materials are made available under the
9// terms of the Apache Software License 2.0 which is available at
10// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
11// which is available at https://opensource.org/licenses/MIT.
12//
13// SPDX-License-Identifier: Apache-2.0 OR MIT
14
15#ifndef IOX2_BB_DURATION_HPP
16#define IOX2_BB_DURATION_HPP
17
21
22#include <cmath>
23
24namespace iox2 {
25namespace bb {
26class Duration;
27
28namespace duration_literals {
30// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
31constexpr auto operator""_ns(unsigned long long int value) noexcept -> Duration;
32
34// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
35constexpr auto operator""_us(unsigned long long int value) noexcept -> Duration;
36
38// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
39constexpr auto operator""_ms(unsigned long long int value) noexcept -> Duration;
40
42// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
43constexpr auto operator""_s(unsigned long long int value) noexcept -> Duration;
44
46// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
47constexpr auto operator""_m(unsigned long long int value) noexcept -> Duration;
48
50// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
51constexpr auto operator""_h(unsigned long long int value) noexcept -> Duration;
52
54// AXIVION Next Line AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
55constexpr auto operator""_d(unsigned long long int value) noexcept -> Duration;
56} // namespace duration_literals
57
69class Duration {
70 protected:
71 using SecondsT = uint64_t;
72 using NanosecondsT = uint32_t;
73
74 private:
75 SecondsT m_seconds { 0U };
76 NanosecondsT m_nanoseconds { 0U };
77
78 public:
79 // BEGIN CREATION FROM STATIC FUNCTIONS
80
86 template <typename T>
87 static constexpr auto from_nanos(T value) noexcept -> Duration;
88
94 template <typename T>
95 static constexpr auto from_micros(T value) noexcept -> Duration;
96
102 template <typename T>
103 static constexpr auto from_millis(T value) noexcept -> Duration;
104
110 template <typename T>
111 static constexpr auto from_secs(T value) noexcept -> Duration;
112
118 template <typename T>
119 static constexpr auto from_mins(T value) noexcept -> Duration;
120
126 template <typename T>
127 static constexpr auto from_hours(T value) noexcept -> Duration;
128
134 template <typename T>
135 static constexpr auto from_days(T value) noexcept -> Duration;
136
139 static constexpr auto max() noexcept -> Duration;
140
142 static constexpr auto zero() noexcept -> Duration;
143 // END CREATION FROM STATIC FUNCTIONS
144
145 // BEGIN COMPARISON
146 // AXIVION DISABLE STYLE AutosarC++19_03-A8.4.7 : Each argument is larger than two words
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;
153 // AXIVION ENABLE STYLE AutosarC++19_03-A8.4.7
154 // END COMPARISON
155
156 // BEGIN ARITHMETIC
157
161 // AXIVION Next Line AutosarC++19_03-A8.4.7 : Argument is larger than two words
162 constexpr auto operator+(const Duration& rhs) const noexcept -> Duration;
163
167 // AXIVION Next Line AutosarC++19_03-A8.4.7 : Argument is larger than two words
168 constexpr auto operator+=(const Duration& rhs) noexcept -> Duration&;
169
174 // AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
175 constexpr auto operator-(const Duration& rhs) const noexcept -> Duration;
176
181 // AXIVION Next Line AutosarC++19_03-A8.4.7 : Argument is larger than two words
182 constexpr auto operator-=(const Duration& rhs) noexcept -> Duration&;
183
193 template <typename T>
194 constexpr auto operator*(const T& rhs) const noexcept -> Duration;
195
205 template <typename T>
206 constexpr auto operator*=(const T& rhs) noexcept -> Duration&;
207
208 // END ARITHMETIC
209
210 // BEGIN CONVERSION
211
215 constexpr auto as_nanos() const noexcept -> uint64_t;
216
221 constexpr auto as_micros() const noexcept -> uint64_t;
222
227 constexpr auto as_millis() const noexcept -> uint64_t;
228
231 constexpr auto as_secs() const noexcept -> uint64_t;
232
235 constexpr auto as_mins() const noexcept -> uint64_t;
236
239 constexpr auto as_hours() const noexcept -> uint64_t;
240
243 constexpr auto as_days() const noexcept -> uint64_t;
244
246 constexpr auto subsec_nanos() const noexcept -> uint32_t;
247
250 constexpr auto subsec_micros() const noexcept -> uint32_t;
251
254 constexpr auto subsec_millis() const noexcept -> uint32_t;
255
256 // END CONVERSION
257
258 // AXIVION DISABLE STYLE AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
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;
266 // AXIVION ENABLE STYLE AutosarC++19_03-A3.9.1
267
268 // AXIVION Next Construct AutosarC++19_03-A8.4.7 : Argument is larger than two words
269 template <typename T>
270 friend constexpr auto operator*(const T& lhs, const Duration& rhs) noexcept -> Duration;
271
272 static constexpr uint32_t SECS_PER_MINUTE { 60U };
273 static constexpr uint32_t SECS_PER_HOUR { 3600U };
274 static constexpr uint32_t HOURS_PER_DAY { 24U };
275
276 static constexpr uint32_t MILLISECS_PER_SEC { 1000U };
277 static constexpr uint32_t MICROSECS_PER_SEC { MILLISECS_PER_SEC * 1000U };
278
279 static constexpr uint32_t NANOSECS_PER_MICROSEC { 1000U };
280 static constexpr uint32_t NANOSECS_PER_MILLISEC { NANOSECS_PER_MICROSEC * 1000U };
281 static constexpr uint32_t NANOSECS_PER_SEC { NANOSECS_PER_MILLISEC * 1000U };
282
287 constexpr Duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept;
288
291 static constexpr auto create_duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept -> Duration;
292
293 private:
294 template <typename T>
295 static constexpr auto positive_value_or_clamp_to_zero(T value) noexcept -> uint64_t;
296
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;
301
302 template <typename T>
303 constexpr auto multiply_with(const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs) const noexcept
304 -> Duration;
305
306 template <typename T>
307 constexpr auto multiply_with(const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs) const noexcept
308 -> Duration;
309};
310
318// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Each argument is larger than two words
319template <typename T>
320constexpr auto operator*(const T& lhs, const Duration& rhs) noexcept -> Duration {
321 return rhs * lhs;
322}
323
326// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Each argument is larger than two words
327template <typename T>
328constexpr auto operator*=(T& lhs IOX2_MAYBE_UNUSED, const Duration& rhs IOX2_MAYBE_UNUSED) noexcept -> T& {
329 static_assert(
331 "Assigning the result of a Duration multiplication with 'operator*=' to an arithmetic type is not supported");
332 return T();
333}
334
339// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
340constexpr auto operator==(const Duration& lhs, const Duration& rhs) noexcept -> bool {
341 return (lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds == rhs.m_nanoseconds);
342}
343
348// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
349constexpr auto operator!=(const Duration& lhs, const Duration& rhs) noexcept -> bool {
350 return !(lhs == rhs);
351}
352
357// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
358constexpr auto operator<(const Duration& lhs, const Duration& rhs) noexcept -> bool {
359 return (lhs.m_seconds < rhs.m_seconds)
360 || ((lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds < rhs.m_nanoseconds));
361}
362
367// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
368constexpr auto operator>(const Duration& lhs, const Duration& rhs) noexcept -> bool {
369 return (lhs.m_seconds > rhs.m_seconds)
370 || ((lhs.m_seconds == rhs.m_seconds) && (lhs.m_nanoseconds > rhs.m_nanoseconds));
371}
372
377// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
378constexpr auto operator<=(const Duration& lhs, const Duration& rhs) noexcept -> bool {
379 return !(lhs > rhs);
380}
381
386// AXIVION Next Line AutosarC++19_03-A8.4.7 : Each argument is larger than two words
387constexpr auto operator>=(const Duration& lhs, const Duration& rhs) noexcept -> bool {
388 return !(lhs < rhs);
389}
390
391// NOLINTJUSTIFICATION @todo iox-#1617 Seconds_t and Nanoseconds_t should use Newtype pattern to solve this issue
392// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
393constexpr Duration::Duration(const SecondsT seconds, const NanosecondsT nanoseconds) noexcept
394 : m_seconds(seconds)
395 , m_nanoseconds(nanoseconds) {
396 if (nanoseconds >= NANOSECS_PER_SEC) {
397 const SecondsT additional_seconds { static_cast<SecondsT>(nanoseconds)
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;
402 } else {
403 m_seconds += additional_seconds;
404 m_nanoseconds = m_nanoseconds % NANOSECS_PER_SEC;
405 }
406 }
407}
408
409constexpr auto Duration::create_duration(const SecondsT seconds, const NanosecondsT nanoseconds) noexcept -> Duration {
410 return { seconds, nanoseconds };
411}
412
413constexpr auto Duration::max() noexcept -> Duration {
414 return Duration { std::numeric_limits<SecondsT>::max(), NANOSECS_PER_SEC - 1U };
415}
416
417constexpr auto Duration::zero() noexcept -> Duration {
418 return Duration { 0U, 0U };
419}
420
421template <typename T>
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");
424
425 // AXIVION Next Construct AutosarC++19_03-A1.4.3 : Value is a templated an arbitrary integer
426 // type that is not necessarily unsigned
427 if (value < 0) {
428 return 0U;
429 }
430
431 return static_cast<uint64_t>(value);
432}
433
434template <typename T>
435constexpr auto Duration::from_nanos(const T value) noexcept -> Duration {
436 const auto clamped_value = positive_value_or_clamp_to_zero(value);
437 const auto seconds = static_cast<Duration::SecondsT>(clamped_value / Duration::NANOSECS_PER_SEC);
438 const auto nanoseconds = static_cast<Duration::NanosecondsT>(clamped_value % Duration::NANOSECS_PER_SEC);
439 return create_duration(seconds, nanoseconds);
440}
441template <typename T>
442constexpr auto Duration::from_micros(const T value) noexcept -> Duration {
443 const auto clamped_value = positive_value_or_clamp_to_zero(value);
444 const auto seconds = static_cast<Duration::SecondsT>(clamped_value / Duration::MICROSECS_PER_SEC);
445 const auto nanoseconds = static_cast<Duration::NanosecondsT>((clamped_value % Duration::MICROSECS_PER_SEC)
447 return create_duration(seconds, nanoseconds);
448}
449template <typename T>
450constexpr auto Duration::from_millis(const T value) noexcept -> Duration {
451 const auto clamped_value = positive_value_or_clamp_to_zero(value);
452 const auto seconds = static_cast<Duration::SecondsT>(clamped_value / Duration::MILLISECS_PER_SEC);
453 const auto nanoseconds = static_cast<Duration::NanosecondsT>((clamped_value % Duration::MILLISECS_PER_SEC)
455 return create_duration(seconds, nanoseconds);
456}
457template <typename T>
458constexpr auto Duration::from_secs(const T value) noexcept -> Duration {
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() };
461
462 // AXIVION Next Construct AutosarC++19_03-M0.1.2, AutosarC++19_03-M0.1.9, FaultDetection-DeadBranches : False positive, platform-dependent
463 if (clamped_value > MAX_SECONDS_BEFORE_OVERFLOW) {
464 return Duration::max();
465 }
466 return Duration { static_cast<Duration::SecondsT>(clamped_value), 0U };
467}
468template <typename T>
469constexpr auto Duration::from_mins(const T value) noexcept -> Duration {
470 const auto clamped_value = positive_value_or_clamp_to_zero(value);
471 constexpr uint64_t MAX_MINUTES_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max() / Duration::SECS_PER_MINUTE };
472 if (clamped_value > MAX_MINUTES_BEFORE_OVERFLOW) {
473 return Duration::max();
474 }
475 return Duration { static_cast<Duration::SecondsT>(clamped_value * Duration::SECS_PER_MINUTE), 0U };
476}
477template <typename T>
478constexpr auto Duration::from_hours(const T value) noexcept -> Duration {
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) {
482 return Duration::max();
483 }
484 return Duration { static_cast<Duration::SecondsT>(clamped_value * Duration::SECS_PER_HOUR), 0U };
485}
486template <typename T>
487constexpr auto Duration::from_days(const T value) noexcept -> Duration {
488 const auto clamped_value = positive_value_or_clamp_to_zero(value);
489 constexpr uint64_t SECS_PER_DAY { static_cast<uint64_t>(Duration::HOURS_PER_DAY * Duration::SECS_PER_HOUR) };
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) {
492 return Duration::max();
493 }
494 return Duration { static_cast<Duration::SecondsT>(clamped_value * SECS_PER_DAY), 0U };
495}
496
497constexpr auto Duration::as_nanos() const noexcept -> uint64_t {
498 constexpr SecondsT MAX_SECONDS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max()
499 / static_cast<uint64_t>(NANOSECS_PER_SEC) };
500 constexpr NanosecondsT MAX_NANOSECONDS_BEFORE_OVERFLOW { static_cast<NanosecondsT>(
501 std::numeric_limits<uint64_t>::max() % static_cast<uint64_t>(NANOSECS_PER_SEC)) };
502 constexpr Duration MAX_DURATION_BEFORE_OVERFLOW { create_duration(MAX_SECONDS_BEFORE_OVERFLOW,
503 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
504
505 if (*this > MAX_DURATION_BEFORE_OVERFLOW) {
506 return std::numeric_limits<uint64_t>::max();
507 }
508
509 return (m_seconds * NANOSECS_PER_SEC) + m_nanoseconds;
510}
511
512constexpr auto Duration::as_micros() const noexcept -> uint64_t {
513 constexpr SecondsT MAX_SECONDS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max() / MICROSECS_PER_SEC };
514 constexpr NanosecondsT MAX_NANOSECONDS_BEFORE_OVERFLOW {
515 static_cast<NanosecondsT>(std::numeric_limits<uint64_t>::max() % MICROSECS_PER_SEC) * NANOSECS_PER_MICROSEC
516 };
517 constexpr Duration MAX_DURATION_BEFORE_OVERFLOW { create_duration(MAX_SECONDS_BEFORE_OVERFLOW,
518 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
519
520 if (*this > MAX_DURATION_BEFORE_OVERFLOW) {
521 return std::numeric_limits<uint64_t>::max();
522 }
523
524 return (m_seconds * MICROSECS_PER_SEC)
525 + (static_cast<SecondsT>(m_nanoseconds) / static_cast<SecondsT>(NANOSECS_PER_MICROSEC));
526}
527
528constexpr auto Duration::as_millis() const noexcept -> uint64_t {
529 constexpr SecondsT MAX_SECONDS_BEFORE_OVERFLOW { std::numeric_limits<uint64_t>::max() / MILLISECS_PER_SEC };
530 constexpr NanosecondsT MAX_NANOSECONDS_BEFORE_OVERFLOW {
531 static_cast<NanosecondsT>(std::numeric_limits<uint64_t>::max() % MILLISECS_PER_SEC) * NANOSECS_PER_MILLISEC
532 };
533 constexpr Duration MAX_DURATION_BEFORE_OVERFLOW { create_duration(MAX_SECONDS_BEFORE_OVERFLOW,
534 MAX_NANOSECONDS_BEFORE_OVERFLOW) };
535
536 if (*this > MAX_DURATION_BEFORE_OVERFLOW) {
537 return std::numeric_limits<uint64_t>::max();
538 }
539
540 return (m_seconds * MILLISECS_PER_SEC)
541 + (static_cast<SecondsT>(m_nanoseconds) / static_cast<SecondsT>(NANOSECS_PER_MILLISEC));
542}
543
544constexpr auto Duration::as_secs() const noexcept -> uint64_t {
545 return m_seconds;
546}
547
548constexpr auto Duration::as_mins() const noexcept -> uint64_t {
549 return m_seconds / SECS_PER_MINUTE;
550}
551
552constexpr auto Duration::as_hours() const noexcept -> uint64_t {
553 return m_seconds / SECS_PER_HOUR;
554}
555
556constexpr auto Duration::as_days() const noexcept -> uint64_t {
557 return m_seconds / static_cast<uint64_t>(HOURS_PER_DAY * SECS_PER_HOUR);
558}
559
560constexpr auto Duration::subsec_nanos() const noexcept -> uint32_t {
561 return m_nanoseconds;
562}
563
564constexpr auto Duration::subsec_micros() const noexcept -> uint32_t {
565 return m_nanoseconds / NANOSECS_PER_MICROSEC;
566}
567
568constexpr auto Duration::subsec_millis() const noexcept -> uint32_t {
569 return m_nanoseconds / NANOSECS_PER_MILLISEC;
570}
571
572// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Argument is larger than two words
573constexpr auto Duration::operator+(const Duration& rhs) const noexcept -> Duration {
574 SecondsT seconds { m_seconds + rhs.m_seconds };
575 NanosecondsT nanoseconds { m_nanoseconds + rhs.m_nanoseconds };
576 if (nanoseconds >= NANOSECS_PER_SEC) {
577 ++seconds;
578 nanoseconds -= NANOSECS_PER_SEC;
579 }
580
581 const auto sum = create_duration(seconds, nanoseconds);
582 if (sum < *this) {
583 return Duration::max();
584 }
585 return sum;
586}
587
588// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Argument is larger than two words
589constexpr auto Duration::operator+=(const Duration& rhs) noexcept -> Duration& {
590 *this = *this + rhs;
591 return *this;
592}
593
594// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Argument is larger than two words
595constexpr auto Duration::operator-(const Duration& rhs) const noexcept -> Duration {
596 if (*this < rhs) {
597 return Duration::zero();
598 }
599 SecondsT seconds { m_seconds - rhs.m_seconds };
600 // AXIVION Next Construct AutosarC++19_03-M0.1.9, AutosarC++19_03-A0.1.1, FaultDetection-UnusedAssignments : False positive, variable IS used
601 NanosecondsT nanoseconds { 0U };
602 if (m_nanoseconds >= rhs.m_nanoseconds) {
603 nanoseconds = m_nanoseconds - rhs.m_nanoseconds;
604 } else {
605 // AXIVION Next Construct AutosarC++19_03-A4.7.1, AutosarC++19_03-M0.3.1, FaultDetection-IntegerOverflow : It is ensured that m_nanoseconds is never larger than NANOSECS_PER_SEC
606 nanoseconds = (NANOSECS_PER_SEC - rhs.m_nanoseconds) + m_nanoseconds;
607 --seconds;
608 }
609 return create_duration(seconds, nanoseconds);
610}
611
612// AXIVION Next Construct AutosarC++19_03-A8.4.7 : Argument is larger than two words
613constexpr auto Duration::operator-=(const Duration& rhs) noexcept -> Duration& {
614 *this = *this - rhs;
615 return *this;
616}
617
618template <typename T>
619constexpr auto Duration::multiply_with(const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs) const noexcept
620 -> Duration {
621 if ((rhs <= static_cast<T>(0)) || (*this == Duration::zero())) {
622 return Duration::zero();
623 }
624
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);
628
629 const SecondsT max_before_overflow { std::numeric_limits<SecondsT>::max() / multiplicator };
630
631 // check if the result of the m_seconds multiplication would already overflow
632 if (m_seconds > max_before_overflow) {
633 return Duration::max();
634 }
635 const auto duration_from_seconds = Duration(m_seconds * multiplicator, 0U);
636
637 // the m_nanoseconds multiplication cannot exceed the limits of a Duration, since m_nanoseconds is always less than
638 // a second and m_seconds can hold 64 bits and the multiplicator is at max 64 bits
639
640 // check if the result of the m_nanoseconds multiplication can easily be converted into a Duration
641 // AXIVION Next Construct AutosarC++19_03-M0.1.2, AutosarC++19_03-M0.1.9, FaultDetection-DeadBranches : False positive! Branching depends on input parameter
642 if (m_nanoseconds <= max_before_overflow) {
643 return duration_from_seconds + Duration::from_nanos(m_nanoseconds * multiplicator);
644 }
645
646 // when we reach this, the multiplicator must be larger than 2^32, since smaller values multiplied with the
647 // m_nanoseconds(uint32_t) would fit into 64 bits;
648 // to accurately determine the result, the calculation is split into a multiplication with the lower 32 bits of the
649 // multiplicator and another one with the upper 32 bits;
650
651 // this is the easy part with the lower 32 bits
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) };
654
655 // this is the complicated part with the upper 32 bits;
656 // the m_nanoseconds are multiplied with the upper 32 bits of the multiplicator shifted by 32 bit to the right, thus
657 // having again a multiplication of two 32 bit values whose result fits into a 64 bit variable;
658 // one bit of the result represents 2^32 nanoseconds;
659 // just shifting left by 32 bits would result in an overflow, therefore blocks of full seconds must be extracted of
660 // the result;
661 // this cannot be done by dividing through NANOSECS_PER_SEC, since that one is base 1_000_000_000 and the result is
662 // base 2^32, therefore the least common multiple can be used to get blocks of full seconds represented with the LSB
663 // representing 2^32 nanoseconds;
664 // this can then safely be converted to seconds as well as nanoseconds without loosing precision
665
666 // least common multiple of 2^32 and NANOSECONDS_PER_SECOND;
667 // for the following calculation it is not important to be the least common multiple, any common multiple will do
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");
672
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 };
675
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 };
681
682 // AXIVION Next Construct AutosarC++19_03-A4.7.1, AutosarC++19_03-M0.3.1, FaultDetection-IntegerOverflow : The logic from above prevents overflows
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);
686
687 return duration_from_seconds + duration_from_nanos_low + duration_from_nanos_high;
688}
689
690
691template <typename From, typename To>
692constexpr auto Duration::would_cast_from_floating_point_probably_overflow(const From floating_point) const noexcept
693 -> bool {
694 static_assert(std::is_floating_point<From>::value, "only floating point is allowed");
695
696 // depending on the internal representation this could be either the last value to not cause an overflow
697 // or the first one which causes an overflow;
698 // to be safe, this is handled like causing an overflow which would result in undefined behavior when casting to
699 // Seconds_t
700 constexpr From SECONDS_BEFORE_LIKELY_OVERFLOW { static_cast<From>(std::numeric_limits<To>::max()) };
701 return floating_point >= SECONDS_BEFORE_LIKELY_OVERFLOW;
702}
703
704template <typename T>
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");
707
708 if (std::isinf(floating_point_seconds)) {
709 return Duration::max();
710 }
711
712 T seconds_full { 0 };
713 T seconds_fraction { std::modf(floating_point_seconds, &seconds_full) };
714
715 if (would_cast_from_floating_point_probably_overflow<T, SecondsT>(seconds_full)) {
716 return Duration::max();
717 }
718
719 return Duration { static_cast<SecondsT>(seconds_full),
720 static_cast<NanosecondsT>(seconds_fraction * NANOSECS_PER_SEC) };
721}
722
723template <typename T>
724constexpr auto Duration::multiply_with(const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs) const noexcept
725 -> Duration {
726 if (std::isnan(rhs)) {
727 return (*this == Duration::zero()) ? Duration::zero() : Duration::max();
728 }
729
730 // this must be done after the NAN check in order to prevent to access a signaling NAN
731 if ((rhs <= static_cast<T>(0)) || (*this == Duration::zero())) {
732 return Duration::zero();
733 }
734
735 auto duration_from_seconds = from_floating_point_seconds<T>(static_cast<T>(m_seconds) * rhs);
736
737 auto result_nanoseconds = static_cast<T>(m_nanoseconds) * rhs;
738
739 if (!would_cast_from_floating_point_probably_overflow<T, uint64_t>(result_nanoseconds)) {
740 return duration_from_seconds + Duration::from_nanos(static_cast<uint64_t>(result_nanoseconds));
741 }
742
743 // the multiplication result of nanoseconds would exceed the value an uint64_t can represent
744 // -> convert result to seconds and and calculate duration
745 auto floating_point_seconds = result_nanoseconds / NANOSECS_PER_SEC;
746 auto duration_from_nanos = from_floating_point_seconds<T>(floating_point_seconds);
747
748 return duration_from_seconds + duration_from_nanos;
749}
750
751// AXIVION Next Construct AutosarC++19_03-M5.17.1 : False positive! Corresponding assignment operator is implemented below
752template <typename T>
753constexpr auto Duration::operator*(const T& rhs) const noexcept -> Duration {
754 static_assert(std::is_arithmetic<T>::value, "non arithmetic types are not supported for multiplication");
755
756 return multiply_with<T>(rhs);
757}
758
759template <typename T>
760constexpr auto Duration::operator*=(const T& rhs) noexcept -> Duration& {
761 static_assert(std::is_arithmetic<T>::value, "non arithmetic types are not supported for multiplication");
762
763 *this = multiply_with<T>(rhs);
764
765 return *this;
766}
767
768namespace duration_literals {
769// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
770constexpr auto operator""_ns(unsigned long long int value) noexcept -> Duration {
771 return Duration::from_nanos(value);
772}
773
774// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
775constexpr auto operator""_us(unsigned long long int value) noexcept -> Duration {
776 return Duration::from_micros(value);
777}
778
779// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
780constexpr auto operator""_ms(unsigned long long int value) noexcept -> Duration {
781 return Duration::from_millis(value);
782}
783
784// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
785constexpr auto operator""_s(unsigned long long int value) noexcept -> Duration {
786 return Duration::from_secs(value);
787}
788
789// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
790constexpr auto operator""_m(unsigned long long int value) noexcept -> Duration {
791 return Duration::from_mins(value);
792}
793
794// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
795constexpr auto operator""_h(unsigned long long int value) noexcept -> Duration {
796 return Duration::from_hours(value);
797}
798
799// AXIVION Next Construct AutosarC++19_03-A3.9.1 : Use of unsigned long long int in user-defined literals is enforced by the standard
800constexpr auto operator""_d(unsigned long long int value) noexcept -> Duration {
801 return Duration::from_days(value);
802}
803} // namespace duration_literals
804
805} // namespace bb
806} // namespace iox2
807
808// AXIVION Next Construct AutosarC++19_03-M5.17.1 : This is not used as shift operator but as stream operator and does not require to implement '<<='
809inline auto operator<<(iox2::legacy::log::LogStream& stream, const iox2::bb::Duration duration) noexcept
811 stream << duration.as_secs() << "s " << duration.subsec_nanos() << "ns";
812 return stream;
813}
814
815// AXIVION Next Construct AutosarC++19_03-M5.17.1 : This is not used as shift operator but as stream operator and does not require to implement '<<='
816inline auto operator<<(std::ostream& stream, const iox2::bb::Duration duration) -> std::ostream& {
817 stream << duration.as_secs() << "s " << duration.subsec_nanos() << "ns";
818 return stream;
819}
820
821#endif // IOX2_BB_DURATION_HPP
#define IOX2_MAYBE_UNUSED
IOX2_MAYBE_UNUSED adds the [[gnu::unused]] attribute when it is available for the current compiler or...
uint32_t NanosecondsT
Definition duration.hpp:72
constexpr auto subsec_nanos() const noexcept -> uint32_t
returns the subsecond part of the duration in nanoseconds
Definition duration.hpp:560
static constexpr auto from_millis(T value) noexcept -> Duration
Constructs a new Duration object from milliseconds.
Definition duration.hpp:450
static constexpr uint32_t NANOSECS_PER_SEC
Definition duration.hpp:281
constexpr auto as_hours() const noexcept -> uint64_t
returns the duration in hours
Definition duration.hpp:552
static constexpr auto from_hours(T value) noexcept -> Duration
Constructs a new Duration object from hours.
Definition duration.hpp:478
constexpr auto as_nanos() const noexcept -> uint64_t
returns the duration in nanoseconds
Definition duration.hpp:497
static constexpr uint32_t MILLISECS_PER_SEC
Definition duration.hpp:276
constexpr auto as_micros() const noexcept -> uint64_t
returns the duration in microseconds
Definition duration.hpp:512
static constexpr auto from_secs(T value) noexcept -> Duration
Constructs a new Duration object from seconds.
Definition duration.hpp:458
static constexpr auto create_duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept -> Duration
Definition duration.hpp:409
constexpr auto operator+=(const Duration &rhs) noexcept -> Duration &
Adds a Duration to itself. On overflow duration saturates to Duration::max().
Definition duration.hpp:589
static constexpr auto max() noexcept -> Duration
Constructs a new Duration object of maximum allowed length. Useful for functions which should have an...
Definition duration.hpp:413
static constexpr auto from_days(T value) noexcept -> Duration
Constructs a new Duration object from days.
Definition duration.hpp:487
constexpr auto operator+(const Duration &rhs) const noexcept -> Duration
Creates Duration object by addition. On overflow duration saturates to Duration::max().
Definition duration.hpp:573
static constexpr uint32_t SECS_PER_MINUTE
Definition duration.hpp:272
static constexpr uint32_t MICROSECS_PER_SEC
Definition duration.hpp:277
constexpr Duration(SecondsT seconds, NanosecondsT nanoseconds) noexcept
Constructs a Duration from seconds and nanoseconds.
Definition duration.hpp:393
static constexpr uint32_t SECS_PER_HOUR
Definition duration.hpp:273
static constexpr auto from_micros(T value) noexcept -> Duration
Constructs a new Duration object from microseconds.
Definition duration.hpp:442
constexpr auto operator-=(const Duration &rhs) noexcept -> Duration &
Subtracts a Duration from itself. On underflow duration saturates to Duration::zero().
Definition duration.hpp:613
constexpr auto subsec_millis() const noexcept -> uint32_t
returns the subsecond part of the duration in milliseconds
Definition duration.hpp:568
constexpr auto as_millis() const noexcept -> uint64_t
returns the duration in milliseconds
Definition duration.hpp:528
static constexpr auto zero() noexcept -> Duration
Constructs a new Duration object with a duration of zero.
Definition duration.hpp:417
static constexpr auto from_mins(T value) noexcept -> Duration
Constructs a new Duration object from minutes.
Definition duration.hpp:469
constexpr auto operator-(const Duration &rhs) const noexcept -> Duration
Creates Duration object by subtraction. On underflow duration saturates to Duration::zero().
Definition duration.hpp:595
constexpr auto subsec_micros() const noexcept -> uint32_t
returns the subsecond part of the duration in microseconds
Definition duration.hpp:564
constexpr auto as_mins() const noexcept -> uint64_t
returns the duration in minutes
Definition duration.hpp:548
static constexpr uint32_t HOURS_PER_DAY
Definition duration.hpp:274
static constexpr uint32_t NANOSECS_PER_MILLISEC
Definition duration.hpp:280
static constexpr uint32_t NANOSECS_PER_MICROSEC
Definition duration.hpp:279
constexpr auto as_secs() const noexcept -> uint64_t
returns the duration in seconds
Definition duration.hpp:544
static constexpr auto from_nanos(T value) noexcept -> Duration
Constructs a new Duration object from nanoseconds.
Definition duration.hpp:435
constexpr auto as_days() const noexcept -> uint64_t
returns the duration in days
Definition duration.hpp:556
constexpr auto operator*=(const T &rhs) noexcept -> Duration &
Multiplies a Duration with an arithmetic type and assigns the result to itself.
Definition duration.hpp:760
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...
Definition duration.hpp:320
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 &
Definition duration.hpp:809
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...
Definition duration.hpp:328
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...
Definition duration.hpp:320
constexpr auto operator>(const Duration &lhs, const Duration &rhs) noexcept -> bool
Greater than operator.
Definition duration.hpp:368
constexpr auto operator<=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Less than or equal to operator.
Definition duration.hpp:378
constexpr auto operator!=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Not equal to operator.
Definition duration.hpp:349
constexpr auto operator==(const Duration &lhs, const Duration &rhs) noexcept -> bool
Equal to operator.
Definition duration.hpp:340
constexpr auto operator>=(const Duration &lhs, const Duration &rhs) noexcept -> bool
Greater than or equal to operator.
Definition duration.hpp:387
constexpr auto operator<(const Duration &lhs, const Duration &rhs) noexcept -> bool
Less than operator.
Definition duration.hpp:358
constexpr bool always_false_v
Helper value to bind a static_assert to a type.