8#if (defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0) || \
9 (!defined(CLI11_DISABLE_EXTRA_VALIDATORS) || CLI11_DISABLE_EXTRA_VALIDATORS == 0)
14#include "StringTools.hpp"
15#include "Validators.hpp"
22#include <initializer_list>
42class IPV4Validator :
public Validator {
50template <
typename DesiredType>
class TypeValidator :
public Validator {
52 explicit TypeValidator(
const std::string &validator_name)
53 : Validator(validator_name, [](std::string &input_string) {
54 using CLI::detail::lexical_cast;
55 auto val = DesiredType();
56 if(!lexical_cast(input_string, val)) {
57 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
61 TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
74 template <
typename T>
Bound(T min_val, T max_val) {
75 std::stringstream out;
76 out << detail::type_name<T>() <<
" bounded to [" << min_val <<
" - " << max_val <<
"]";
79 func_ = [min_val, max_val](std::string &input) {
80 using CLI::detail::lexical_cast;
82 bool converted = lexical_cast(input, val);
84 return std::string(
"Value ") + input +
" could not be converted";
87 input = detail::to_string(min_val);
88 else if(val > max_val)
89 input = detail::to_string(max_val);
96 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<T>(0), max_val) {}
102CLI11_MODULE_INLINE
const detail::IPV4Validator ValidIPV4;
106 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
107auto smart_deref(T value) ->
decltype(*value) {
113 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
114typename std::remove_reference<T>::type &smart_deref(T &value) {
119template <
typename T> std::string generate_set(
const T &set) {
120 using element_t =
typename detail::element_type<T>::type;
121 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
122 std::string out(1,
'{');
123 out.append(detail::join(
124 detail::smart_deref(set),
132template <
typename T> std::string generate_map(
const T &map,
bool key_only =
false) {
133 using element_t =
typename detail::element_type<T>::type;
134 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
135 std::string out(1,
'{');
136 out.append(detail::join(
137 detail::smart_deref(map),
138 [key_only](
const iteration_type_t &v) {
153 template <
typename CC,
typename VV>
154 static auto test(
int) ->
decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
155 template <
typename,
typename>
static auto test(...) ->
decltype(std::false_type());
157 static const auto value =
decltype(test<C, V>(0))::value;
158 using type = std::integral_constant<bool, value>;
162template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
163auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
164 using element_t =
typename detail::element_type<T>::type;
165 auto &setref = detail::smart_deref(set);
166 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](
decltype(*std::begin(setref)) v) {
169 return {(it != std::end(setref)), it};
173template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
174auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
175 auto &setref = detail::smart_deref(set);
176 auto it = setref.find(val);
177 return {(it != std::end(setref)), it};
181template <
typename T,
typename V>
182auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
183 -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
184 using element_t =
typename detail::element_type<T>::type;
186 auto res = search(set, val);
187 if((res.first) || (!(filter_function))) {
191 auto &setref = detail::smart_deref(set);
192 auto it = std::find_if(std::begin(setref), std::end(setref), [&](
decltype(*std::begin(setref)) v) {
194 a = filter_function(a);
197 return {(it != std::end(setref)), it};
204 using filter_fn_t = std::function<std::string(std::string)>;
207 template <
typename T,
typename... Args>
208 IsMember(std::initializer_list<T> values, Args &&...args)
209 :
IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
212 template <
typename T>
explicit IsMember(T &&set) :
IsMember(std::forward<T>(set), nullptr) {}
216 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
220 using element_t =
typename detail::element_type<T>::type;
221 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
223 using local_item_t =
typename IsMemberType<item_t>::type;
227 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
230 auto shared_set = std::make_shared<T>(std::move(set));
233 desc_function_ = [shared_set]() {
return detail::generate_set(detail::smart_deref(*shared_set)); };
237 func_ = [shared_set, filter_fn](std::string &input) {
238 using CLI::detail::lexical_cast;
240 if(!lexical_cast(input, b)) {
246 auto res = detail::search(*shared_set, b, filter_fn);
254 return std::string{};
258 return input +
" not in " + detail::generate_set(detail::smart_deref(*shared_set));
263 template <
typename T,
typename... Args>
264 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
266 std::forward<T>(set),
267 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
272template <
typename T>
using TransformPairs = std::vector<std::pair<std::string, T>>;
277 using filter_fn_t = std::function<std::string(std::string)>;
280 template <
typename... Args>
281 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
282 :
Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
289 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
292 "mapping must produce value pairs");
295 using element_t =
typename detail::element_type<T>::type;
296 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
297 using local_item_t =
typename IsMemberType<item_t>::type;
301 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
304 auto shared_mapping = std::make_shared<T>(std::move(mapping));
307 desc_function_ = [shared_mapping]() {
return detail::generate_map(detail::smart_deref(*shared_mapping)); };
309 func_ = [shared_mapping, filter_fn](std::string &input) {
310 using CLI::detail::lexical_cast;
312 if(!lexical_cast(input, b)) {
313 return std::string();
319 auto res = detail::search(*shared_mapping, b, filter_fn);
323 return std::string{};
328 template <
typename T,
typename... Args>
329 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
331 std::forward<T>(mapping),
332 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
339 using filter_fn_t = std::function<std::string(std::string)>;
342 template <
typename... Args>
343 CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
344 :
CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
354 "mapping must produce value pairs");
357 using element_t =
typename detail::element_type<T>::type;
358 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
359 using local_item_t =
typename IsMemberType<item_t>::type;
361 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
364 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
367 auto shared_mapping = std::make_shared<T>(std::move(mapping));
369 auto tfunc = [shared_mapping]() {
370 std::string out(
"value in ");
371 out += detail::generate_map(detail::smart_deref(*shared_mapping)) +
" OR {";
373 detail::smart_deref(*shared_mapping),
374 [](
const iteration_type_t &v) {
384 func_ = [shared_mapping, tfunc, filter_fn](std::string &input) {
385 using CLI::detail::lexical_cast;
387 bool converted = lexical_cast(input, b);
392 auto res = detail::search(*shared_mapping, b, filter_fn);
395 return std::string{};
398 for(
const auto &v : detail::smart_deref(*shared_mapping)) {
400 if(output_string == input) {
401 return std::string();
405 return "Check " + input +
" " + tfunc() +
" FAILED";
410 template <
typename T,
typename... Args>
413 std::forward<T>(mapping),
414 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
419inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
422inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
425inline std::string ignore_space(std::string item) {
426 item.erase(std::remove(std::begin(item), std::end(item),
' '), std::end(item));
427 item.erase(std::remove(std::begin(item), std::end(item),
'\t'), std::end(item));
442class AsNumberWithUnit :
public Validator {
450 CASE_INSENSITIVE = 1,
453 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
456 template <
typename Number>
459 const std::string &unit_name =
"UNIT") {
460 description(generate_description<Number>(unit_name, opts));
461 validate_mapping(mapping, opts);
464 func_ = [mapping, opts](std::string &input) -> std::string {
467 detail::rtrim(input);
469 throw ValidationError(
"Input is empty");
473 auto unit_begin = input.end();
474 const std::locale loc{};
475 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), loc)) {
479 std::string unit{unit_begin, input.end()};
480 input.resize(
static_cast<std::size_t
>(std::distance(input.begin(), unit_begin)));
483 if(opts & UNIT_REQUIRED && unit.empty()) {
484 throw ValidationError(
"Missing mandatory unit");
486 if(opts & CASE_INSENSITIVE) {
487 unit = detail::to_lower(unit);
490 using CLI::detail::lexical_cast;
491 if(!lexical_cast(input, num)) {
492 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
493 detail::type_name<Number>());
500 auto it = mapping.find(unit);
501 if(it == mapping.end()) {
502 throw ValidationError(unit +
503 " unit not recognized. "
505 detail::generate_map(mapping,
true));
509 using CLI::detail::lexical_cast;
510 bool converted = lexical_cast(input, num);
512 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
513 detail::type_name<Number>());
516 bool ok = detail::checked_multiply(num, it->second);
518 throw ValidationError(detail::to_string(num) +
" multiplied by " + unit +
519 " factor would cause number overflow. Use smaller value.");
522 num =
static_cast<Number
>(it->second);
525 input = detail::to_string(num);
534 template <
typename Number>
static void validate_mapping(std::map<std::string, Number> &mapping,
Options opts) {
535 for(
auto &kv : mapping) {
536 if(kv.first.empty()) {
537 throw ValidationError(
"Unit must not be empty.");
539 if(!detail::isalpha(kv.first)) {
540 throw ValidationError(
"Unit must contain only letters.");
545 if(opts & CASE_INSENSITIVE) {
546 std::map<std::string, Number> lower_mapping;
547 for(
auto &kv : mapping) {
548 auto s = detail::to_lower(kv.first);
549 if(lower_mapping.count(s)) {
550 throw ValidationError(std::string(
"Several matching lowercase unit representations are found: ") +
553 lower_mapping[std::move(s)] = kv.second;
555 mapping = std::move(lower_mapping);
560 template <
typename Number>
static std::string generate_description(
const std::string &
name,
Options opts) {
561 std::stringstream out;
562 out << detail::type_name<Number>() <<
' ';
563 if(opts & UNIT_REQUIRED) {
566 out <<
'[' <<
name <<
']';
589 using result_t = std::uint64_t;
602 static std::map<std::string, result_t> init_mapping(
bool kb_is_1000);
605 static const std::map<std::string, result_t> &get_mapping(
bool kb_is_1000);
608#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
610#if CLI11_HAS_FILESYSTEM
612enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
613class PermissionValidator :
public Validator {
615 explicit PermissionValidator(Permission permission);
619class FileSizeValidator :
public Validator {
621 explicit FileSizeValidator(std::uint64_t min_size, std::uint64_t max_size = 0);
625CLI11_MODULE_INLINE
const detail::PermissionValidator ReadPermissions(detail::Permission::read);
628CLI11_MODULE_INLINE
const detail::PermissionValidator WritePermissions(detail::Permission::write);
631CLI11_MODULE_INLINE
const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
634CLI11_MODULE_INLINE
const FileSizeValidator NonEmptyFile(1, 0);
642#include "impl/ExtraValidators_inl.hpp"
Definition ExtraValidators.hpp:442
Options
Definition ExtraValidators.hpp:448
AsSizeValue(bool kb_is_1000)
Definition ExtraValidators_inl.hpp:60
Bound(T min_val, T max_val)
Definition ExtraValidators.hpp:74
Bound(T max_val)
Range of one value is 0 to value.
Definition ExtraValidators.hpp:96
IsMember(T &&set)
This checks to see if an item is in a set (empty function).
Definition ExtraValidators.hpp:212
IsMember(T set, F filter_function)
Definition ExtraValidators.hpp:216
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:264
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition ExtraValidators.hpp:208
Validate the input as a particular type.
Definition ExtraValidators.hpp:50
Thrown when validation of results fails.
Definition Error.hpp:222
Some validators that are provided.
Definition Validators.hpp:55
Validator & description(std::string validator_desc)
Specify the type string.
Definition Validators.hpp:96
Validator & name(std::string validator_name)
Specify the type string.
Definition Validators.hpp:106
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition Validators.hpp:58
std::function< std::string(std::string &)> func_
Definition Validators.hpp:62
Definition ExtraValidators.hpp:152
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition TypeTools.hpp:133
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value).
Definition TypeTools.hpp:143
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value).
Definition TypeTools.hpp:139