13#include "StringTools.hpp"
14#include "TypeTools.hpp"
31#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
62 std::function<std::string(std::string &)>
func_{[](std::string &) {
return std::string{}; }};
72 Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
76 Validator() =
default;
80 Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name =
"")
82 name_(std::move(validator_name)) {}
85 func_ = std::move(op);
90 std::string
operator()(std::string &str)
const;
95 std::string value = str;
112 return std::string{};
116 name_ = std::move(validator_name);
122 newval.
name_ = std::move(validator_name);
175 void _merge_description(
const Validator &val1,
const Validator &val2,
const std::string &merger);
188enum class path_type : std::uint8_t { nonexistent, file, directory };
191CLI11_INLINE path_type check_path(
const char *file)
noexcept;
254 :
Validator(validator_name, [](std::string &input_string) {
255 using CLI::detail::lexical_cast;
256 auto val = DesiredType();
257 if(!lexical_cast(input_string, val)) {
258 return std::string(
"Failed parsing ") + input_string +
" as a " + detail::type_name<DesiredType>();
260 return std::string();
272 explicit FileOnDefaultPath(std::string default_path,
bool enableErrorReturn =
true);
282 template <
typename T>
283 Range(T min_val, T max_val,
const std::string &validator_name = std::string{}) :
Validator(validator_name) {
284 if(validator_name.empty()) {
285 std::stringstream out;
286 out << detail::type_name<T>() <<
" in [" << min_val <<
" - " << max_val <<
"]";
287 description(out.str());
290 func_ = [min_val, max_val](std::string &input) {
291 using CLI::detail::lexical_cast;
293 bool converted = lexical_cast(input, val);
294 if((!converted) || (val < min_val || val > max_val)) {
295 std::stringstream out;
296 out <<
"Value " << input <<
" not in range [";
297 out << min_val <<
" - " << max_val <<
"]";
300 return std::string{};
305 template <
typename T>
306 explicit Range(T max_val,
const std::string &validator_name = std::string{})
307 :
Range(static_cast<T>(0), max_val, validator_name) {}
311const Range NonNegativeNumber((std::numeric_limits<double>::max)(),
"NONNEGATIVE");
314const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(),
"POSITIVE");
323 template <
typename T>
Bound(T min_val, T max_val) {
324 std::stringstream out;
325 out << detail::type_name<T>() <<
" bounded to [" << min_val <<
" - " << max_val <<
"]";
326 description(out.str());
328 func_ = [min_val, max_val](std::string &input) {
329 using CLI::detail::lexical_cast;
331 bool converted = lexical_cast(input, val);
333 return std::string(
"Value ") + input +
" could not be converted";
336 input = detail::to_string(min_val);
337 else if(val > max_val)
338 input = detail::to_string(max_val);
340 return std::string{};
345 template <
typename T>
explicit Bound(T max_val) :
Bound(static_cast<T>(0), max_val) {}
350 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
351auto smart_deref(T value) ->
decltype(*value) {
357 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
358typename std::remove_reference<T>::type &smart_deref(T &value) {
363template <
typename T> std::string generate_set(
const T &set) {
364 using element_t =
typename detail::element_type<T>::type;
365 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
366 std::string out(1,
'{');
367 out.append(detail::join(
368 detail::smart_deref(set),
369 [](
const iteration_type_t &v) {
return detail::pair_adaptor<element_t>::first(v); },
376template <
typename T> std::string generate_map(
const T &map,
bool key_only =
false) {
377 using element_t =
typename detail::element_type<T>::type;
378 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
379 std::string out(1,
'{');
380 out.append(detail::join(
381 detail::smart_deref(map),
382 [key_only](
const iteration_type_t &v) {
383 std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
387 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
397 template <
typename CC,
typename VV>
398 static auto test(
int) ->
decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
399 template <
typename,
typename>
static auto test(...) ->
decltype(std::false_type());
401 static const auto value =
decltype(test<C, V>(0))::value;
402 using type = std::integral_constant<bool, value>;
406template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
407auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
408 using element_t =
typename detail::element_type<T>::type;
409 auto &setref = detail::smart_deref(set);
410 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](
decltype(*std::begin(setref)) v) {
413 return {(it != std::end(setref)), it};
417template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
418auto search(
const T &set,
const V &val) -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
419 auto &setref = detail::smart_deref(set);
420 auto it = setref.find(val);
421 return {(it != std::end(setref)), it};
425template <
typename T,
typename V>
426auto search(
const T &set,
const V &val,
const std::function<V(V)> &filter_function)
427 -> std::pair<bool,
decltype(std::begin(detail::smart_deref(set)))> {
428 using element_t =
typename detail::element_type<T>::type;
430 auto res = search(set, val);
431 if((res.first) || (!(filter_function))) {
435 auto &setref = detail::smart_deref(set);
436 auto it = std::find_if(std::begin(setref), std::end(setref), [&](
decltype(*std::begin(setref)) v) {
437 V a{detail::pair_adaptor<element_t>::first(v)};
438 a = filter_function(a);
441 return {(it != std::end(setref)), it};
449inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
450 if((a > 0) == (b > 0)) {
451 return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
453 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
457inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(
const T &a,
const T &b) {
458 return ((std::numeric_limits<T>::max)() / a < b);
462template <
typename T>
typename std::enable_if<std::is_integral<T>::value,
bool>::type checked_multiply(T &a, T b) {
463 if(a == 0 || b == 0 || a == 1 || b == 1) {
467 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
470 if(overflowCheck(a, b)) {
479typename std::enable_if<std::is_floating_point<T>::value,
bool>::type checked_multiply(T &a, T b) {
481 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
492 using filter_fn_t = std::function<std::string(std::string)>;
495 template <
typename T,
typename... Args>
496 IsMember(std::initializer_list<T> values, Args &&...args)
497 :
IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
500 template <
typename T>
explicit IsMember(T &&set) :
IsMember(std::forward<T>(set), nullptr) {}
504 template <
typename T,
typename F>
explicit IsMember(T set, F filter_function) {
508 using element_t =
typename detail::element_type<T>::type;
509 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
511 using local_item_t =
typename IsMemberType<item_t>::type;
515 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
518 desc_function_ = [set]() {
return detail::generate_set(detail::smart_deref(set)); };
522 func_ = [set, filter_fn](std::string &input) {
523 using CLI::detail::lexical_cast;
525 if(!lexical_cast(input, b)) {
531 auto res = detail::search(set, b, filter_fn);
539 return std::string{};
543 return input +
" not in " + detail::generate_set(detail::smart_deref(set));
548 template <
typename T,
typename... Args>
549 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
551 std::forward<T>(set),
552 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
557template <
typename T>
using TransformPairs = std::vector<std::pair<std::string, T>>;
562 using filter_fn_t = std::function<std::string(std::string)>;
565 template <
typename... Args>
566 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
567 :
Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
574 template <
typename T,
typename F>
explicit Transformer(T mapping, F filter_function) {
577 "mapping must produce value pairs");
580 using element_t =
typename detail::element_type<T>::type;
581 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
582 using local_item_t =
typename IsMemberType<item_t>::type;
586 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
589 desc_function_ = [mapping]() {
return detail::generate_map(detail::smart_deref(mapping)); };
591 func_ = [mapping, filter_fn](std::string &input) {
592 using CLI::detail::lexical_cast;
594 if(!lexical_cast(input, b)) {
595 return std::string();
601 auto res = detail::search(mapping, b, filter_fn);
605 return std::string{};
610 template <
typename T,
typename... Args>
611 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
613 std::forward<T>(mapping),
614 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
621 using filter_fn_t = std::function<std::string(std::string)>;
624 template <
typename... Args>
625 CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
626 :
CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
636 "mapping must produce value pairs");
639 using element_t =
typename detail::element_type<T>::type;
640 using item_t =
typename detail::pair_adaptor<element_t>::first_type;
641 using local_item_t =
typename IsMemberType<item_t>::type;
643 using iteration_type_t =
typename detail::pair_adaptor<element_t>::value_type;
646 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
648 auto tfunc = [mapping]() {
649 std::string out(
"value in ");
650 out += detail::generate_map(detail::smart_deref(mapping)) +
" OR {";
652 detail::smart_deref(mapping),
659 desc_function_ = tfunc;
661 func_ = [mapping, tfunc, filter_fn](std::string &input) {
662 using CLI::detail::lexical_cast;
664 bool converted = lexical_cast(input, b);
669 auto res = detail::search(mapping, b, filter_fn);
672 return std::string{};
675 for(
const auto &v : detail::smart_deref(mapping)) {
677 if(output_string == input) {
678 return std::string();
682 return "Check " + input +
" " + tfunc() +
" FAILED";
687 template <
typename T,
typename... Args>
690 std::forward<T>(mapping),
691 [filter_fn_1, filter_fn_2](std::string a) {
return filter_fn_2(filter_fn_1(a)); },
696inline std::string ignore_case(std::string item) {
return detail::to_lower(item); }
699inline std::string ignore_underscore(std::string item) {
return detail::remove_underscore(item); }
702inline std::string ignore_space(std::string item) {
703 item.erase(std::remove(std::begin(item), std::end(item),
' '), std::end(item));
704 item.erase(std::remove(std::begin(item), std::end(item),
'\t'), std::end(item));
727 CASE_INSENSITIVE = 1,
730 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
733 template <
typename Number>
735 Options opts = DEFAULT,
736 const std::string &unit_name =
"UNIT") {
737 description(generate_description<Number>(unit_name, opts));
738 validate_mapping(mapping, opts);
741 func_ = [mapping, opts](std::string &input) -> std::string {
744 detail::rtrim(input);
746 throw ValidationError(
"Input is empty");
750 auto unit_begin = input.end();
751 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
755 std::string unit{unit_begin, input.end()};
756 input.resize(
static_cast<std::size_t
>(std::distance(input.begin(), unit_begin)));
759 if(opts & UNIT_REQUIRED && unit.empty()) {
760 throw ValidationError(
"Missing mandatory unit");
762 if(opts & CASE_INSENSITIVE) {
763 unit = detail::to_lower(unit);
766 using CLI::detail::lexical_cast;
767 if(!lexical_cast(input, num)) {
768 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
769 detail::type_name<Number>());
776 auto it = mapping.find(unit);
777 if(it == mapping.end()) {
778 throw ValidationError(unit +
779 " unit not recognized. "
781 detail::generate_map(mapping,
true));
785 using CLI::detail::lexical_cast;
786 bool converted = lexical_cast(input, num);
788 throw ValidationError(std::string(
"Value ") + input +
" could not be converted to " +
789 detail::type_name<Number>());
792 bool ok = detail::checked_multiply(num, it->second);
794 throw ValidationError(detail::to_string(num) +
" multiplied by " + unit +
795 " factor would cause number overflow. Use smaller value.");
798 num =
static_cast<Number
>(it->second);
801 input = detail::to_string(num);
810 template <
typename Number>
static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
811 for(
auto &kv : mapping) {
812 if(kv.first.empty()) {
813 throw ValidationError(
"Unit must not be empty.");
815 if(!detail::isalpha(kv.first)) {
816 throw ValidationError(
"Unit must contain only letters.");
821 if(opts & CASE_INSENSITIVE) {
822 std::map<std::string, Number> lower_mapping;
823 for(
auto &kv : mapping) {
824 auto s = detail::to_lower(kv.first);
825 if(lower_mapping.count(s)) {
826 throw ValidationError(std::string(
"Several matching lowercase unit representations are found: ") +
829 lower_mapping[detail::to_lower(kv.first)] = kv.second;
831 mapping = std::move(lower_mapping);
836 template <
typename Number>
static std::string generate_description(
const std::string &name, Options opts) {
837 std::stringstream out;
838 out << detail::type_name<Number>() <<
' ';
839 if(opts & UNIT_REQUIRED) {
842 out <<
'[' << name <<
']';
848inline AsNumberWithUnit::Options operator|(
const AsNumberWithUnit::Options &a,
const AsNumberWithUnit::Options &b) {
849 return static_cast<AsNumberWithUnit::Options
>(
static_cast<int>(a) |
static_cast<int>(b));
865 using result_t = std::uint64_t;
878 static std::map<std::string, result_t> init_mapping(
bool kb_is_1000);
881 static std::map<std::string, result_t> get_mapping(
bool kb_is_1000);
889CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
898#include "impl/Validators_inl.hpp"
Definition Validators.hpp:719
Options
Definition Validators.hpp:725
Definition Validators.hpp:863
Produce a bounded range (factory). Min and max are inclusive.
Definition Validators.hpp:317
Bound(T min_val, T max_val)
Definition Validators.hpp:323
Bound(T max_val)
Range of one value is 0 to value.
Definition Validators.hpp:345
Class wrapping some of the accessors of Validator.
Definition Validators.hpp:179
Definition Validators.hpp:270
Verify items are in a set.
Definition Validators.hpp:490
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition Validators.hpp:500
IsMember(T set, F filter_function)
Definition Validators.hpp:504
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 Validators.hpp:549
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition Validators.hpp:496
Produce a range (factory). Min and max are inclusive.
Definition Validators.hpp:276
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition Validators.hpp:283
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition Validators.hpp:306
Validate the input as a particular type.
Definition Validators.hpp:251
Thrown when validation of results fails.
Definition Error.hpp:221
Some validators that are provided.
Definition Validators.hpp:55
Validator operator&(const Validator &other) const
Definition Validators_inl.hpp:45
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Definition Validators.hpp:156
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition Validators.hpp:66
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition Validators.hpp:140
Validator & description(std::string validator_desc)
Specify the type string.
Definition Validators.hpp:100
std::string operator()(const std::string &str) const
Definition Validators.hpp:94
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Definition Validators.hpp:150
Validator operator|(const Validator &other) const
Definition Validators_inl.hpp:67
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Definition Validators.hpp:158
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition Validators.hpp:68
bool non_modifying_
specify that a validator should not modify the input
Definition Validators.hpp:70
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition Validators.hpp:78
Validator & name(std::string validator_name)
Specify the type string.
Definition Validators.hpp:115
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
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
Definition Validators.hpp:108
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition Validators.hpp:133
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
Definition Validators.hpp:126
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition Validators.hpp:128
std::string name_
The name for search purposes of the Validator.
Definition Validators.hpp:64
CLI11_NODISCARD bool get_modifying() const
Get a boolean if the validator is allowed to modify the input returns true if it can modify the input...
Definition Validators.hpp:161
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
Definition Validators.hpp:120
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition Validators_inl.hpp:89
std::string operator()(std::string &str) const
Definition Validators_inl.hpp:26
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition Validators.hpp:145
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition Validators.hpp:80
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition Validators.hpp:84
Check for an existing directory (returns error message if check fails)
Definition Validators.hpp:200
Check for an existing file (returns error message if check fails)
Definition Validators.hpp:194
Check for an existing path.
Definition Validators.hpp:206
Validate the given string is a legal ipv4 address.
Definition Validators.hpp:218
Check for an non-existing path.
Definition Validators.hpp:212
Definition Validators.hpp:396
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition TypeTools.hpp:130