21#include "lib/stdcompat/type_traits.h"
22#include "pw_assert/assert.h"
23#include "pw_numeric/integer_division.h"
24#include "pw_polyfill/language_feature_macros.h"
26namespace pw::thread::internal {
29inline constexpr size_t kNamedPriorities = 9;
33PW_CONSTEVAL std::array<uint32_t, kNamedPriorities> PriorityOffsets(
35 std::array<uint32_t, kNamedPriorities> offsets{};
37 for (
unsigned i = 0; i < kNamedPriorities; ++i) {
39 uint64_t priority_value = IntegerDivisionRoundNearest<uint64_t>(
40 static_cast<uint64_t
>(highest) * i, kNamedPriorities - 1);
42 offsets[i] =
static_cast<uint32_t
>(priority_value);
50template <
typename T, T kLowest, T kHighest,
bool = kLowest <= kHighest>
53 static constexpr u
int32_t Range() { return kHighest - kLowest; }
55 constexpr AbstractLevel() : n_{} {}
56 explicit constexpr AbstractLevel(T value) : n_{value} {}
57 constexpr T value() const { return n_; }
59 constexpr
bool operator==(AbstractLevel rhs) const { return n_ == rhs.n_; }
60 constexpr
bool operator!=(AbstractLevel rhs) const { return n_ != rhs.n_; }
61 constexpr
bool operator<(AbstractLevel rhs) const { return n_ < rhs.n_; }
62 constexpr
bool operator<=(AbstractLevel rhs) const { return n_ <= rhs.n_; }
63 constexpr
bool operator>(AbstractLevel rhs) const { return n_ > rhs.n_; }
64 constexpr
bool operator>=(AbstractLevel rhs) const { return n_ >= rhs.n_; }
66 constexpr AbstractLevel operator+(u
int32_t amount) const {
67 return AbstractLevel(static_cast<T>(static_cast<u
int32_t>(n_) + amount));
69 constexpr AbstractLevel operator-(u
int32_t amount) const {
70 return AbstractLevel(static_cast<T>(static_cast<u
int32_t>(n_) - amount));
74 static_assert(kLowest <= kHighest);
78template <
typename T, T kLowest, T kHighest>
79struct AbstractLevel<T, kLowest, kHighest, false> {
81 static constexpr uint32_t Range() {
return kLowest - kHighest; }
83 constexpr AbstractLevel() : n_{} {}
84 explicit constexpr AbstractLevel(T value) : n_{value} {}
85 constexpr T value()
const {
return n_; }
87 constexpr bool operator==(AbstractLevel rhs)
const {
return n_ == rhs.n_; }
88 constexpr bool operator!=(AbstractLevel rhs)
const {
return n_ != rhs.n_; }
89 constexpr bool operator<(AbstractLevel rhs)
const {
return n_ > rhs.n_; }
90 constexpr bool operator<=(AbstractLevel rhs)
const {
return n_ >= rhs.n_; }
91 constexpr bool operator>(AbstractLevel rhs)
const {
return n_ < rhs.n_; }
92 constexpr bool operator>=(AbstractLevel rhs)
const {
return n_ <= rhs.n_; }
94 constexpr AbstractLevel operator+(uint32_t amount)
const {
95 return AbstractLevel(
static_cast<T
>(
static_cast<uint32_t
>(n_) - amount));
97 constexpr AbstractLevel operator-(uint32_t amount)
const {
98 return AbstractLevel(
static_cast<T
>(
static_cast<uint32_t
>(n_) + amount));
102 static_assert(kLowest > kHighest);
108template <
typename T,
bool = std::is_enum_v<T>>
109struct UnderlyingInteger :
public std::underlying_type<T> {};
112struct UnderlyingInteger<T, false> :
public cpp20::type_identity<T> {};
116template <
typename T, T kLowestPriority, T kHighestPriority, T kDefaultPriority>
120 static constexpr bool IsSupported() {
return Level::Range() != 0u; }
123 constexpr Priority() : Priority(kDefault) {}
125 constexpr Priority(
const Priority&) =
default;
126 constexpr Priority& operator=(
const Priority&) =
default;
131 static constexpr Priority Lowest() {
return Priority(kLevels[kLowest]); }
134 static constexpr Priority VeryLow() {
return Priority(kLevels[kVeryLow]); }
137 static constexpr Priority Low() {
return Priority(kLevels[kLow]); }
140 static constexpr Priority MediumLow() {
return Priority(kLevels[kMedLow]); }
144 static constexpr Priority Medium() {
return Priority(kLevels[kMed]); }
147 static constexpr Priority MediumHigh() {
return Priority(kLevels[kMedHigh]); }
150 static constexpr Priority High() {
return Priority(kLevels[kHigh]); }
153 static constexpr Priority VeryHigh() {
return Priority(kLevels[kVeryHigh]); }
158 static constexpr Priority Highest() {
return Priority(kLevels[kHighest]); }
161 static constexpr Priority Default() {
return Priority(); }
168 constexpr Priority NextHigher(Priority maximum = Highest())
const {
169 PW_ASSERT(*
this != maximum);
170 return Priority(level_ + 1);
178 constexpr Priority NextLower(Priority minimum = Lowest())
const {
179 PW_ASSERT(*
this != minimum);
180 return Priority(level_ - 1);
184 constexpr Priority NextLowerClamped(Priority minimum = Lowest())
const {
185 return *
this > minimum ? Priority(level_ - 1) : *this;
189 constexpr Priority NextHigherClamped(Priority maximum = Highest())
const {
190 return *
this < maximum ? Priority(level_ + 1) : *this;
193 constexpr bool operator==(Priority rhs)
const {
return level_ == rhs.level_; }
194 constexpr bool operator!=(Priority rhs)
const {
return level_ != rhs.level_; }
195 constexpr bool operator<(Priority rhs)
const {
return level_ < rhs.level_; }
196 constexpr bool operator<=(Priority rhs)
const {
return level_ <= rhs.level_; }
197 constexpr bool operator>(Priority rhs)
const {
return level_ > rhs.level_; }
198 constexpr bool operator>=(Priority rhs)
const {
return level_ >= rhs.level_; }
203 using native_type = T;
208 constexpr native_type native()
const {
209 return static_cast<native_type
>(level_.value());
215 static constexpr Priority FromNative(native_type priority) {
216 const Level level(
static_cast<NativeInt
>(priority));
217 PW_ASSERT(kLevels[kLowest] <= level);
218 PW_ASSERT(level <= kLevels[kHighest]);
219 return Priority(level);
223 static_assert(std::is_integral_v<native_type> || std::is_enum_v<native_type>,
224 "The native priority type must be an integer or enum");
225 static_assert(
sizeof(native_type) <=
sizeof(uint32_t),
226 "The native priority type cannot be larger than 32 bits");
228 using NativeInt =
typename UnderlyingInteger<native_type>::type;
229 using Level = AbstractLevel<NativeInt,
230 static_cast<NativeInt
>(kLowestPriority),
231 static_cast<NativeInt
>(kHighestPriority)>;
245 static_assert(kNamedPriorities ==
static_cast<size_t>(kHighest) + 1);
249 static constexpr std::array<Level, kNamedPriorities> kLevels = [] {
250 const std::array offsets = PriorityOffsets(Level::Range());
252 std::array<Level, kNamedPriorities> levels{};
253 for (
size_t i = 0; i < offsets.size(); ++i) {
254 levels[i] = Level(
static_cast<NativeInt
>(kLowestPriority)) + offsets[i];
259 static constexpr Level kDefault{
static_cast<NativeInt
>(kDefaultPriority)};
260 static_assert(kLevels[kLowest] <= kDefault && kDefault <= kLevels[kHighest],
261 "pw::thread::backend::kDefaultPriority must be between "
262 "kLowestPriority and kHighestPriority");
264 explicit constexpr Priority(Level level) : level_{level} {}