1+ #include < oryx/chron/preprocessor.hpp>
2+
3+ #include < algorithm>
4+ #include < string_view>
5+ #include < span>
6+
7+ #include < oryx/chron/details/ctre.hpp>
8+ #include < oryx/chron/details/to_underlying.hpp>
9+
10+ namespace oryx ::chron {
11+ namespace {
12+
13+ struct DollarExpressionPair {
14+ std::string_view expr;
15+ std::string_view cron;
16+ };
17+
18+ template <typename Enum>
19+ requires std::is_enum_v<Enum>
20+ auto ReplaceWithNumeric (std::string data, std::span<const std::string_view> names) -> std::string {
21+ static auto find_icase = [](std::string_view haystack, std::string_view needle) {
22+ return std::ranges::search (
23+ haystack, needle, [](const int lhs, const int rhs) { return lhs == rhs; },
24+ [](const int lhs) { return std::toupper (lhs); });
25+ };
26+
27+ auto value = details::to_underlying (Enum::First);
28+
29+ std::string cached_str_value;
30+ for (auto & name : names) {
31+ std::string_view view{data};
32+ size_t search_start = 0 ;
33+
34+ while (search_start < view.size ()) {
35+ auto subview = view.substr (search_start);
36+ auto found = find_icase (subview, name);
37+
38+ if (found.empty ()) {
39+ break ;
40+ }
41+
42+ if (cached_str_value.empty ()) {
43+ cached_str_value = std::to_string (value);
44+ }
45+
46+ auto found_pos = search_start + std::distance (subview.begin (), found.begin ());
47+ data.replace (found_pos, name.size (), cached_str_value);
48+
49+ // Update part_view to reflect the changes and move search position
50+ view = data;
51+ search_start = found_pos + cached_str_value.size ();
52+ }
53+ cached_str_value.clear ();
54+ value++;
55+ }
56+ return data;
57+ }
58+
59+ } // namespace
60+
61+ auto DollarExpressionProcessor::Process (std::string data) noexcept -> std::string {
62+ static constexpr std::array<DollarExpressionPair, 6 > kExpressions {
63+ DollarExpressionPair (" @yearly" , " 0 0 0 1 1 *" ), DollarExpressionPair (" @annually" , " 0 0 0 1 1 *" ),
64+ DollarExpressionPair (" @monthly" , " 0 0 0 1 * *" ), DollarExpressionPair (" @weekly" , " 0 0 0 * * 0" ),
65+ DollarExpressionPair (" @daily" , " 0 0 0 * * ?" ), DollarExpressionPair (" @hourly" , " 0 0 * * * ?" )};
66+
67+ if (!data.empty () && data[0 ] == ' @' ) {
68+ auto it = std::ranges::find (kExpressions , data, &DollarExpressionPair::expr);
69+ if (it != kExpressions .end ()) [[likely]] {
70+ return std::string (it->cron );
71+ }
72+ }
73+ return data;
74+ }
75+
76+ auto WeekMonthDayLiteralProcessor::Process (std::string data) noexcept -> std::string {
77+ static constexpr std::array<std::string_view, 12 > kMonthNames {" JAN" , " FEB" , " MAR" , " APR" , " MAY" , " JUN" ,
78+ " JUL" , " AUG" , " SEP" , " OCT" , " NOV" , " DEC" };
79+
80+ static constexpr std::array<std::string_view, 7 > kDayNames {" SUN" , " MON" , " TUE" , " WED" , " THU" , " FRI" , " SAT" };
81+ static constexpr auto matcher = ctre::match<R"#( ^\s*(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s*$)#" >;
82+
83+ auto match = matcher (data);
84+ if (!match) [[unlikely]] {
85+ return data;
86+ }
87+
88+ auto month = ReplaceWithNumeric<Months>(match.get <5 >().to_string (), kMonthNames );
89+ auto dow = ReplaceWithNumeric<Weekdays>(match.get <6 >().to_string (), kDayNames );
90+ return std::format (" {} {} {} {} {} {}" , match.get <1 >().to_view (), match.get <2 >().to_view (),
91+ match.get <3 >().to_view (), match.get <4 >().to_view (), month, dow);
92+ }
93+
94+ } // namespace oryx::chron
0 commit comments