Skip to content

Commit 1a1d309

Browse files
committed
refactored last usage of std::regex_replace
use std::optional<T> instead of std::tuple<bool , T> removed unused regex
1 parent 8b9dca2 commit 1a1d309

12 files changed

Lines changed: 110 additions & 83 deletions

File tree

include/oryx/chron/data.hpp

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@
44
#include <string>
55
#include <string_view>
66
#include <set>
7-
#include <regex>
87
#include <string>
98
#include <vector>
109
#include <array>
1110
#include <span>
1211
#include <type_traits>
13-
#include <iterator>
1412

1513
#include <oryx/chron/time_types.hpp>
1614
#include <oryx/chron/details/string_split.hpp>
1715
#include <oryx/chron/details/ctre.hpp>
1816
#include <oryx/chron/details/string_cast.hpp>
1917
#include <oryx/chron/details/to_underlying.hpp>
18+
#include <oryx/chron/details/time_types_transform.hpp>
2019

2120
namespace oryx::chron {
2221

@@ -28,11 +27,6 @@ class Data {
2827
static constexpr std::array<Months, kNumberOfLongMonths> kMonthsWith31{
2928
Months::January, Months::March, Months::May, Months::July, Months::August, Months::October, Months::December};
3029

31-
static constexpr std::array<std::string_view, 12> kMonthNames{"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
32-
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
33-
34-
static constexpr std::array<std::string_view, 7> kDayNames{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
35-
3630
Data() = default;
3731

3832
auto IsValid() const -> bool { return valid_; }
@@ -103,26 +97,15 @@ template <typename T>
10397
auto Data::ValidateLiteral(const std::string& s, std::set<T>& numbers, std::span<const std::string_view> names)
10498
-> bool {
10599
auto parts = details::StringSplit(s, ',');
106-
auto value_of_first_name = details::to_underlying(T::First);
107-
108-
for (auto& name : names) {
109-
std::regex regex_pattern(name.data(), std::regex_constants::ECMAScript | std::regex_constants::icase);
110-
111-
for (auto& part : parts) {
112-
std::string replaced;
113-
std::regex_replace(std::back_inserter(replaced), part.begin(), part.end(), regex_pattern,
114-
std::to_string(value_of_first_name));
115-
part = replaced;
116-
}
117-
++value_of_first_name;
100+
for (auto& part : parts) {
101+
details::ReplaceWithNumeric<T>(part, names);
118102
}
119-
120103
return ProcessParts(parts, numbers);
121104
}
122105

123106
template <typename T>
124107
auto Data::ProcessParts(const std::vector<std::string>& parts, std::set<T>& numbers) -> bool {
125-
bool result = true;
108+
bool result{true};
126109
for (auto& part : parts) {
127110
result &= ConvertFromStringRangeToNumberRange(part, numbers);
128111
}
@@ -215,28 +198,4 @@ auto Data::ConvertFromStringRangeToNumberRange(std::string_view range, std::set<
215198
return result;
216199
}
217200

218-
template <typename T>
219-
requires(std::is_same_v<T, Months> || std::is_same_v<T, DayOfWeek>)
220-
auto Data::ReplaceStringNameWithNumeric(std::string& s) -> std::string& {
221-
auto value = details::to_underlying(T::First);
222-
223-
if constexpr (std::is_same_v<T, Months>) {
224-
for (auto name : kMonthNames) {
225-
std::regex regex_pattern(name.data(), std::regex_constants::ECMAScript | std::regex_constants::icase);
226-
std::string replaced;
227-
std::regex_replace(std::back_inserter(replaced), s.begin(), s.end(), regex_pattern, std::to_string(value));
228-
s = replaced;
229-
++value;
230-
}
231-
} else {
232-
for (auto name : kDayNames) {
233-
std::regex regex_pattern(name.data(), std::regex_constants::ECMAScript | std::regex_constants::icase);
234-
std::string replaced;
235-
std::regex_replace(std::back_inserter(replaced), s.begin(), s.end(), regex_pattern, std::to_string(value));
236-
s = replaced;
237-
++value;
238-
}
239-
}
240-
return s;
241-
}
242201
} // namespace oryx::chron
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <string_view>
5+
#include <array>
6+
#include <span>
7+
#include <algorithm>
8+
9+
#include "oryx/chron/time_types.hpp"
10+
#include "to_underlying.hpp"
11+
12+
namespace oryx::chron::details {
13+
14+
inline constexpr std::array<std::string_view, 12> kMonthNames{"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
15+
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
16+
17+
inline constexpr std::array<std::string_view, 7> kDayNames{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
18+
19+
using NamesView = std::span<const std::string_view>;
20+
21+
template <typename T>
22+
auto ReplaceWithNumeric(std::string& data, NamesView names) -> std::string& {
23+
static auto find_icase = [](std::string_view haystack, std::string_view needle) {
24+
return std::ranges::search(
25+
haystack, needle, [](const int lhs, const int rhs) { return lhs == rhs; },
26+
[](const int lhs) { return std::toupper(lhs); });
27+
};
28+
29+
auto value = to_underlying(T::First);
30+
31+
std::string cached_str_value;
32+
for (auto& name : names) {
33+
std::string_view view{data};
34+
size_t search_start = 0;
35+
36+
while (search_start < view.size()) {
37+
auto subview = view.substr(search_start);
38+
auto found = find_icase(subview, name);
39+
40+
if (found.empty()) {
41+
break;
42+
}
43+
44+
if (cached_str_value.empty()) {
45+
cached_str_value = std::to_string(value);
46+
}
47+
48+
auto found_pos = search_start + std::distance(subview.begin(), found.begin());
49+
data.replace(found_pos, name.size(), cached_str_value);
50+
51+
// Update part_view to reflect the changes and move search position
52+
view = data;
53+
search_start = found_pos + cached_str_value.size();
54+
}
55+
cached_str_value.clear();
56+
value++;
57+
}
58+
return data;
59+
}
60+
61+
inline auto ReplaceDayNameWithNumeric(std::string& data) -> std::string& {
62+
return ReplaceWithNumeric<DayOfWeek>(data, kDayNames);
63+
}
64+
65+
inline auto ReplaceMonthNameWithNumeric(std::string& data) -> std::string& {
66+
return ReplaceWithNumeric<Months>(data, kMonthNames);
67+
}
68+
69+
} // namespace oryx::chron::details

include/oryx/chron/randomization.hpp

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

33
#include <string_view>
4-
#include <tuple>
4+
#include <optional>
55
#include <random>
66

77
namespace oryx::chron {
@@ -12,7 +12,7 @@ class Randomization {
1212
Randomization(const Randomization&) = delete;
1313
auto operator=(const Randomization&) -> Randomization& = delete;
1414

15-
auto Parse(std::string_view cron_schedule) -> std::tuple<bool, std::string>;
15+
auto Parse(std::string_view cron_schedule) -> std::optional<std::string>;
1616

1717
private:
1818
std::random_device random_device_;

include/oryx/chron/schedule.hpp

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

3-
#include <tuple>
3+
#include <optional>
44

55
#include <oryx/chron/data.hpp>
66
#include <oryx/chron/date_time.hpp>
@@ -12,7 +12,7 @@ class Schedule {
1212
explicit Schedule(Data data)
1313
: data_(std::move(data)) {}
1414

15-
auto CalculateFrom(const TimePoint& from) const -> std::tuple<bool, TimePoint>;
15+
auto CalculateFrom(const TimePoint& from) const -> std::optional<TimePoint>;
1616

1717
static auto ToCalendarTime(TimePoint time) -> DateTime;
1818

include/oryx/chron/traits.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ namespace oryx::chron::traits {
99

1010
template <typename T>
1111
concept Clock = requires(const T& t, TimePoint tp) {
12-
// Must provide: Now() -> std::chrono::system_clock::time_point
1312
{ t.Now() } -> std::same_as<TimePoint>;
14-
15-
// Must provide: UtcOffset(time_point) -> std::chrono::seconds
1613
{ t.UtcOffset(tp) } -> std::same_as<std::chrono::seconds>;
1714
};
1815

src/data.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ auto Data::Create<DataCachePolicy::kBypassCache>(const std::string& cron_express
6060
}
6161

6262
void Data::Parse(std::string_view cron_expression) {
63-
static const std::regex kSplit{R"#(^\s*(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s*$)#",
64-
std::regex_constants::ECMAScript};
6563
static constexpr std::array<DollarExprPair, 6> kShortcuts{
6664
DollarExprPair("@yearly", "0 0 0 1 1 *"), DollarExprPair("@annually", "0 0 0 1 1 *"),
6765
DollarExprPair("@monthly", "0 0 0 1 * *"), DollarExprPair("@weekly", "0 0 0 * * 0"),
@@ -79,8 +77,8 @@ void Data::Parse(std::string_view cron_expression) {
7977
valid_ &= ValidateNumeric<Minutes>(match.get<2>().to_view(), minutes_);
8078
valid_ &= ValidateNumeric<Hours>(match.get<3>().to_view(), hours_);
8179
valid_ &= ValidateNumeric<DayOfMonth>(match.get<4>().to_view(), day_of_month_);
82-
valid_ &= ValidateLiteral<Months>(match.get<5>().to_string(), months_, kMonthNames);
83-
valid_ &= ValidateLiteral<DayOfWeek>(match.get<6>().to_string(), day_of_week_, kDayNames);
80+
valid_ &= ValidateLiteral<Months>(match.get<5>().to_string(), months_, details::kMonthNames);
81+
valid_ &= ValidateLiteral<DayOfWeek>(match.get<6>().to_string(), day_of_week_, details::kDayNames);
8482
valid_ &= CheckDomVsDow(match.get<4>().to_view(), match.get<6>().to_view());
8583
valid_ &= ValidateDateVsMonths();
8684
}

src/randomization.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
#include <optional>
12
#include <oryx/chron/randomization.hpp>
23

34
#include <algorithm>
4-
#include <regex>
55
#include <map>
66
#include <array>
77
#include <iterator>
@@ -87,7 +87,7 @@ auto DayLimiter(const std::set<Months>& months) -> std::pair<int, int> {
8787
Randomization::Randomization()
8888
: twister_(random_device_()) {}
8989

90-
auto Randomization::Parse(std::string_view cron_schedule) -> std::tuple<bool, std::string> {
90+
auto Randomization::Parse(std::string_view cron_schedule) -> std::optional<std::string> {
9191
// Split on space to get each separate part, six parts expected
9292
auto matcher = ctre::match<R"#(^\s*(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s*$)#">;
9393
// Replace text with numbers
@@ -96,10 +96,10 @@ auto Randomization::Parse(std::string_view cron_schedule) -> std::tuple<bool, st
9696
if (auto match = matcher(cron_schedule)) {
9797
// Replace month and day names first
9898
auto month = match.get<5>().to_string();
99-
Data::ReplaceStringNameWithNumeric<Months>(month);
99+
details::ReplaceMonthNameWithNumeric(month);
100100

101101
auto dow = match.get<6>().to_string();
102-
Data::ReplaceStringNameWithNumeric<DayOfWeek>(dow);
102+
details::ReplaceDayNameWithNumeric(dow);
103103

104104
// Merge all sections into one string
105105
working_copy = std::format("{} {} {} {} {} {}", match.get<1>().to_view(), match.get<2>().to_view(),
@@ -146,8 +146,10 @@ auto Randomization::Parse(std::string_view cron_schedule) -> std::tuple<bool, st
146146
success &= day_of_week.first;
147147
final_cron_schedule += " " + day_of_week.second;
148148
}
149-
150-
return {success, final_cron_schedule};
149+
if (success) {
150+
return final_cron_schedule;
151+
}
152+
return std::nullopt;
151153
}
152154

153155
} // namespace oryx::chron

src/schedule.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
#include <oryx/chron/schedule.hpp>
2-
3-
#include <tuple>
1+
#include <optional>
42

3+
#include <oryx/chron/schedule.hpp>
54
#include <oryx/chron/details/to_underlying.hpp>
5+
#include <oryx/chron/chrono_types.hpp>
66

77
using namespace std::chrono;
88

99
namespace oryx::chron {
1010

11-
auto Schedule::CalculateFrom(const TimePoint& from) const -> std::tuple<bool, TimePoint> {
11+
auto Schedule::CalculateFrom(const TimePoint& from) const -> std::optional<TimePoint> {
1212
auto curr = from;
1313

14-
bool done = false;
14+
bool done{};
1515
auto max_iterations = std::numeric_limits<uint16_t>::max();
1616

1717
while (!done && --max_iterations > 0) {
@@ -74,14 +74,16 @@ auto Schedule::CalculateFrom(const TimePoint& from) const -> std::tuple<bool, Ti
7474
// the `tick()` within the same second will never be earlier than schedule time,
7575
// and the task will trigger in that `tick()`.
7676
curr -= curr.time_since_epoch() % seconds{1};
77-
78-
return std::make_tuple(max_iterations > 0, curr);
77+
if (max_iterations > 0) {
78+
return curr;
79+
}
80+
return std::nullopt;
7981
}
8082

8183
auto Schedule::ToCalendarTime(TimePoint time) -> DateTime {
82-
auto daypoint = std::chrono::floor<std::chrono::days>(time);
83-
auto ymd = std::chrono::year_month_day(daypoint); // calendar date
84-
auto time_of_day = std::chrono::hh_mm_ss(time - daypoint); // Yields time_of_day type
84+
auto daypoint = floor<days>(time);
85+
auto ymd = year_month_day(daypoint); // calendar date
86+
auto time_of_day = hh_mm_ss(time - daypoint); // Yields time_of_day type
8587

8688
// Obtain individual components as integers
8789
return {.year = int(ymd.year()),

src/task.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ auto Task::CalculateNext(TimePoint from) -> bool {
2828
auto result = schedule_.CalculateFrom(from);
2929

3030
// In case the calculation fails, the task will no longer expire.
31-
valid_ = std::get<0>(result);
31+
valid_ = result.has_value();
3232
if (valid_) {
33-
next_schedule_ = std::get<1>(result);
33+
next_schedule_ = result.value();
3434

3535
// Make sure that the task is allowed to run.
3636
last_run_ = next_schedule_ - 1s;

tests/data_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ SCENARIO("Date that exist in one of the months") { REQUIRE(Data::Create("0 0 * 3
190190
SCENARIO("Replacing text with numbers") {
191191
{
192192
std::string s = "SUN-TUE";
193-
REQUIRE(Data::ReplaceStringNameWithNumeric<DayOfWeek>(s) == "0-2");
193+
REQUIRE(details::ReplaceDayNameWithNumeric(s) == "0-2");
194194
}
195195

196196
{
197197
std::string s = "JAN-DEC";
198-
REQUIRE(Data::ReplaceStringNameWithNumeric<Months>(s) == "1-12");
198+
REQUIRE(details::ReplaceMonthNameWithNumeric(s) == "1-12");
199199
}
200200
}

0 commit comments

Comments
 (0)