-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathrollover.hpp
More file actions
155 lines (138 loc) · 5.37 KB
/
rollover.hpp
File metadata and controls
155 lines (138 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#pragma once
#include <stdx/compiler.hpp>
#include <stdx/concepts.hpp>
#include <type_traits>
namespace stdx {
inline namespace v1 {
template <typename T> struct rollover_t {
static_assert(unsigned_integral<T>,
"Argument to rollover_t must be an unsigned integral type.");
using underlying_t = T;
constexpr rollover_t() = default;
// NOLINTBEGIN(modernize-use-constraints)
template <typename U,
typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr explicit rollover_t(U u) : value{static_cast<underlying_t>(u)} {}
template <typename U,
typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr explicit rollover_t(rollover_t<U> u)
: rollover_t{static_cast<U>(u)} {}
// NOLINTEND(modernize-use-constraints)
[[nodiscard]] constexpr auto as_underlying() const -> underlying_t {
return value;
}
constexpr explicit operator underlying_t() const { return value; }
[[nodiscard]] constexpr auto operator+() const -> rollover_t {
return *this;
}
[[nodiscard]] constexpr auto operator-() const -> rollover_t {
return rollover_t{static_cast<underlying_t>(-value)};
}
constexpr auto operator++() -> rollover_t & {
++value;
return *this;
}
constexpr auto operator++(int) -> rollover_t { return rollover_t{value++}; }
constexpr auto operator--() -> rollover_t & {
--value;
return *this;
}
constexpr auto operator--(int) -> rollover_t { return rollover_t{value--}; }
constexpr auto operator+=(rollover_t other) -> rollover_t & {
value += other.value;
return *this;
}
constexpr auto operator-=(rollover_t other) -> rollover_t & {
value -= other.value;
return *this;
}
constexpr auto operator*=(rollover_t other) -> rollover_t & {
value *= other.value;
return *this;
}
constexpr auto operator/=(rollover_t other) -> rollover_t & {
value /= other.value;
return *this;
}
constexpr auto operator%=(rollover_t other) -> rollover_t & {
value %= other.value;
return *this;
}
private:
[[nodiscard]] friend constexpr auto operator==(rollover_t lhs,
rollover_t rhs) -> bool {
return lhs.value == rhs.value;
}
[[nodiscard]] friend constexpr auto operator!=(rollover_t lhs,
rollover_t rhs) -> bool {
return not(lhs == rhs);
}
friend constexpr auto operator<(rollover_t, rollover_t)
-> bool STDX_DELETED(
"Comparison operators on rollover_t are deleted because "
"they are non-transitive. If you know your data is safe, "
"you can use cmp_less(rollover_t, rollover_t).");
friend constexpr auto operator<=(rollover_t, rollover_t)
-> bool STDX_DELETED(
"Comparison operators on rollover_t are deleted because "
"they are non-transitive. If you know your data is safe, "
"you can use cmp_less(rollover_t, rollover_t).");
friend constexpr auto operator>(rollover_t, rollover_t)
-> bool STDX_DELETED(
"Comparison operators on rollover_t are deleted because "
"they are non-transitive. If you know your data is safe, "
"you can use cmp_less(rollover_t, rollover_t).");
friend constexpr auto operator>=(rollover_t, rollover_t)
-> bool STDX_DELETED(
"Comparison operators on rollover_t are deleted because "
"they are non-transitive. If you know your data is safe, "
"you can use cmp_less(rollover_t, rollover_t).");
[[nodiscard]] friend constexpr auto cmp_less(rollover_t lhs, rollover_t rhs)
-> bool {
constexpr auto mid = static_cast<underlying_t>(~underlying_t{}) / 2;
return static_cast<underlying_t>(lhs.value - rhs.value) > mid;
}
[[nodiscard]] friend constexpr auto operator+(rollover_t lhs,
rollover_t rhs)
-> rollover_t {
lhs += rhs;
return lhs;
}
[[nodiscard]] friend constexpr auto operator-(rollover_t lhs,
rollover_t rhs)
-> rollover_t {
lhs -= rhs;
return lhs;
}
[[nodiscard]] friend constexpr auto operator*(rollover_t lhs,
rollover_t rhs)
-> rollover_t {
lhs *= rhs;
return lhs;
}
[[nodiscard]] friend constexpr auto operator/(rollover_t lhs,
rollover_t rhs)
-> rollover_t {
lhs /= rhs;
return lhs;
}
[[nodiscard]] friend constexpr auto operator%(rollover_t lhs,
rollover_t rhs)
-> rollover_t {
lhs %= rhs;
return lhs;
}
underlying_t value{};
};
template <typename T> rollover_t(T) -> rollover_t<T>;
} // namespace v1
} // namespace stdx
template <typename T, typename U>
struct std::common_type<stdx::rollover_t<T>, stdx::rollover_t<U>> {
using type = stdx::rollover_t<std::common_type_t<T, U>>;
};
template <typename T, typename I>
struct std::common_type<stdx::rollover_t<T>, I> {
using type =
stdx::rollover_t<std::common_type_t<T, std::make_unsigned_t<I>>>;
};