7#define CLI11_ENABLE_EXTRA_VALIDATORS 1
10#if (defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS == 1) || \
11 (!defined(CLI11_DISABLE_EXTRA_VALIDATORS) || CLI11_DISABLE_EXTRA_VALIDATORS == 0)
16#include "StringTools.hpp"
17#include "Validators.hpp"
51 :
Validator(validator_name, [](std::string &input_string) {
52 using CLI::detail::lexical_cast;
53 auto val = DesiredType();
54 if(!lexical_cast(input_string, val)) {
55 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
72 template <
typename T>
Bound(T min_val, T max_val) {
73 std::stringstream out;
74 out << detail::type_name<T>() <<
" bounded to [" << min_val <<
" - " << max_val <<
"]";
77 func_ = [min_val, max_val](std::string &input) {
78 using CLI::detail::lexical_cast;
80 bool converted = lexical_cast(input, val);
82 return std::string(
"Value ") + input +
" could not be converted";
85 input = detail::to_string(min_val);
86 else if(val > max_val)
87 input = detail::to_string(max_val);
94 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<T>(0), max_val) {}
100const detail::IPV4Validator ValidIPV4;
104 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
105auto smart_deref(T value) ->
decltype(*value) {
111 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
112typename std::remove_reference<T>::type &smart_deref(T &value) {
117template <
typename T> std::string generate_set(
const T &set) {
118 using element_t =
typename detail::element_type<T>::type;
119 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
120 std::string out(1,
'{');
121 out.append(detail::join(
122 detail::smart_deref(set),
130template <
typename T> std::string generate_map(
const T &map,
bool key_only =
false) {
131 using element_t =
typename detail::element_type<T>::type;
132 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
133 std::string out(1,
'{');
134 out.append(detail::join(
135 detail::smart_deref(map),
136 [key_only](
const iteration_type_t &v) {
151 template <
typename CC,
typename VV>
152 static auto test(
int) ->
decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
153 template <
typename,
typename>
static auto test(...) ->
decltype(std::false_type());
155 static const auto value =
decltype(test<C, V>(0))::value;
156 using type = std::integral_constant<bool, value>;
160template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
161auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
162 using element_t =
typename detail::element_type<T>::type;
163 auto &setref = detail::smart_deref(set);
164 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](
decltype(*std::begin(setref)) v) {
167 return {(it != std::end(setref)), it};
171template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
172auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
173 auto &setref = detail::smart_deref(set);
174 auto it = setref.find(val);
175 return {(it != std::end(setref)), it};
179template <
typename T,
typename V>
180auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
181 -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
182 using element_t =
typename detail::element_type<T>::type;
184 auto res = search(set, val);
185 if((res.first) || (!(filter_function))) {
189 auto &setref = detail::smart_deref(set);
190 auto it = std::find_if(std::begin(setref), std::end(setref), [&](
decltype(*std::begin(setref)) v) {
192 a = filter_function(a);
195 return {(it != std::end(setref)), it};
202 using filter_fn_t = std::function<std::string(std::string)>;
205 template <
typename T,
typename... Args>
206 IsMember(std::initializer_list<T> values, Args &&...args)
207 :
IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
210 template <
typename T>
explicit IsMember(T &&set) :
IsMember(std::forward<T>(set), nullptr) {}
214 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
218 using element_t =
typename detail::element_type<T>::type;
219 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
221 using local_item_t =
typename IsMemberType<item_t>::type;
225 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
228 desc_function_ = [set]() {
return detail::generate_set(detail::smart_deref(set)); };
232 func_ = [set, filter_fn](std::string &input) {
233 using CLI::detail::lexical_cast;
235 if(!lexical_cast(input, b)) {
241 auto res = detail::search(set, b, filter_fn);
249 return std::string{};
253 return input +
" not in " + detail::generate_set(detail::smart_deref(set));
258 template <
typename T,
typename... Args>
259 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
261 std::forward<T>(set),
262 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
267template <
typename T>
using TransformPairs = std::vector<std::pair<std::string, T>>;
272 using filter_fn_t = std::function<std::string(std::string)>;
275 template <
typename... Args>
276 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
277 :
Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
284 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
287 "mapping must produce value pairs");
290 using element_t =
typename detail::element_type<T>::type;
291 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
292 using local_item_t =
typename IsMemberType<item_t>::type;
296 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
299 desc_function_ = [mapping]() {
return detail::generate_map(detail::smart_deref(mapping)); };
301 func_ = [mapping, filter_fn](std::string &input) {
302 using CLI::detail::lexical_cast;
304 if(!lexical_cast(input, b)) {
305 return std::string();
311 auto res = detail::search(mapping, b, filter_fn);
315 return std::string{};
320 template <
typename T,
typename... Args>
321 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
323 std::forward<T>(mapping),
324 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
331 using filter_fn_t = std::function<std::string(std::string)>;
334 template <
typename... Args>
335 CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
336 :
CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
346 "mapping must produce value pairs");
349 using element_t =
typename detail::element_type<T>::type;
350 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
351 using local_item_t =
typename IsMemberType<item_t>::type;
353 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
356 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
358 auto tfunc = [mapping]() {
359 std::string out(
"value in ");
360 out += detail::generate_map(detail::smart_deref(mapping)) +
" OR {";
362 detail::smart_deref(mapping),
371 func_ = [mapping, tfunc, filter_fn](std::string &input) {
372 using CLI::detail::lexical_cast;
374 bool converted = lexical_cast(input, b);
379 auto res = detail::search(mapping, b, filter_fn);
382 return std::string{};
385 for(
const auto &v : detail::smart_deref(mapping)) {
387 if(output_string == input) {
388 return std::string();
392 return "Check " + input +
" " + tfunc() +
" FAILED";
397 template <
typename T,
typename... Args>
400 std::forward<T>(mapping),
401 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
406inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
409inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
412inline std::string ignore_space(std::string item) {
413 item.erase(std::remove(std::begin(item), std::end(item),
' '), std::end(item));
414 item.erase(std::remove(std::begin(item), std::end(item),
'\t'), std::end(item));
437 CASE_INSENSITIVE = 1,
440 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
443 template <
typename Number>
446 const std::string &unit_name =
"UNIT") {
447 description(generate_description<Number>(unit_name, opts));
448 validate_mapping(mapping, opts);
451 func_ = [mapping, opts](std::string &input) -> std::string {
454 detail::rtrim(input);
456 throw ValidationError(
"Input is empty");
460 auto unit_begin = input.end();
461 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
465 std::string unit{unit_begin, input.end()};
466 input.resize(
static_cast<std::size_t
>(std::distance(input.begin(), unit_begin)));
469 if(opts & UNIT_REQUIRED && unit.empty()) {
470 throw ValidationError(
"Missing mandatory unit");
472 if(opts & CASE_INSENSITIVE) {
473 unit = detail::to_lower(unit);
476 using CLI::detail::lexical_cast;
477 if(!lexical_cast(input, num)) {
478 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
479 detail::type_name<Number>());
486 auto it = mapping.find(unit);
487 if(it == mapping.end()) {
488 throw ValidationError(unit +
489 " unit not recognized. "
491 detail::generate_map(mapping,
true));
495 using CLI::detail::lexical_cast;
496 bool converted = lexical_cast(input, num);
498 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
499 detail::type_name<Number>());
502 bool ok = detail::checked_multiply(num, it->second);
504 throw ValidationError(detail::to_string(num) +
" multiplied by " + unit +
505 " factor would cause number overflow. Use smaller value.");
508 num =
static_cast<Number
>(it->second);
511 input = detail::to_string(num);
520 template <
typename Number>
static void validate_mapping(std::map<std::string, Number> &mapping,
Options opts) {
521 for(
auto &kv : mapping) {
522 if(kv.first.empty()) {
523 throw ValidationError(
"Unit must not be empty.");
525 if(!detail::isalpha(kv.first)) {
526 throw ValidationError(
"Unit must contain only letters.");
531 if(opts & CASE_INSENSITIVE) {
532 std::map<std::string, Number> lower_mapping;
533 for(
auto &kv : mapping) {
534 auto s = detail::to_lower(kv.first);
535 if(lower_mapping.count(s)) {
536 throw ValidationError(std::string(
"Several matching lowercase unit representations are found: ") +
539 lower_mapping[detail::to_lower(kv.first)] = kv.second;
541 mapping = std::move(lower_mapping);
546 template <
typename Number>
static std::string generate_description(
const std::string &
name,
Options opts) {
547 std::stringstream out;
548 out << detail::type_name<Number>() <<
' ';
549 if(opts & UNIT_REQUIRED) {
552 out <<
'[' <<
name <<
']';
575 using result_t = std::uint64_t;
588 static std::map<std::string, result_t> init_mapping(
bool kb_is_1000);
591 static std::map<std::string, result_t> get_mapping(
bool kb_is_1000);
594#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
596#if CLI11_HAS_FILESYSTEM
598enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
599class PermissionValidator :
public Validator {
601 explicit PermissionValidator(Permission permission);
606const detail::PermissionValidator ReadPermissions(detail::Permission::read);
609const detail::PermissionValidator WritePermissions(detail::Permission::write);
612const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
620#include "impl/ExtraValidators_inl.hpp"
Definition ExtraValidators.hpp:429
Options
Definition ExtraValidators.hpp:435
Definition ExtraValidators.hpp:573
AsSizeValue(bool kb_is_1000)
Definition ExtraValidators_inl.hpp:60
Produce a bounded range (factory). Min and max are inclusive.
Definition ExtraValidators.hpp:66
Bound(T min_val, T max_val)
Definition ExtraValidators.hpp:72
Bound(T max_val)
Range of one value is 0 to value.
Definition ExtraValidators.hpp:94
Verify items are in a set.
Definition ExtraValidators.hpp:200
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition ExtraValidators.hpp:210
IsMember(T set, F filter_function)
Definition ExtraValidators.hpp:214
IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest (string only currently)
Definition ExtraValidators.hpp:259
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition ExtraValidators.hpp:206
Validate the input as a particular type.
Definition ExtraValidators.hpp:48
Thrown when validation of results fails.
Definition Error.hpp:221
Some validators that are provided.
Definition Validators.hpp:54
Validator & description(std::string validator_desc)
Specify the type string.
Definition Validators.hpp:99
Validator & name(std::string validator_name)
Specify the type string.
Definition Validators.hpp:114
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition Validators.hpp:57
std::function< std::string(std::string &)> func_
Definition Validators.hpp:61
Validate the given string is a legal ipv4 address.
Definition ExtraValidators.hpp:40
Definition ExtraValidators.hpp:150
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition TypeTools.hpp:130
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value)
Definition TypeTools.hpp:140
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition TypeTools.hpp:136