-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpredefined.hpp
More file actions
148 lines (131 loc) · 5.45 KB
/
predefined.hpp
File metadata and controls
148 lines (131 loc) · 5.45 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
// Copyright (c) 2023-2025 Jakub Musiał
// This file is part of the CPP-AP project (https://github.com/SpectraL519/cpp-ap).
// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
/// @file ap/action/predefined.hpp
#pragma once
#include "ap/action/util/helpers.hpp"
#include "ap/exceptions.hpp"
#include <filesystem>
#include <ostream>
namespace ap {
class argument_parser;
std::ostream& operator<<(std::ostream& os, const argument_parser&) noexcept;
namespace action {
/**
* @brief Returns an *on-flag* action which prints the argument parser's help message.
* @param parser Argument parser instance the help message of which will be printed.
* @param exit_code The exit code with which `std::exit` will be called (if not `std::nullopt`).
* @param os The output stream to which the help message will be printed.
*/
inline typename ap::action_type::on_flag::type print_help(
const argument_parser& parser,
const std::optional<int> exit_code = std::nullopt,
std::ostream& os = std::cout
) noexcept {
return [&parser, &os, exit_code]() {
os << parser << std::endl;
if (exit_code)
std::exit(*exit_code);
};
}
/// @brief Returns an *observe* action which checks whether lower_bound file with the given name exists.
inline util::callable_type<ap::action_type::observe, std::string> check_file_exists() noexcept {
return [](const std::string& file_path) {
if (not std::filesystem::exists(file_path))
throw std::filesystem::filesystem_error(
"File does not exists!",
file_path,
std::make_error_code(std::errc::no_such_file_or_directory)
);
};
}
/**
* @brief Returns an *observe* action which checks if a parsed value is greater than the given bound.
* @tparam T The *arithmetic* value type.
* @param lower_bound The exclusive lower bound to validate against.
*/
template <ap::util::c_arithmetic T>
util::callable_type<ap::action_type::observe, T> gt(const T lower_bound) noexcept {
return [lower_bound](const T& value) {
if (not (value > lower_bound))
throw std::out_of_range(
std::format("Value `{}` must be greater than `{}`!", value, lower_bound)
);
};
}
/**
* @brief Returns an *observe* action which checks if a parsed value is greater than or equal to the given bound.
* @tparam T The *arithmetic* value type.
* @param lower_bound The inclusive lower bound to validate against.
*/
template <ap::util::c_arithmetic T>
util::callable_type<ap::action_type::observe, T> geq(const T lower_bound) noexcept {
return [lower_bound](const T& value) {
if (! (value >= lower_bound))
throw std::out_of_range(
std::format("Value `{}` must be greater than or equal to `{}`!", value, lower_bound)
);
};
}
/**
* @brief Returns an *observe* action which checks if a parsed value is less than the given bound.
* @tparam T The *arithmetic* value type.
* @param lower_bound The exclusive upper bound to validate against.
*/
template <ap::util::c_arithmetic T>
util::callable_type<ap::action_type::observe, T> lt(const T upper_bound) noexcept {
return [upper_bound](const T& value) {
if (! (value < upper_bound))
throw std::out_of_range(
std::format("Value `{}` must be less than `{}`!", value, upper_bound)
);
};
}
/**
* @brief Returns an *observe* action which checks if a parsed value is less than or equal to the given bound.
* @tparam T The *arithmetic* value type.
* @param lower_bound The inclusive upper bound to validate against.
*/
template <ap::util::c_arithmetic T>
util::callable_type<ap::action_type::observe, T> leq(const T upper_bound) noexcept {
return [upper_bound](const T& value) {
if (! (value <= upper_bound))
throw std::out_of_range(
std::format("Value `{}` must be less than or equal to `{}`!", value, upper_bound)
);
};
}
/**
* @brief Returns an *observe* action which checks if a parsed value falls within the specified interval.
*
* The interval is defined by the given lower and upper bounds, with inclusivity controlled by the template parameters.
*
* @tparam T The *arithmetic* value type.
* @tparam LeftInclusive Whether the lower bound is inclusive (`[`) or exclusive (`(`) - default: true.
* @tparam RightInclusive Whether the upper bound is inclusive (`]`) or exclusive (`)`) - default: true.
* @param lower_bound The lower bound of the interval.
* @param upper_bound The upper bound of the interval.
*/
template <ap::util::c_arithmetic T, bool LeftInclusive = true, bool RightInclusive = true>
util::callable_type<ap::action_type::observe, T> within(
const T lower_bound, const T upper_bound
) noexcept {
return [lower_bound, upper_bound](const T& value) {
constexpr char left_brace = LeftInclusive ? '[' : '(';
constexpr char right_brace = RightInclusive ? ']' : ')';
const bool is_valid =
(LeftInclusive ? value >= lower_bound : value > lower_bound)
and (RightInclusive ? value <= upper_bound : value < upper_bound);
if (not is_valid)
throw std::out_of_range(std::format(
"Value `{}` must be in interval {}{}, {}{}!",
value,
left_brace,
lower_bound,
upper_bound,
right_brace
));
};
}
} // namespace action
} // namespace ap