CLI11
C++11 Command Line Interface Parser
Loading...
Searching...
No Matches
Validators.hpp
1// Copyright (c) 2017-2025, 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 : std::uint8_t { 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 // NOLINTNEXTLINE
360 return value;
361}
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; // the type of the object pair
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); },
370 ","));
371 out.push_back('}');
372 return out;
373}
374
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; // the type of the object pair
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))};
384
385 if(!key_only) {
386 res.append("->");
387 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
388 }
389 return res;
390 },
391 ","));
392 out.push_back('}');
393 return out;
394}
395
396template <typename C, typename V> struct has_find {
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());
400
401 static const auto value = decltype(test<C, V>(0))::value;
402 using type = std::integral_constant<bool, value>;
403};
404
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) {
412 });
413 return {(it != std::end(setref)), it};
414}
415
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};
422}
423
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;
429 // do the potentially faster first search
430 auto res = search(set, val);
431 if((res.first) || (!(filter_function))) {
432 return res;
433 }
434 // if we haven't found it do the longer linear search with all the element translations
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);
439 return (a == val);
440 });
441 return {(it != std::end(setref)), it};
442}
443
444// the following suggestion was made by Nikita Ofitserov(@himikof)
445// done in templates to prevent compiler warnings on negation of unsigned numbers
446
448template <typename T>
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));
452 }
453 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
454}
456template <typename T>
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);
459}
460
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) {
464 a *= b;
465 return true;
466 }
467 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
468 return false;
469 }
470 if(overflowCheck(a, b)) {
471 return false;
472 }
473 a *= b;
474 return true;
475}
476
478template <typename T>
479typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
480 T c = a * b;
481 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
482 return false;
483 }
484 a = c;
485 return true;
486}
487
488} // namespace detail
490class IsMember : public Validator {
491 public:
492 using filter_fn_t = std::function<std::string(std::string)>;
493
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)...) {}
498
500 template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
501
504 template <typename T, typename F> explicit IsMember(T set, F filter_function) {
505
506 // Get the type of the contained item - requires a container have ::value_type
507 // if the type does not have first_type and second_type, these are both value_type
508 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
509 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
510
511 using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
512 // (const char * to std::string)
513
514 // Make a local copy of the filter function, using a std::function if not one already
515 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
516
517 // This is the type name for help, it will take the current version of the set contents
518 desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
519
520 // This is the function that validates
521 // It stores a copy of the set pointer-like, so shared_ptr will stay alive
522 func_ = [set, filter_fn](std::string &input) {
523 using CLI::detail::lexical_cast;
524 local_item_t b;
525 if(!lexical_cast(input, b)) {
526 throw ValidationError(input); // name is added later
527 }
528 if(filter_fn) {
529 b = filter_fn(b);
530 }
531 auto res = detail::search(set, b, filter_fn);
532 if(res.first) {
533 // Make sure the version in the input string is identical to the one in the set
534 if(filter_fn) {
535 input = detail::value_string(detail::pair_adaptor<element_t>::first(*(res.second)));
536 }
537
538 // Return empty error string (success)
539 return std::string{};
540 }
541
542 // If you reach this point, the result was not found
543 return input + " not in " + detail::generate_set(detail::smart_deref(set));
544 };
545 }
546
548 template <typename T, typename... Args>
549 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
550 : IsMember(
551 std::forward<T>(set),
552 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
553 other...) {}
554};
555
557template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
558
560class Transformer : public Validator {
561 public:
562 using filter_fn_t = std::function<std::string(std::string)>;
563
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)...) {}
568
570 template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
571
574 template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
575
577 "mapping must produce value pairs");
578 // Get the type of the contained item - requires a container have ::value_type
579 // if the type does not have first_type and second_type, these are both value_type
580 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
581 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
582 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
583 // (const char * to std::string)
584
585 // Make a local copy of the filter function, using a std::function if not one already
586 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
587
588 // This is the type name for help, it will take the current version of the set contents
589 desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
590
591 func_ = [mapping, filter_fn](std::string &input) {
592 using CLI::detail::lexical_cast;
593 local_item_t b;
594 if(!lexical_cast(input, b)) {
595 return std::string();
596 // there is no possible way we can match anything in the mapping if we can't convert so just return
597 }
598 if(filter_fn) {
599 b = filter_fn(b);
600 }
601 auto res = detail::search(mapping, b, filter_fn);
602 if(res.first) {
603 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
604 }
605 return std::string{};
606 };
607 }
608
610 template <typename T, typename... Args>
611 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
612 : Transformer(
613 std::forward<T>(mapping),
614 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
615 other...) {}
616};
617
620 public:
621 using filter_fn_t = std::function<std::string(std::string)>;
622
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)...) {}
627
629 template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
630
633 template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
634
636 "mapping must produce value pairs");
637 // Get the type of the contained item - requires a container have ::value_type
638 // if the type does not have first_type and second_type, these are both value_type
639 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
640 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
641 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
642 // (const char * to std::string)
643 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
644
645 // Make a local copy of the filter function, using a std::function if not one already
646 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
647
648 auto tfunc = [mapping]() {
649 std::string out("value in ");
650 out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
651 out += detail::join(
652 detail::smart_deref(mapping),
653 [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
654 ",");
655 out.push_back('}');
656 return out;
657 };
658
659 desc_function_ = tfunc;
660
661 func_ = [mapping, tfunc, filter_fn](std::string &input) {
662 using CLI::detail::lexical_cast;
663 local_item_t b;
664 bool converted = lexical_cast(input, b);
665 if(converted) {
666 if(filter_fn) {
667 b = filter_fn(b);
668 }
669 auto res = detail::search(mapping, b, filter_fn);
670 if(res.first) {
671 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
672 return std::string{};
673 }
674 }
675 for(const auto &v : detail::smart_deref(mapping)) {
676 auto output_string = detail::value_string(detail::pair_adaptor<element_t>::second(v));
677 if(output_string == input) {
678 return std::string();
679 }
680 }
681
682 return "Check " + input + " " + tfunc() + " FAILED";
683 };
684 }
685
687 template <typename T, typename... Args>
688 CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
690 std::forward<T>(mapping),
691 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
692 other...) {}
693};
694
696inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
697
699inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
700
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));
705 return item;
706}
707
720 public:
725 enum Options : std::uint8_t {
726 CASE_SENSITIVE = 0,
727 CASE_INSENSITIVE = 1,
728 UNIT_OPTIONAL = 0,
729 UNIT_REQUIRED = 2,
730 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
731 };
732
733 template <typename Number>
734 explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
735 Options opts = DEFAULT,
736 const std::string &unit_name = "UNIT") {
737 description(generate_description<Number>(unit_name, opts));
738 validate_mapping(mapping, opts);
739
740 // transform function
741 func_ = [mapping, opts](std::string &input) -> std::string {
742 Number num{};
743
744 detail::rtrim(input);
745 if(input.empty()) {
746 throw ValidationError("Input is empty");
747 }
748
749 // Find split position between number and prefix
750 auto unit_begin = input.end();
751 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
752 --unit_begin;
753 }
754
755 std::string unit{unit_begin, input.end()};
756 input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
757 detail::trim(input);
758
759 if(opts & UNIT_REQUIRED && unit.empty()) {
760 throw ValidationError("Missing mandatory unit");
761 }
762 if(opts & CASE_INSENSITIVE) {
763 unit = detail::to_lower(unit);
764 }
765 if(unit.empty()) {
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>());
770 }
771 // No need to modify input if no unit passed
772 return {};
773 }
774
775 // find corresponding factor
776 auto it = mapping.find(unit);
777 if(it == mapping.end()) {
778 throw ValidationError(unit +
779 " unit not recognized. "
780 "Allowed values: " +
781 detail::generate_map(mapping, true));
782 }
783
784 if(!input.empty()) {
785 using CLI::detail::lexical_cast;
786 bool converted = lexical_cast(input, num);
787 if(!converted) {
788 throw ValidationError(std::string("Value ") + input + " could not be converted to " +
789 detail::type_name<Number>());
790 }
791 // perform safe multiplication
792 bool ok = detail::checked_multiply(num, it->second);
793 if(!ok) {
794 throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
795 " factor would cause number overflow. Use smaller value.");
796 }
797 } else {
798 num = static_cast<Number>(it->second);
799 }
800
801 input = detail::to_string(num);
802
803 return {};
804 };
805 }
806
807 private:
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.");
814 }
815 if(!detail::isalpha(kv.first)) {
816 throw ValidationError("Unit must contain only letters.");
817 }
818 }
819
820 // make all units lowercase if CASE_INSENSITIVE
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: ") +
827 s);
828 }
829 lower_mapping[detail::to_lower(kv.first)] = kv.second;
830 }
831 mapping = std::move(lower_mapping);
832 }
833 }
834
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) {
840 out << name;
841 } else {
842 out << '[' << name << ']';
843 }
844 return out.str();
845 }
846};
847
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));
850}
851
864 public:
865 using result_t = std::uint64_t;
866
874 explicit AsSizeValue(bool kb_is_1000);
875
876 private:
878 static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
879
881 static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
882};
883
884namespace detail {
889CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
890
891} // namespace detail
893
894// [CLI11:validators_hpp:end]
895} // namespace CLI
896
897#ifndef CLI11_COMPILE
898#include "impl/Validators_inl.hpp" // IWYU pragma: export
899#endif
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
translate named items to other or a value set
Definition Validators.hpp:619
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition Validators.hpp:629
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:688
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition Validators.hpp:625
CheckedTransformer(T mapping, F filter_function)
Definition Validators.hpp:633
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
Translate named items to other or a value set.
Definition Validators.hpp:560
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:611
Transformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition Validators.hpp:566
Transformer(T &&mapping)
direct map of std::string to std::string
Definition Validators.hpp:570
Transformer(T mapping, F filter_function)
Definition Validators.hpp:574
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:396
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition TypeTools.hpp:130