10#include "vipra/concepts/numeric.hpp"
13enum ArgType : uint8_t {
16 VALUE_REQUIRED = 0x02,
20inline constexpr auto operator|(ArgType Lhs, ArgType Rhs) -> ArgType
22 return static_cast<ArgType
>(
static_cast<std::underlying_type_t<ArgType>
>(Lhs) |
23 static_cast<std::underlying_type_t<ArgType>
>(Rhs));
26inline constexpr auto operator&(ArgType Lhs, ArgType Rhs) -> ArgType
28 return static_cast<ArgType
>(
static_cast<std::underlying_type_t<ArgType>
>(Lhs) &
29 static_cast<std::underlying_type_t<ArgType>
>(Rhs));
32inline constexpr auto operator==(ArgType Lhs, ArgType Rhs) ->
bool
34 return static_cast<std::underlying_type_t<ArgType>
>(Lhs) ==
35 static_cast<std::underlying_type_t<ArgType>
>(Rhs);
38inline constexpr auto operator!=(ArgType Lhs, ArgType Rhs) ->
bool
40 return static_cast<std::underlying_type_t<ArgType>
>(Lhs) !=
41 static_cast<std::underlying_type_t<ArgType>
>(Rhs);
46 using ArgsMap = std::map<std::string, std::string, std::less<>>;
47 using ArgsSet = std::set<std::string, std::less<>>;
55 static void parse(
int argc,
const char*
const* argv)
58 auto args = format(argc, argv);
60 for (
auto arg = std::next(args.begin()); arg != args.end(); ++arg ) {
61 if ( arg->length() < 2 )
throw std::runtime_error(
"Unknown Flag: " + *arg);
62 if ( (*arg)[0] !=
'-' )
throw std::runtime_error(
"Unknown Flag: " + *arg);
64 auto [flag, val] = split_arg(*arg);
66 auto [fullValid, fullError] = validate_flag(flag, val);
68 get_args()[flag] = val;
72 auto [compositeValid, compositeError] = validate_composite_flag(flag);
73 if ( compositeValid ) {
77 throw std::runtime_error(fullError +
": " += flag);
89 get_arg_map()[key] = ArgType::OPTIONAL;
100 if ( type & ArgType::REQUIRED ) get_req_set().insert(key);
101 get_arg_map()[key] = type;
110 static void register_arg(std::string
const& key, std::string
const& defaultValue,
113 if ( type & ArgType::REQUIRED ) get_req_set().insert(key);
114 get_arg_map()[key] = type;
115 get_defaults()[key] = defaultValue;
125 static auto has(std::string_view key) ->
bool
127 if ( get_defaults().find(key) != get_defaults().end() ) {
131 return get_args().find(key) != get_args().end();
140 template <
typename val_t = std::
string>
141 [[nodiscard]]
static auto get(std::string_view key) -> val_t
143 auto iter = get_args().find(key);
144 if ( iter == get_args().end() ) {
145 iter = get_defaults().find(key);
146 if ( iter == get_defaults().end() )
147 throw std::out_of_range(
"Attempt To Access Missing Argument:" + std::string(key));
151 return static_cast<val_t
>(std::stof(iter->second));
163 static auto count() ->
size_t {
return get_args().size(); }
171 get_arg_map().clear();
172 get_req_set().clear();
182 static auto split_arg(std::string_view arg) -> std::pair<std::string, std::string>
184 auto loc = arg.find(
'=');
185 if ( loc == std::string::npos )
186 return std::make_pair(std::string(arg.begin() + 1),
"");
188 return std::make_pair(std::string(arg.begin() + 1, loc - 1),
189 std::string(arg.begin() + loc + 1, arg.length() - (loc + 1)));
192 static auto split_single_letter_args(std::string_view arg) -> std::vector<std::string>
194 std::vector<std::string> args;
195 for (
auto chr : arg ) {
196 args.emplace_back(1, chr);
207 static auto validate_composite_flag(std::string
const& arg)
208 -> std::pair<bool, std::string>
210 auto flags = split_single_letter_args(arg);
211 for (
const auto& flag : flags ) {
212 auto valid = validate_flag(flag,
"");
213 if ( ! valid.first )
return valid;
214 get_args()[flag] =
"";
225 static auto validate_flag(std::string_view flag,
226 std::string_view value) -> std::pair<bool, std::string>
228 auto& argSet = get_arg_map();
229 auto iter = argSet.find(flag);
230 if ( iter == argSet.end() )
return {
false,
"Unknown Flag"};
232 auto type = iter->second;
234 if ( (type & ArgType::VALUE_REQUIRED) == ArgType::VALUE_REQUIRED ) {
235 if ( value.empty() )
return {
false,
"Required Value Missing"};
246 static void check_required()
248 for (
const auto& arg : get_req_set() ) {
250 throw std::runtime_error(
"Missing Flag: " + arg);
262 static auto format(
int argc,
const char*
const* argv) -> std::vector<std::string>
264 return std::vector<std::string>{argv,
265 std::next(argv,
static_cast<std::ptrdiff_t
>(argc))};
268 static inline auto get_arg_map() -> std::map<std::string, ArgType, std::less<>>&
270 static std::map<std::string, ArgType, std::less<>> argSet;
274 static inline auto get_req_set() -> ArgsSet&
276 static ArgsSet reqSet;
280 static inline auto get_args() -> ArgsMap&
286 static inline auto get_defaults() -> ArgsMap&
288 static ArgsMap defaults{};
static auto get(std::string_view key) -> val_t
Returns the argument with the given key.
Definition cli_arguments.hpp:141
static auto count() -> size_t
Returns the number of arguments.
Definition cli_arguments.hpp:163
static auto has(std::string_view key) -> bool
Returns true if the argument is present.
Definition cli_arguments.hpp:125
static void parse(int argc, const char *const *argv)
Parses out the arguments passed into the program.
Definition cli_arguments.hpp:55
static void reset()
Clears the registered arguments.
Definition cli_arguments.hpp:169
static void register_arg(std::string const &key, ArgType type)
Adds an argument flag that can be accepted, and sets its type.
Definition cli_arguments.hpp:98
static void register_arg(std::string const &key)
Adds an argument flag that can be accepted.
Definition cli_arguments.hpp:87
static void register_arg(std::string const &key, std::string const &defaultValue, ArgType type)
Adds an argument flag that can be accepted, sets its type and provides a default value.
Definition cli_arguments.hpp:110
Checks that a type is a numeric type.
Definition numeric.hpp:13