15namespace tcspc::internal {
17constexpr auto as_signed(std::unsigned_integral
auto i)
18 -> std::make_signed_t<
decltype(i)> {
19 return static_cast<std::make_signed_t<decltype(i)
>>(i);
22constexpr auto as_unsigned(std::signed_integral
auto i)
23 -> std::make_unsigned_t<
decltype(i)> {
24 return static_cast<std::make_unsigned_t<decltype(i)
>>(i);
27constexpr auto ensure_signed(std::integral
auto i)
28 -> std::make_signed_t<
decltype(i)> {
29 return static_cast<std::make_signed_t<decltype(i)
>>(i);
32constexpr auto ensure_unsigned(std::integral
auto i)
33 -> std::make_unsigned_t<
decltype(i)> {
34 return static_cast<std::make_unsigned_t<decltype(i)
>>(i);
39template <
typename T,
typename R>
40concept representable_in =
41 std::integral<T> && std::integral<R> &&
42 std::cmp_greater_equal(std::numeric_limits<T>::min(),
43 std::numeric_limits<R>::min()) &&
44 std::cmp_less_equal(std::numeric_limits<T>::max(),
45 std::numeric_limits<R>::max());
47template <
typename R, std::
integral T>
48constexpr auto convert_with_check(T v) -> R {
49 if (not std::in_range<R>(v))
50 throw std::range_error(
"value out of range of integer type");
51 return static_cast<R
>(v);
54template <std::
integral T>
constexpr auto add_with_check(T a, T b) -> T {
57 if (not __builtin_add_overflow(a, b, &c))
60 using limits = std::numeric_limits<T>;
61 bool const safe_to_add = std::is_signed_v<T> && b < 0
62 ? a >= limits::min() - b
63 : a <= limits::max() - b;
67 throw std::overflow_error(
"integer overflow on addition");
70template <std::
integral T>
constexpr auto subtract_with_check(T a, T b) -> T {
73 if (not __builtin_sub_overflow(a, b, &c))
76 using limits = std::numeric_limits<T>;
77 bool const safe_to_subtract = std::is_signed_v<T> && b < 0
78 ? a <= limits::max() + b
79 : a >= limits::min() + b;
83 throw std::overflow_error(
"integer overflow on subtraction");
87template <std::
integral T>
constexpr auto add_sat(T a, T b)
noexcept -> T {
88 using limits = std::numeric_limits<T>;
91 if (not __builtin_add_overflow(a, b, &c))
94 bool const safe_to_add = std::is_signed_v<T> && b < 0
95 ? a >= limits::min() - b
96 : a <= limits::max() - b;
100 if constexpr (std::is_signed_v<T>) {
102 return limits::min();
104 return limits::max();
107template <std::
integral T>
108constexpr auto add_with_wrap(T a, T b)
noexcept -> T {
109 return static_cast<T
>(as_unsigned(a) + as_unsigned(b));
112template <std::
integral T>
113constexpr auto subtract_with_wrap(T a, T b)
noexcept -> T {
114 return static_cast<T
>(as_unsigned(a) - as_unsigned(b));
119template <std::
integral T>
120constexpr auto pairing_cutoff(T stop_time, T window_size)
noexcept {
122 if (stop_time < std::numeric_limits<T>::min() + window_size)
123 return std::numeric_limits<T>::min();
124 return stop_time - window_size;