Skip to content

Commit b6d7b19

Browse files
committed
fixed std::to_underlying not being available in c++20
1 parent 0d8b29f commit b6d7b19

7 files changed

Lines changed: 55 additions & 19 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ target_sources(${PROJECT_NAME}
7575
FILES ${ORYX_CHRON_HEADERS}
7676
)
7777

78+
# Experimental
79+
target_precompile_headers(${PROJECT_NAME} PUBLIC
80+
<string>
81+
<chrono>
82+
)
83+
7884
if(ORYX_CHRON_SANITIZE_ADDRESS)
7985
oryx_enable_addr_sanitizer(${PROJECT_NAME})
8086
elseif(ORYX_CHRON_SANITIZE_THREAD)

include/oryx/chron/data.hpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@
22

33
#include <cstdint>
44
#include <string>
5+
#include <string_view>
56
#include <set>
67
#include <regex>
78
#include <string>
8-
#include <utility>
99
#include <vector>
1010
#include <array>
1111
#include <span>
12-
#include <utility>
12+
#include <type_traits>
13+
#include <iterator>
1314

1415
#include <oryx/chron/time_types.hpp>
1516
#include <oryx/chron/details/string_split.hpp>
1617
#include <oryx/chron/details/ctre.hpp>
1718
#include <oryx/chron/details/string_cast.hpp>
19+
#include <oryx/chron/details/to_underlying.hpp>
1820

1921
namespace oryx::chron {
2022

@@ -101,7 +103,7 @@ template <typename T>
101103
auto Data::ValidateLiteral(const std::string& s, std::set<T>& numbers, std::span<const std::string_view> names)
102104
-> bool {
103105
auto parts = details::StringSplit(s, ',');
104-
auto value_of_first_name = std::to_underlying(T::First);
106+
auto value_of_first_name = details::to_underlying(T::First);
105107

106108
for (auto& name : names) {
107109
std::regex regex_pattern(name.data(), std::regex_constants::ECMAScript | std::regex_constants::icase);
@@ -145,7 +147,7 @@ template <typename T>
145147
auto Data::GetStep(std::string_view s, uint8_t& start, uint8_t& step) -> bool {
146148
if (auto match = ctre::match<R"#((\d+|\*)/(\d+))#">(s)) {
147149
auto first = match.get<1>().to_view();
148-
int raw_start = (first == "*") ? std::to_underlying(T::First) : details::StringCast<int>(first);
150+
int raw_start = (first == "*") ? details::to_underlying(T::First) : details::StringCast<int>(first);
149151
int raw_step = details::StringCast<int>(match.get<2>().to_view());
150152
if (IsWithinLimits<T>(raw_start, raw_start) && raw_step > 0) {
151153
start = static_cast<uint8_t>(raw_start);
@@ -158,7 +160,7 @@ auto Data::GetStep(std::string_view s, uint8_t& start, uint8_t& step) -> bool {
158160

159161
template <typename T>
160162
auto Data::AddFullRange(std::set<T>& set) -> void {
161-
for (auto v = std::to_underlying(T::First); v <= std::to_underlying(T::Last); ++v) {
163+
for (auto v = details::to_underlying(T::First); v <= details::to_underlying(T::Last); ++v) {
162164
if (set.find(static_cast<T>(v)) == set.end()) {
163165
set.emplace(static_cast<T>(v));
164166
}
@@ -175,8 +177,8 @@ auto Data::AddNumber(std::set<T>& set, int32_t number) -> bool {
175177

176178
template <typename T>
177179
auto Data::IsWithinLimits(int32_t low, int32_t high) -> bool {
178-
return IsBetween(low, std::to_underlying(T::First), std::to_underlying(T::Last)) &&
179-
IsBetween(high, std::to_underlying(T::First), std::to_underlying(T::Last));
180+
return IsBetween(low, details::to_underlying(T::First), details::to_underlying(T::Last)) &&
181+
IsBetween(high, details::to_underlying(T::First), details::to_underlying(T::Last));
180182
}
181183

182184
template <typename T>
@@ -191,19 +193,19 @@ auto Data::ConvertFromStringRangeToNumberRange(std::string_view range, std::set<
191193
result = AddNumber<T>(numbers, details::StringCast<int32_t>(range));
192194
} else if (GetRange<T>(range, left, right)) {
193195
if (left <= right) {
194-
for (auto v = std::to_underlying(left); v <= std::to_underlying(right); ++v) {
196+
for (auto v = details::to_underlying(left); v <= details::to_underlying(right); ++v) {
195197
result &= AddNumber(numbers, v);
196198
}
197199
} else {
198-
for (auto v = std::to_underlying(left); v <= std::to_underlying(T::Last); ++v) {
200+
for (auto v = details::to_underlying(left); v <= details::to_underlying(T::Last); ++v) {
199201
result &= AddNumber(numbers, v);
200202
}
201-
for (auto v = std::to_underlying(T::First); v <= std::to_underlying(right); ++v) {
203+
for (auto v = details::to_underlying(T::First); v <= details::to_underlying(right); ++v) {
202204
result &= AddNumber(numbers, v);
203205
}
204206
}
205207
} else if (GetStep<T>(range, step_start, step)) {
206-
for (auto v = step_start; v <= std::to_underlying(T::Last); v += step) {
208+
for (auto v = step_start; v <= details::to_underlying(T::Last); v += step) {
207209
result &= AddNumber(numbers, v);
208210
}
209211
} else {
@@ -216,7 +218,7 @@ auto Data::ConvertFromStringRangeToNumberRange(std::string_view range, std::set<
216218
template <typename T>
217219
requires(std::is_same_v<T, Months> || std::is_same_v<T, DayOfWeek>)
218220
auto Data::ReplaceStringNameWithNumeric(std::string& s) -> std::string& {
219-
auto value = std::to_underlying(T::First);
221+
auto value = details::to_underlying(T::First);
220222

221223
if constexpr (std::is_same_v<T, Months>) {
222224
for (auto name : kMonthNames) {

include/oryx/chron/details/any_of.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#include <cstdint>
44
#include <set>
5-
#include <utility>
5+
6+
#include <oryx/chron/details/to_underlying.hpp>
67

78
namespace oryx::chron::details {
89

@@ -23,7 +24,7 @@ auto AnyOf(const std::set<T>& set, uint8_t low, uint8_t high) -> bool {
2324
template <typename Enum>
2425
requires std::is_enum_v<Enum>
2526
auto AnyOf(const std::set<Enum>& set, Enum low, Enum high) -> bool {
26-
for (auto i = std::to_underlying(low); i <= std::to_underlying(high); ++i)
27+
for (auto i = details::to_underlying(low); i <= details::to_underlying(high); ++i)
2728
if (set.contains(static_cast<Enum>(i))) return true;
2829
return false;
2930
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include <utility>
4+
#include <type_traits>
5+
6+
namespace oryx::chron::details {
7+
8+
#ifndef __cpp_lib_to_underlying
9+
10+
template <typename Enum>
11+
requires std::is_enum_v<Enum>
12+
constexpr auto to_underlying(Enum e) noexcept -> std::underlying_type_t<Enum> {
13+
return static_cast<std::underlying_type_t<Enum>>(e);
14+
}
15+
16+
#else
17+
18+
using std::to_underlying;
19+
20+
#endif
21+
22+
} // namespace oryx::chron::details

include/oryx/chron/schedule.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <tuple>
4+
35
#include <oryx/chron/data.hpp>
46
#include <oryx/chron/date_time.hpp>
57
#include <oryx/chron/chrono_types.hpp>

src/randomization.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <oryx/chron/data.hpp>
1212
#include <oryx/chron/details/ctre.hpp>
1313
#include <oryx/chron/details/string_cast.hpp>
14+
#include <oryx/chron/details/to_underlying.hpp>
1415

1516
namespace oryx::chron {
1617
namespace {
@@ -41,7 +42,7 @@ auto GetRandomInRange(std::string_view section,
4142
// Remove items outside the limit
4243
if (limit.first != -1 && limit.second != -1) {
4344
for (auto it = numbers.begin(); it != numbers.end();) {
44-
if (std::to_underlying(*it) < limit.first || std::to_underlying(*it) > limit.second) {
45+
if (details::to_underlying(*it) < limit.first || details::to_underlying(*it) > limit.second) {
4546
it = numbers.erase(it);
4647
} else {
4748
++it;
@@ -54,7 +55,7 @@ auto GetRandomInRange(std::string_view section,
5455
std::uniform_int_distribution<> distribution(0, static_cast<int>(numbers.size() - 1));
5556
auto it = numbers.begin();
5657
std::advance(it, distribution(twister));
57-
selected_value = std::to_underlying(*it);
58+
selected_value = details::to_underlying(*it);
5859
result.second = std::to_string(selected_value);
5960
}
6061
} else {
@@ -66,7 +67,7 @@ auto GetRandomInRange(std::string_view section,
6667
}
6768

6869
auto DayLimiter(const std::set<Months>& months) -> std::pair<int, int> {
69-
int max = std::to_underlying(DayOfMonth::Last);
70+
int max = details::to_underlying(DayOfMonth::Last);
7071

7172
for (auto month : months) {
7273
if (month == Months::February) {
@@ -78,7 +79,7 @@ auto DayLimiter(const std::set<Months>& months) -> std::pair<int, int> {
7879
}
7980
}
8081

81-
return {std::to_underlying(DayOfMonth::First), max};
82+
return {details::to_underlying(DayOfMonth::First), max};
8283
}
8384

8485
} // namespace

src/schedule.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <tuple>
44

5+
#include <oryx/chron/details/to_underlying.hpp>
6+
57
using namespace std::chrono;
68

79
namespace oryx::chron {
@@ -24,7 +26,7 @@ auto Schedule::CalculateFrom(const TimePoint& from) const -> std::tuple<bool, Ti
2426
date_changed = true;
2527
}
2628
// If all days are allowed (or the field is ignored via '?'), then the 'day of week' takes precedence.
27-
else if (data_.GetDayOfMonth().size() != std::to_underlying(DayOfMonth::Last)) {
29+
else if (data_.GetDayOfMonth().size() != details::to_underlying(DayOfMonth::Last)) {
2830
// Add days until one of the allowed days are found, or stay at the current one.
2931
if (data_.GetDayOfMonth().find(static_cast<DayOfMonth>(unsigned(ymd.day()))) ==
3032
data_.GetDayOfMonth().end()) {

0 commit comments

Comments
 (0)