CLI11  2.5.0
Validators.hpp
Go to the documentation of this file.
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 
40 namespace CLI {
41 // [CLI11:validators_hpp:verbatim]
42 
43 class Option;
44 
46 
53 
55 class 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  }
151  Validator newval(*this);
152  newval.application_index_ = app_index;
153  return newval;
154  }
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 
179 class CustomValidator : public Validator {
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.
185 namespace detail {
186 
189 
191 CLI11_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 
218 class IPV4Validator : public Validator {
219  public:
220  IPV4Validator();
221 };
222 
224  public:
226 };
227 
228 } // namespace detail
229 
230 // Static is not needed here, because global const implies static.
231 
234 
237 
240 
243 
246 
249 
251 template <typename DesiredType> class TypeValidator : public Validator {
252  public:
253  explicit TypeValidator(const std::string &validator_name)
254  : Validator(validator_name, [](std::string &input_string) {
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 
266 const TypeValidator<double> Number("NUMBER");
267 
270 class FileOnDefaultPath : public Validator {
271  public:
272  explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true);
273 };
274 
276 class 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) {
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 
311 const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
312 
314 const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
315 
317 class 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) {
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 
348 namespace detail {
349 template <typename T,
350  enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
351 auto smart_deref(T value) -> decltype(*value) {
352  return *value;
353 }
354 
355 template <
356  typename T,
358 typename std::remove_reference<T>::type &smart_deref(T &value) {
359  return value;
360 }
362 template <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 
375 template <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) {
383 
384  if(!key_only) {
385  res.append("->");
387  }
388  return res;
389  },
390  ","));
391  out.push_back('}');
392  return out;
393 }
394 
395 template <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 
405 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
406 auto 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) {
410  return (detail::pair_adaptor<element_t>::first(v) == val);
411  });
412  return {(it != std::end(setref)), it};
413 }
414 
416 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
417 auto 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 
424 template <typename T, typename V>
425 auto 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 
447 template <typename T>
448 inline 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 }
455 template <typename T>
456 inline 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 
461 template <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 
477 template <typename T>
478 typename 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
489 class 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) {
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) {
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 
556 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
557 
559 class 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 
575  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
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) {
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) {
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 
634  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
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) {
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) {
671  return std::string{};
672  }
673  }
674  for(const auto &v : detail::smart_deref(mapping)) {
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 
695 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
696 
698 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
699 
701 inline 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 
718 class AsNumberWithUnit : public Validator {
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()) {
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()) {
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 
883 namespace detail {
888 CLI11_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
std::uint64_t result_t
Definition: Validators.hpp:864
Definition: Validators.hpp:718
path_type
CLI enumeration of different file types.
Definition: Validators.hpp:188
std::string name_
The name for search purposes of the Validator.
Definition: Validators.hpp:64
std::enable_if< std::is_signed< T >::value, T >::type overflowCheck(const T &a, const T &b)
Do a check for overflow on signed numbers.
Definition: Validators.hpp:448
TypeValidator(const std::string &validator_name)
Definition: Validators.hpp:253
Options
Definition: Validators.hpp:724
Transformer(T mapping, F filter_function)
Definition: Validators.hpp:573
Validate the input as a particular type.
Definition: Validators.hpp:251
const detail::NonexistentPathValidator NonexistentPath
Check for an non-existing path.
Definition: Validators.hpp:242
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
std::string operator()(std::string &str) const
Definition: App.hpp:36
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition: Validators.hpp:306
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition: TypeTools.hpp:130
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
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Definition: Validators.hpp:150
enabler
Simple empty scoped class.
Definition: TypeTools.hpp:36
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:200
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition: Validators.hpp:78
bool non_modifying_
specify that a validator should not modify the input
Definition: Validators.hpp:70
const TypeValidator< double > Number("NUMBER")
Check for a number.
std::string ignore_space(std::string item)
Helper function to allow checks to ignore spaces to be passed to IsMember or Transform.
Definition: Validators.hpp:701
Produce a bounded range (factory). Min and max are inclusive.
Definition: Validators.hpp:317
std::string generate_set(const T &set)
Generate a string representation of a set.
Definition: Validators.hpp:362
Validator operator&(const Validator &other) const
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
Definition: Validators.hpp:126
Class wrapping some of the accessors of Validator.
Definition: Validators.hpp:179
TypeValidator()
Definition: Validators.hpp:262
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition: Validators.hpp:133
Definition: Validators.hpp:270
translate named items to other or a value set
Definition: Validators.hpp:618
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:624
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:491
AsNumberWithUnit(std::map< std::string, Number > mapping, Options opts=DEFAULT, const std::string &unit_name="UNIT")
Definition: Validators.hpp:733
STL namespace.
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: Validators.hpp:695
Check for an non-existing path.
Definition: Validators.hpp:212
std::function< std::string(std::string &)> func_
Definition: Validators.hpp:62
auto smart_deref(T value) -> decltype(*value)
Definition: Validators.hpp:351
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:565
typename std::remove_const< value_type >::type first_type
Definition: TypeTools.hpp:132
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Definition: Validators.hpp:158
Validate the given string is a legal ipv4 address.
Definition: Validators.hpp:218
bool lexical_cast(const std::string &input, T &output)
Integer conversion.
Definition: TypeTools.hpp:1112
constexpr std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size(){return subtype_count< typename std::tuple_element< I, T >::type >::value+tuple_type_size< T, I+1 >);}template< typename T > struct type_count< T, typename std::enable_if< is_tuple_like< T >::value >::type >{static constexpr int value{tuple_type_size< T, 0 >)};};template< typename T > struct subtype_count{static constexpr int value{is_mutable_container< T >::value?expected_max_vector_size:type_count< T >::value};};template< typename T, typename Enable=void > struct type_count_min{static const int value{0};};template< typename T >struct type_count_min< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_tuple_like< T >::value &&!is_wrapper< T >::value &&!is_complex< T >::value &&!std::is_void< T >::value >::type >{static constexpr int value{type_count< T >::value};};template< typename T > struct type_count_min< T, typename std::enable_if< is_complex< T >::value >::type >{static constexpr int value{1};};template< typename T >struct type_count_min< T, typename std::enable_if< is_wrapper< T >::value &&!is_complex< T >::value &&!is_tuple_like< T >::value >::type >{static constexpr int value{subtype_count_min< typename T::value_type >::value};};template< typename T, std::size_t I >constexpr typename std::enable_if< I==type_count_base< T >::value, int >::type tuple_type_size_min(){return 0;}template< typename T, std::size_t I > constexpr typename std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size_min(){return subtype_count_min< typename std::tuple_element< I, T >::type >::value+tuple_type_size_min< T, I+1 >);}template< typename T > struct type_count_min< T, typename std::enable_if< is_tuple_like< T >::value >::type >{static constexpr int value{tuple_type_size_min< T, 0 >)};};template< typename T > struct subtype_count_min{static constexpr int value{is_mutable_container< T >::value?((type_count< T >::value< expected_max_vector_size)?type_count< T >::value:0):type_count_min< T >::value};};template< typename T, typename Enable=void > struct expected_count{static const int value{0};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_wrapper< T >::value &&!std::is_void< T >::value >::type >{static constexpr int value{1};};template< typename T > struct expected_count< T, typename std::enable_if< is_mutable_container< T >::value >::type >{static constexpr int value{expected_max_vector_size};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&is_wrapper< T >::value >::type >{static constexpr int value{expected_count< typename T::value_type >::value};};enum class object_category:int{char_value=1, integral_value=2, unsigned_integral=4, enumeration=6, boolean_value=8, floating_point=10, number_constructible=12, double_constructible=14, integer_constructible=16, string_assignable=23, string_constructible=24, wstring_assignable=25, wstring_constructible=26, other=45, wrapper_value=50, complex_number=60, tuple_value=70, container_value=80,};template< typename T, typename Enable=void > struct classify_object{static constexpr object_category value{object_category::other};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&!std::is_same< T, char >::value &&std::is_signed< T >::value &&!is_bool< T >::value &&!std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::integral_value};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&!std::is_same< T, char >::value &&!is_bool< T >::value >::type >{static constexpr object_category value{object_category::unsigned_integral};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_same< T, char >::value &&!std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::char_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_bool< T >::value >::type >{static constexpr object_category value{object_category::boolean_value};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_floating_point< T >::value >::type >{static constexpr object_category value{object_category::floating_point};};#define WIDE_STRING_CHECK#define STRING_CHECKtemplate< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&WIDE_STRING_CHECK &&std::is_assignable< T &, std::string >::value >::type >{static constexpr object_category value{object_category::string_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&(type_count< T >::value==1)&&WIDE_STRING_CHECK &&std::is_constructible< T, std::string >::value >::type >{static constexpr object_category value{object_category::string_constructible};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&STRING_CHECK &&std::is_assignable< T &, std::wstring >::value >::type >{static constexpr object_category value{object_category::wstring_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::wstring >::value &&(type_count< T >::value==1)&&STRING_CHECK &&std::is_constructible< T, std::wstring >::value >::type >{static constexpr object_category value{object_category::wstring_constructible};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::enumeration};};template< typename T > struct classify_object< T, typename std::enable_if< is_complex< T >::value >::type >{static constexpr object_category value{object_category::complex_number};};template< typename T > struct uncommon_type{using type=typename std::conditional< !std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&!std::is_constructible< T, std::string >::value &&!std::is_assignable< T &, std::wstring >::value &&!std::is_constructible< T, std::wstring >::value &&!is_complex< T >::value &&!is_mutable_container< T >::value &&!std::is_enum< T >::value, std::true_type, std::false_type >::type;static constexpr bool value=type::value;};template< typename T >struct classify_object< T, typename std::enable_if<(!is_mutable_container< T >::value &&is_wrapper< T >::value &&!is_tuple_like< T >::value &&uncommon_type< T >::value)>::type >{static constexpr object_category value{object_category::wrapper_value};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::number_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&!is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::integer_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::double_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< is_tuple_like< T >::value &&((type_count< T >::value >=2 &&!is_wrapper< T >::value)||(uncommon_type< T >::value &&!is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value)||(uncommon_type< T >::value &&type_count< T >::value >=2))>::type >{static constexpr object_category value{object_category::tuple_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_mutable_container< T >::value >::type >{static constexpr object_category value{object_category::container_value};};template< typename T, enable_if_t< classify_object< T >::value==object_category::char_value, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"CHAR";}template< typename T, enable_if_t< classify_object< T >::value==object_category::integral_value||classify_object< T >::value==object_category::integer_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"INT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::unsigned_integral, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"UINT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::floating_point||classify_object< T >::value==object_category::number_constructible||classify_object< T >::value==object_category::double_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"FLOAT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::enumeration, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"ENUM";}template< typename T, enable_if_t< classify_object< T >::value==object_category::boolean_value, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"BOOLEAN";}template< typename T, enable_if_t< classify_object< T >::value==object_category::complex_number, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"COMPLEX";}template< typename T, enable_if_t< classify_object< T >::value >=object_category::string_assignable &&classify_object< T >::value<=object_category::other, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"TEXT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value||classify_object< T >::value==object_category::wrapper_value, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value==1, detail::enabler >=detail::dummy >inline std::string type_name(){return type_name< typename std::decay< typename std::tuple_element< 0, T >::type >::type >);}template< typename T, std::size_t I >inline typename std::enable_if< I==type_count_base< T >::value, std::string >::type tuple_name(){return std::string{};}template< typename T, std::size_t I >inline typename std::enable_if<(I< type_count_base< T >::value), std::string >::type tuple_name(){auto str=std::string{type_name< typename std::decay< typename std::tuple_element< I, T >::type >::type >)}+ ','+tuple_name< T, I+1 >);if(str.back()== ',') str.pop_back();return str;}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler > > std::string type_name()
Recursively generate the tuple type name.
Definition: TypeTools.hpp:925
constexpr enabler dummy
An instance to use in EnableIf.
Definition: TypeTools.hpp:39
Definition: Validators.hpp:862
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:620
auto to_string(T &&value) -> decltype(std::forward< T >(value))
Convert an object to a string (directly forward if this can become a string)
Definition: TypeTools.hpp:337
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
std::integral_constant< bool, value > type
Definition: Validators.hpp:401
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: Validators.hpp:569
const Range NonNegativeNumber((std::numeric_limits< double >::max)(),"NONNEGATIVE")
Check for a non negative number.
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition: Validators.hpp:66
static const auto value
Definition: Validators.hpp:400
Definition: Validators.hpp:395
FileOnDefaultPath(std::string default_path, bool enableErrorReturn=true)
IsMember(T set, F filter_function)
Definition: Validators.hpp:503
CLI11_INLINE path_type check_path(const char *file) noexcept
get the type of the path from a file name
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:561
#define CLI11_INLINE
Definition: Macros.hpp:150
const detail::IPV4Validator ValidIPV4
Check for an IP4 address.
Definition: Validators.hpp:245
Bound(T max_val)
Range of one value is 0 to value.
Definition: Validators.hpp:345
const detail::ExistingFileValidator ExistingFile
Check for existing file (returns error message if check fails)
Definition: Validators.hpp:233
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform. ...
Definition: Validators.hpp:698
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:53
Produce a range (factory). Min and max are inclusive.
Definition: Validators.hpp:276
Check for an existing path.
Definition: Validators.hpp:206
static auto test(int) -> decltype(std::declval< CC >().find(std::declval< VV >()), std::true_type())
Bound(T min_val, T max_val)
Definition: Validators.hpp:323
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: Validators.hpp:406
Validator operator|(const Validator &other) const
const detail::ExistingPathValidator ExistingPath
Check for an existing path.
Definition: Validators.hpp:239
Thrown when validation of results fails.
Definition: Error.hpp:221
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: StringTools.hpp:116
CLI11_INLINE std::string & rtrim(std::string &str)
Trim whitespace from right of string.
std::string remove_underscore(std::string str)
remove underscores from a string
Definition: StringTools.hpp:191
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 & name(std::string validator_name)
Specify the type string.
Definition: Validators.hpp:115
Translate named items to other or a value set.
Definition: Validators.hpp:559
typename std::enable_if< B, T >::type enable_if_t
Definition: TypeTools.hpp:47
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: Validators.hpp:499
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition: Validators.hpp:495
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition: Validators.hpp:145
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
CLI11_INLINE std::pair< std::string, std::string > split_program_name(std::string commandline)
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:183
Verify items are in a set.
Definition: Validators.hpp:489
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
#define CLI11_NODISCARD
Definition: Macros.hpp:58
Some validators that are provided.
Definition: Validators.hpp:55
Validator(std::string validator_desc, std::function< std::string(std::string &)> func)
Definition: Validators.hpp:72
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition: Validators.hpp:68
std::string operator()(const std::string &str) const
Definition: Validators.hpp:94
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
Definition: Validators.hpp:108
std::vector< std::pair< std::string, T >> TransformPairs
definition of the default transformation object
Definition: Validators.hpp:556
const detail::EscapedStringTransformer EscapedString
convert escaped characters into their associated values
Definition: Validators.hpp:248
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: Validators.hpp:628
std::string value_string(const T &value)
get a string as a convertible value for arithmetic types
Definition: TypeTools.hpp:470
const detail::ExistingDirectoryValidator ExistingDirectory
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:236
T type
Definition: TypeTools.hpp:82
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
Definition: Validators.hpp:120
Check for an existing file (returns error message if check fails)
Definition: Validators.hpp:194
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition: Validators.hpp:128
Definition: Validators.hpp:223
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Definition: Validators.hpp:156
CheckedTransformer(T mapping, F filter_function)
Definition: Validators.hpp:632
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition: Validators.hpp:84
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition: Validators.hpp:58
std::enable_if< std::is_integral< T >::value, bool >::type checked_multiply(T &a, T b)
Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.
Definition: Validators.hpp:461
typename T::value_type value_type
Definition: TypeTools.hpp:131
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition: Validators.hpp:140
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition: Validators.hpp:283
Validator()=default
std::string generate_map(const T &map, bool key_only=false)
Generate a string representation of a map.
Definition: Validators.hpp:375
AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b)
Definition: Validators.hpp:847
bool isalpha(const std::string &str)
Verify that str consists of letters only.
Definition: StringTools.hpp:178
T type
Definition: TypeTools.hpp:116
const Range PositiveNumber((std::numeric_limits< double >::min)(),(std::numeric_limits< double >::max)(),"POSITIVE")
Check for a positive valued number (val>0.0), ::min here is the smallest positive number...
Validator & description(std::string validator_desc)
Specify the type string.
Definition: Validators.hpp:100