CLI11
C++11 Command Line Interface Parser
Loading...
Searching...
No Matches
Validators.hpp
1// Copyright (c) 2017-2024, University of Cincinnati, developed by Henry Schreiner
2// under NSF AWARD 1414736 and by the respective contributors.
3// All rights reserved.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6
7#pragma once
8
9// IWYU pragma: private, include "CLI/CLI.hpp"
10
11#include "Error.hpp"
12#include "Macros.hpp"
13#include "StringTools.hpp"
14#include "TypeTools.hpp"
15
16// [CLI11:public_includes:set]
17#include <cmath>
18#include <cstdint>
19#include <functional>
20#include <iostream>
21#include <limits>
22#include <map>
23#include <memory>
24#include <string>
25#include <utility>
26#include <vector>
27// [CLI11:public_includes:end]
28
29// [CLI11:validators_hpp_filesystem:verbatim]
30
31#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
32#include <filesystem> // NOLINT(build/include)
33#else
34#include <sys/stat.h>
35#include <sys/types.h>
36#endif
37
38// [CLI11:validators_hpp_filesystem:end]
39
40namespace CLI {
41// [CLI11:validators_hpp:verbatim]
42
43class Option;
44
46
53
55class Validator {
56 protected:
58 std::function<std::string()> desc_function_{[]() { return std::string{}; }};
59
62 std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
64 std::string name_{};
68 bool active_{true};
70 bool non_modifying_{false};
71
72 Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
73 : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {}
74
75 public:
76 Validator() = default;
78 explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
80 Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
81 : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
82 name_(std::move(validator_name)) {}
84 Validator &operation(std::function<std::string(std::string &)> op) {
85 func_ = std::move(op);
86 return *this;
87 }
90 std::string operator()(std::string &str) const;
91
94 std::string operator()(const std::string &str) const {
95 std::string value = str;
96 return (active_) ? func_(value) : std::string{};
97 }
98
100 Validator &description(std::string validator_desc) {
101 desc_function_ = [validator_desc]() { return validator_desc; };
102 return *this;
103 }
105 CLI11_NODISCARD Validator description(std::string validator_desc) const;
106
108 CLI11_NODISCARD std::string get_description() const {
109 if(active_) {
110 return desc_function_();
111 }
112 return std::string{};
113 }
115 Validator &name(std::string validator_name) {
116 name_ = std::move(validator_name);
117 return *this;
118 }
120 CLI11_NODISCARD Validator name(std::string validator_name) const {
121 Validator newval(*this);
122 newval.name_ = std::move(validator_name);
123 return newval;
124 }
126 CLI11_NODISCARD const std::string &get_name() const { return name_; }
128 Validator &active(bool active_val = true) {
129 active_ = active_val;
130 return *this;
131 }
133 CLI11_NODISCARD Validator active(bool active_val = true) const {
134 Validator newval(*this);
135 newval.active_ = active_val;
136 return newval;
137 }
138
140 Validator &non_modifying(bool no_modify = true) {
141 non_modifying_ = no_modify;
142 return *this;
143 }
145 Validator &application_index(int app_index) {
146 application_index_ = app_index;
147 return *this;
148 }
150 CLI11_NODISCARD Validator application_index(int app_index) const {
151 Validator newval(*this);
152 newval.application_index_ = app_index;
153 return newval;
154 }
156 CLI11_NODISCARD int get_application_index() const { return application_index_; }
158 CLI11_NODISCARD bool get_active() const { return active_; }
159
161 CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; }
162
165 Validator operator&(const Validator &other) const;
166
169 Validator operator|(const Validator &other) const;
170
172 Validator operator!() const;
173
174 private:
175 void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger);
176};
177
180 public:
181};
182// The implementation of the built in validators is using the Validator class;
183// the user is only expected to use the const (static) versions (since there's no setup).
184// Therefore, this is in detail.
185namespace detail {
186
188enum class path_type { nonexistent, file, directory };
189
191CLI11_INLINE path_type check_path(const char *file) noexcept;
192
195 public:
197};
198
201 public:
203};
204
207 public:
209};
210
213 public:
215};
216
218class IPV4Validator : public Validator {
219 public:
221};
222
224 public:
226};
227
228} // namespace detail
229
230// Static is not needed here, because global const implies static.
231
233const detail::ExistingFileValidator ExistingFile;
234
236const detail::ExistingDirectoryValidator ExistingDirectory;
237
239const detail::ExistingPathValidator ExistingPath;
240
242const detail::NonexistentPathValidator NonexistentPath;
243
245const detail::IPV4Validator ValidIPV4;
246
248const detail::EscapedStringTransformer EscapedString;
249
251template <typename DesiredType> class TypeValidator : public Validator {
252 public:
253 explicit TypeValidator(const std::string &validator_name)
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>();
259 }
260 return std::string();
261 }) {}
262 TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
263};
264
266const TypeValidator<double> Number("NUMBER");
267
271 public:
272 explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true);
273};
274
276class Range : public Validator {
277 public:
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());
288 }
289
290 func_ = [min_val, max_val](std::string &input) {
291 using CLI::detail::lexical_cast;
292 T val;
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 << "]";
298 return out.str();
299 }
300 return std::string{};
301 };
302 }
303
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) {}
308};
309
311const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
312
314const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
315
317class Bound : public Validator {
318 public:
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());
327
328 func_ = [min_val, max_val](std::string &input) {
329 using CLI::detail::lexical_cast;
330 T val;
331 bool converted = lexical_cast(input, val);
332 if(!converted) {
333 return std::string("Value ") + input + " could not be converted";
334 }
335 if(val < min_val)
336 input = detail::to_string(min_val);
337 else if(val > max_val)
338 input = detail::to_string(max_val);
339
340 return std::string{};
341 };
342 }
343
345 template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
346};
347
348namespace detail {
349template <typename T,
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) {
352 return *value;
353}
354
355template <
356 typename T,
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) {
359 return value;
360}
362template <typename T> std::string generate_set(const T &set) {
363 using element_t = typename detail::element_type<T>::type;
364 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
365 std::string out(1, '{');
366 out.append(detail::join(
367 detail::smart_deref(set),
368 [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
369 ","));
370 out.push_back('}');
371 return out;
372}
373
375template <typename T> std::string generate_map(const T &map, bool key_only = false) {
376 using element_t = typename detail::element_type<T>::type;
377 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
378 std::string out(1, '{');
379 out.append(detail::join(
380 detail::smart_deref(map),
381 [key_only](const iteration_type_t &v) {
382 std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
383
384 if(!key_only) {
385 res.append("->");
386 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
387 }
388 return res;
389 },
390 ","));
391 out.push_back('}');
392 return out;
393}
394
395template <typename C, typename V> struct has_find {
396 template <typename CC, typename VV>
397 static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
398 template <typename, typename> static auto test(...) -> decltype(std::false_type());
399
400 static const auto value = decltype(test<C, V>(0))::value;
401 using type = std::integral_constant<bool, value>;
402};
403
405template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
406auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
407 using element_t = typename detail::element_type<T>::type;
408 auto &setref = detail::smart_deref(set);
409 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
411 });
412 return {(it != std::end(setref)), it};
413}
414
416template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
417auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
418 auto &setref = detail::smart_deref(set);
419 auto it = setref.find(val);
420 return {(it != std::end(setref)), it};
421}
422
424template <typename T, typename V>
425auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
426 -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
427 using element_t = typename detail::element_type<T>::type;
428 // do the potentially faster first search
429 auto res = search(set, val);
430 if((res.first) || (!(filter_function))) {
431 return res;
432 }
433 // if we haven't found it do the longer linear search with all the element translations
434 auto &setref = detail::smart_deref(set);
435 auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
437 a = filter_function(a);
438 return (a == val);
439 });
440 return {(it != std::end(setref)), it};
441}
442
443// the following suggestion was made by Nikita Ofitserov(@himikof)
444// done in templates to prevent compiler warnings on negation of unsigned numbers
445
447template <typename T>
448inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
449 if((a > 0) == (b > 0)) {
450 return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
451 }
452 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
453}
455template <typename T>
456inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
457 return ((std::numeric_limits<T>::max)() / a < b);
458}
459
461template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
462 if(a == 0 || b == 0 || a == 1 || b == 1) {
463 a *= b;
464 return true;
465 }
466 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
467 return false;
468 }
469 if(overflowCheck(a, b)) {
470 return false;
471 }
472 a *= b;
473 return true;
474}
475
477template <typename T>
478typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
479 T c = a * b;
480 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
481 return false;
482 }
483 a = c;
484 return true;
485}
486
487} // namespace detail
489class IsMember : public Validator {
490 public:
491 using filter_fn_t = std::function<std::string(std::string)>;
492
494 template <typename T, typename... Args>
495 IsMember(std::initializer_list<T> values, Args &&...args)
496 : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
497
499 template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
500
503 template <typename T, typename F> explicit IsMember(T set, F filter_function) {
504
505 // Get the type of the contained item - requires a container have ::value_type
506 // if the type does not have first_type and second_type, these are both value_type
507 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
508 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
509
510 using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
511 // (const char * to std::string)
512
513 // Make a local copy of the filter function, using a std::function if not one already
514 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
515
516 // This is the type name for help, it will take the current version of the set contents
517 desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
518
519 // This is the function that validates
520 // It stores a copy of the set pointer-like, so shared_ptr will stay alive
521 func_ = [set, filter_fn](std::string &input) {
522 using CLI::detail::lexical_cast;
523 local_item_t b;
524 if(!lexical_cast(input, b)) {
525 throw ValidationError(input); // name is added later
526 }
527 if(filter_fn) {
528 b = filter_fn(b);
529 }
530 auto res = detail::search(set, b, filter_fn);
531 if(res.first) {
532 // Make sure the version in the input string is identical to the one in the set
533 if(filter_fn) {
534 input = detail::value_string(detail::pair_adaptor<element_t>::first(*(res.second)));
535 }
536
537 // Return empty error string (success)
538 return std::string{};
539 }
540
541 // If you reach this point, the result was not found
542 return input + " not in " + detail::generate_set(detail::smart_deref(set));
543 };
544 }
545
547 template <typename T, typename... Args>
548 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
549 : IsMember(
550 std::forward<T>(set),
551 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
552 other...) {}
553};
554
556template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
557
559class Transformer : public Validator {
560 public:
561 using filter_fn_t = std::function<std::string(std::string)>;
562
564 template <typename... Args>
565 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
566 : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
567
569 template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
570
573 template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
574
576 "mapping must produce value pairs");
577 // Get the type of the contained item - requires a container have ::value_type
578 // if the type does not have first_type and second_type, these are both value_type
579 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
580 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
581 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
582 // (const char * to std::string)
583
584 // Make a local copy of the filter function, using a std::function if not one already
585 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
586
587 // This is the type name for help, it will take the current version of the set contents
588 desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
589
590 func_ = [mapping, filter_fn](std::string &input) {
591 using CLI::detail::lexical_cast;
592 local_item_t b;
593 if(!lexical_cast(input, b)) {
594 return std::string();
595 // there is no possible way we can match anything in the mapping if we can't convert so just return
596 }
597 if(filter_fn) {
598 b = filter_fn(b);
599 }
600 auto res = detail::search(mapping, b, filter_fn);
601 if(res.first) {
602 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
603 }
604 return std::string{};
605 };
606 }
607
609 template <typename T, typename... Args>
610 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
611 : Transformer(
612 std::forward<T>(mapping),
613 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
614 other...) {}
615};
616
619 public:
620 using filter_fn_t = std::function<std::string(std::string)>;
621
623 template <typename... Args>
624 CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
625 : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
626
628 template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
629
632 template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
633
635 "mapping must produce value pairs");
636 // Get the type of the contained item - requires a container have ::value_type
637 // if the type does not have first_type and second_type, these are both value_type
638 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
639 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
640 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
641 // (const char * to std::string)
642 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
643
644 // Make a local copy of the filter function, using a std::function if not one already
645 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
646
647 auto tfunc = [mapping]() {
648 std::string out("value in ");
649 out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
650 out += detail::join(
651 detail::smart_deref(mapping),
652 [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
653 ",");
654 out.push_back('}');
655 return out;
656 };
657
658 desc_function_ = tfunc;
659
660 func_ = [mapping, tfunc, filter_fn](std::string &input) {
661 using CLI::detail::lexical_cast;
662 local_item_t b;
663 bool converted = lexical_cast(input, b);
664 if(converted) {
665 if(filter_fn) {
666 b = filter_fn(b);
667 }
668 auto res = detail::search(mapping, b, filter_fn);
669 if(res.first) {
670 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
671 return std::string{};
672 }
673 }
674 for(const auto &v : detail::smart_deref(mapping)) {
675 auto output_string = detail::value_string(detail::pair_adaptor<element_t>::second(v));
676 if(output_string == input) {
677 return std::string();
678 }
679 }
680
681 return "Check " + input + " " + tfunc() + " FAILED";
682 };
683 }
684
686 template <typename T, typename... Args>
687 CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
689 std::forward<T>(mapping),
690 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
691 other...) {}
692};
693
695inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
696
698inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
699
701inline std::string ignore_space(std::string item) {
702 item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
703 item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
704 return item;
705}
706
719 public:
724 enum Options {
725 CASE_SENSITIVE = 0,
726 CASE_INSENSITIVE = 1,
727 UNIT_OPTIONAL = 0,
728 UNIT_REQUIRED = 2,
729 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
730 };
731
732 template <typename Number>
733 explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
734 Options opts = DEFAULT,
735 const std::string &unit_name = "UNIT") {
736 description(generate_description<Number>(unit_name, opts));
737 validate_mapping(mapping, opts);
738
739 // transform function
740 func_ = [mapping, opts](std::string &input) -> std::string {
741 Number num{};
742
743 detail::rtrim(input);
744 if(input.empty()) {
745 throw ValidationError("Input is empty");
746 }
747
748 // Find split position between number and prefix
749 auto unit_begin = input.end();
750 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
751 --unit_begin;
752 }
753
754 std::string unit{unit_begin, input.end()};
755 input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
756 detail::trim(input);
757
758 if(opts & UNIT_REQUIRED && unit.empty()) {
759 throw ValidationError("Missing mandatory unit");
760 }
761 if(opts & CASE_INSENSITIVE) {
762 unit = detail::to_lower(unit);
763 }
764 if(unit.empty()) {
765 using CLI::detail::lexical_cast;
766 if(!lexical_cast(input, num)) {
767 throw ValidationError(std::string("Value ") + input + " could not be converted to " +
768 detail::type_name<Number>());
769 }
770 // No need to modify input if no unit passed
771 return {};
772 }
773
774 // find corresponding factor
775 auto it = mapping.find(unit);
776 if(it == mapping.end()) {
777 throw ValidationError(unit +
778 " unit not recognized. "
779 "Allowed values: " +
780 detail::generate_map(mapping, true));
781 }
782
783 if(!input.empty()) {
784 using CLI::detail::lexical_cast;
785 bool converted = lexical_cast(input, num);
786 if(!converted) {
787 throw ValidationError(std::string("Value ") + input + " could not be converted to " +
788 detail::type_name<Number>());
789 }
790 // perform safe multiplication
791 bool ok = detail::checked_multiply(num, it->second);
792 if(!ok) {
793 throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
794 " factor would cause number overflow. Use smaller value.");
795 }
796 } else {
797 num = static_cast<Number>(it->second);
798 }
799
800 input = detail::to_string(num);
801
802 return {};
803 };
804 }
805
806 private:
809 template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
810 for(auto &kv : mapping) {
811 if(kv.first.empty()) {
812 throw ValidationError("Unit must not be empty.");
813 }
814 if(!detail::isalpha(kv.first)) {
815 throw ValidationError("Unit must contain only letters.");
816 }
817 }
818
819 // make all units lowercase if CASE_INSENSITIVE
820 if(opts & CASE_INSENSITIVE) {
821 std::map<std::string, Number> lower_mapping;
822 for(auto &kv : mapping) {
823 auto s = detail::to_lower(kv.first);
824 if(lower_mapping.count(s)) {
825 throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
826 s);
827 }
828 lower_mapping[detail::to_lower(kv.first)] = kv.second;
829 }
830 mapping = std::move(lower_mapping);
831 }
832 }
833
835 template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
836 std::stringstream out;
837 out << detail::type_name<Number>() << ' ';
838 if(opts & UNIT_REQUIRED) {
839 out << name;
840 } else {
841 out << '[' << name << ']';
842 }
843 return out.str();
844 }
845};
846
848 return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
849}
850
863 public:
864 using result_t = std::uint64_t;
865
873 explicit AsSizeValue(bool kb_is_1000);
874
875 private:
877 static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
878
880 static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
881};
882
883namespace detail {
888CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
889
890} // namespace detail
892
893// [CLI11:validators_hpp:end]
894} // namespace CLI
895
896#ifndef CLI11_COMPILE
897#include "impl/Validators_inl.hpp" // IWYU pragma: export
898#endif
Definition Validators.hpp:718
Options
Definition Validators.hpp:724
Definition Validators.hpp:862
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
translate named items to other or a value set
Definition Validators.hpp:618
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition Validators.hpp:628
CheckedTransformer(T &&mapping, 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.
Definition Validators.hpp:687
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition Validators.hpp:624
CheckedTransformer(T mapping, F filter_function)
Definition Validators.hpp:632
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:489
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition Validators.hpp:499
IsMember(T set, F filter_function)
Definition Validators.hpp:503
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:548
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition Validators.hpp:495
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
Translate named items to other or a value set.
Definition Validators.hpp:559
Transformer(T &&mapping, 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.
Definition Validators.hpp:610
Transformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition Validators.hpp:565
Transformer(T &&mapping)
direct map of std::string to std::string
Definition Validators.hpp:569
Transformer(T mapping, F filter_function)
Definition Validators.hpp:573
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
Definition Validators.hpp:223
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:395
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