CLI11  2.3.2
Validators.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2023, 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 #include "Error.hpp"
10 #include "Macros.hpp"
11 #include "StringTools.hpp"
12 #include "TypeTools.hpp"
13 
14 // [CLI11:public_includes:set]
15 #include <cmath>
16 #include <cstdint>
17 #include <functional>
18 #include <iostream>
19 #include <limits>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 // [CLI11:public_includes:end]
26 
27 // [CLI11:validators_hpp_filesystem:verbatim]
28 
29 // C standard library
30 // Only needed for existence checking
31 #if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
32 #if __has_include(<filesystem>)
33 // Filesystem cannot be used if targeting macOS < 10.15
34 #if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
35 #define CLI11_HAS_FILESYSTEM 0
36 #elif defined(__wasi__)
37 // As of wasi-sdk-14, filesystem is not implemented
38 #define CLI11_HAS_FILESYSTEM 0
39 #else
40 #include <filesystem>
41 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
42 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
43 #define CLI11_HAS_FILESYSTEM 1
44 #elif defined(__GLIBCXX__)
45 // if we are using gcc and Version <9 default to no filesystem
46 #define CLI11_HAS_FILESYSTEM 0
47 #else
48 #define CLI11_HAS_FILESYSTEM 1
49 #endif
50 #else
51 #define CLI11_HAS_FILESYSTEM 0
52 #endif
53 #endif
54 #endif
55 #endif
56 
57 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
58 #include <filesystem> // NOLINT(build/include)
59 #else
60 #include <sys/stat.h>
61 #include <sys/types.h>
62 #endif
63 
64 // [CLI11:validators_hpp_filesystem:end]
65 
66 namespace CLI {
67 // [CLI11:validators_hpp:verbatim]
68 
69 class Option;
70 
72 
79 
81 class Validator {
82  protected:
84  std::function<std::string()> desc_function_{[]() { return std::string{}; }};
85 
88  std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
90  std::string name_{};
94  bool active_{true};
96  bool non_modifying_{false};
97 
98  Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
99  : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {}
100 
101  public:
102  Validator() = default;
104  explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
106  Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
107  : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
108  name_(std::move(validator_name)) {}
110  Validator &operation(std::function<std::string(std::string &)> op) {
111  func_ = std::move(op);
112  return *this;
113  }
116  std::string operator()(std::string &str) const;
117 
120  std::string operator()(const std::string &str) const {
121  std::string value = str;
122  return (active_) ? func_(value) : std::string{};
123  }
124 
126  Validator &description(std::string validator_desc) {
127  desc_function_ = [validator_desc]() { return validator_desc; };
128  return *this;
129  }
131  CLI11_NODISCARD Validator description(std::string validator_desc) const;
132 
134  CLI11_NODISCARD std::string get_description() const {
135  if(active_) {
136  return desc_function_();
137  }
138  return std::string{};
139  }
141  Validator &name(std::string validator_name) {
142  name_ = std::move(validator_name);
143  return *this;
144  }
146  CLI11_NODISCARD Validator name(std::string validator_name) const {
147  Validator newval(*this);
148  newval.name_ = std::move(validator_name);
149  return newval;
150  }
152  CLI11_NODISCARD const std::string &get_name() const { return name_; }
154  Validator &active(bool active_val = true) {
155  active_ = active_val;
156  return *this;
157  }
159  CLI11_NODISCARD Validator active(bool active_val = true) const {
160  Validator newval(*this);
161  newval.active_ = active_val;
162  return newval;
163  }
164 
166  Validator &non_modifying(bool no_modify = true) {
167  non_modifying_ = no_modify;
168  return *this;
169  }
171  Validator &application_index(int app_index) {
172  application_index_ = app_index;
173  return *this;
174  }
177  Validator newval(*this);
178  newval.application_index_ = app_index;
179  return newval;
180  }
184  CLI11_NODISCARD bool get_active() const { return active_; }
185 
187  CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; }
188 
191  Validator operator&(const Validator &other) const;
192 
195  Validator operator|(const Validator &other) const;
196 
198  Validator operator!() const;
199 
200  private:
201  void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger);
202 };
203 
205 class CustomValidator : public Validator {
206  public:
207 };
208 // The implementation of the built in validators is using the Validator class;
209 // the user is only expected to use the const (static) versions (since there's no setup).
210 // Therefore, this is in detail.
211 namespace detail {
212 
215 
217 CLI11_INLINE path_type check_path(const char *file) noexcept;
218 
221  public:
223 };
224 
227  public:
229 };
230 
233  public:
235 };
236 
239  public:
241 };
242 
244 class IPV4Validator : public Validator {
245  public:
246  IPV4Validator();
247 };
248 
249 } // namespace detail
250 
251 // Static is not needed here, because global const implies static.
252 
255 
258 
261 
264 
267 
269 template <typename DesiredType> class TypeValidator : public Validator {
270  public:
271  explicit TypeValidator(const std::string &validator_name)
272  : Validator(validator_name, [](std::string &input_string) {
274  auto val = DesiredType();
275  if(!lexical_cast(input_string, val)) {
276  return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
277  }
278  return std::string();
279  }) {}
280  TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
281 };
282 
284 const TypeValidator<double> Number("NUMBER");
285 
288 class FileOnDefaultPath : public Validator {
289  public:
290  explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true);
291 };
292 
294 class Range : public Validator {
295  public:
300  template <typename T>
301  Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) {
302  if(validator_name.empty()) {
303  std::stringstream out;
304  out << detail::type_name<T>() << " in [" << min_val << " - " << max_val << "]";
305  description(out.str());
306  }
307 
308  func_ = [min_val, max_val](std::string &input) {
310  T val;
311  bool converted = lexical_cast(input, val);
312  if((!converted) || (val < min_val || val > max_val)) {
313  std::stringstream out;
314  out << "Value " << input << " not in range [";
315  out << min_val << " - " << max_val << "]";
316  return out.str();
317  }
318  return std::string{};
319  };
320  }
321 
323  template <typename T>
324  explicit Range(T max_val, const std::string &validator_name = std::string{})
325  : Range(static_cast<T>(0), max_val, validator_name) {}
326 };
327 
329 const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
330 
332 const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
333 
335 class Bound : public Validator {
336  public:
341  template <typename T> Bound(T min_val, T max_val) {
342  std::stringstream out;
343  out << detail::type_name<T>() << " bounded to [" << min_val << " - " << max_val << "]";
344  description(out.str());
345 
346  func_ = [min_val, max_val](std::string &input) {
348  T val;
349  bool converted = lexical_cast(input, val);
350  if(!converted) {
351  return std::string("Value ") + input + " could not be converted";
352  }
353  if(val < min_val)
354  input = detail::to_string(min_val);
355  else if(val > max_val)
356  input = detail::to_string(max_val);
357 
358  return std::string{};
359  };
360  }
361 
363  template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
364 };
365 
366 namespace detail {
367 template <typename T,
368  enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
369 auto smart_deref(T value) -> decltype(*value) {
370  return *value;
371 }
372 
373 template <
374  typename T,
376 typename std::remove_reference<T>::type &smart_deref(T &value) {
377  return value;
378 }
380 template <typename T> std::string generate_set(const T &set) {
381  using element_t = typename detail::element_type<T>::type;
382  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
383  std::string out(1, '{');
384  out.append(detail::join(
385  detail::smart_deref(set),
386  [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
387  ","));
388  out.push_back('}');
389  return out;
390 }
391 
393 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
394  using element_t = typename detail::element_type<T>::type;
395  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
396  std::string out(1, '{');
397  out.append(detail::join(
398  detail::smart_deref(map),
399  [key_only](const iteration_type_t &v) {
401 
402  if(!key_only) {
403  res.append("->");
405  }
406  return res;
407  },
408  ","));
409  out.push_back('}');
410  return out;
411 }
412 
413 template <typename C, typename V> struct has_find {
414  template <typename CC, typename VV>
415  static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
416  template <typename, typename> static auto test(...) -> decltype(std::false_type());
417 
418  static const auto value = decltype(test<C, V>(0))::value;
419  using type = std::integral_constant<bool, value>;
420 };
421 
423 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
424 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
425  using element_t = typename detail::element_type<T>::type;
426  auto &setref = detail::smart_deref(set);
427  auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
428  return (detail::pair_adaptor<element_t>::first(v) == val);
429  });
430  return {(it != std::end(setref)), it};
431 }
432 
434 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
435 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
436  auto &setref = detail::smart_deref(set);
437  auto it = setref.find(val);
438  return {(it != std::end(setref)), it};
439 }
440 
442 template <typename T, typename V>
443 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
444  -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
445  using element_t = typename detail::element_type<T>::type;
446  // do the potentially faster first search
447  auto res = search(set, val);
448  if((res.first) || (!(filter_function))) {
449  return res;
450  }
451  // if we haven't found it do the longer linear search with all the element translations
452  auto &setref = detail::smart_deref(set);
453  auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
455  a = filter_function(a);
456  return (a == val);
457  });
458  return {(it != std::end(setref)), it};
459 }
460 
461 // the following suggestion was made by Nikita Ofitserov(@himikof)
462 // done in templates to prevent compiler warnings on negation of unsigned numbers
463 
465 template <typename T>
466 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
467  if((a > 0) == (b > 0)) {
468  return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
469  }
470  return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
471 }
473 template <typename T>
474 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
475  return ((std::numeric_limits<T>::max)() / a < b);
476 }
477 
479 template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
480  if(a == 0 || b == 0 || a == 1 || b == 1) {
481  a *= b;
482  return true;
483  }
484  if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
485  return false;
486  }
487  if(overflowCheck(a, b)) {
488  return false;
489  }
490  a *= b;
491  return true;
492 }
493 
495 template <typename T>
496 typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
497  T c = a * b;
498  if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
499  return false;
500  }
501  a = c;
502  return true;
503 }
504 
505 } // namespace detail
507 class IsMember : public Validator {
508  public:
509  using filter_fn_t = std::function<std::string(std::string)>;
510 
512  template <typename T, typename... Args>
513  IsMember(std::initializer_list<T> values, Args &&...args)
514  : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
515 
517  template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
518 
521  template <typename T, typename F> explicit IsMember(T set, F filter_function) {
522 
523  // Get the type of the contained item - requires a container have ::value_type
524  // if the type does not have first_type and second_type, these are both value_type
525  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
526  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
527 
528  using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
529  // (const char * to std::string)
530 
531  // Make a local copy of the filter function, using a std::function if not one already
532  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
533 
534  // This is the type name for help, it will take the current version of the set contents
535  desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
536 
537  // This is the function that validates
538  // It stores a copy of the set pointer-like, so shared_ptr will stay alive
539  func_ = [set, filter_fn](std::string &input) {
541  local_item_t b;
542  if(!lexical_cast(input, b)) {
543  throw ValidationError(input); // name is added later
544  }
545  if(filter_fn) {
546  b = filter_fn(b);
547  }
548  auto res = detail::search(set, b, filter_fn);
549  if(res.first) {
550  // Make sure the version in the input string is identical to the one in the set
551  if(filter_fn) {
553  }
554 
555  // Return empty error string (success)
556  return std::string{};
557  }
558 
559  // If you reach this point, the result was not found
560  return input + " not in " + detail::generate_set(detail::smart_deref(set));
561  };
562  }
563 
565  template <typename T, typename... Args>
566  IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
567  : IsMember(
568  std::forward<T>(set),
569  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
570  other...) {}
571 };
572 
574 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
575 
577 class Transformer : public Validator {
578  public:
579  using filter_fn_t = std::function<std::string(std::string)>;
580 
582  template <typename... Args>
583  Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
584  : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
585 
587  template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
588 
591  template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
592 
593  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
594  "mapping must produce value pairs");
595  // Get the type of the contained item - requires a container have ::value_type
596  // if the type does not have first_type and second_type, these are both value_type
597  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
598  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
599  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
600  // (const char * to std::string)
601 
602  // Make a local copy of the filter function, using a std::function if not one already
603  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
604 
605  // This is the type name for help, it will take the current version of the set contents
606  desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
607 
608  func_ = [mapping, filter_fn](std::string &input) {
610  local_item_t b;
611  if(!lexical_cast(input, b)) {
612  return std::string();
613  // there is no possible way we can match anything in the mapping if we can't convert so just return
614  }
615  if(filter_fn) {
616  b = filter_fn(b);
617  }
618  auto res = detail::search(mapping, b, filter_fn);
619  if(res.first) {
621  }
622  return std::string{};
623  };
624  }
625 
627  template <typename T, typename... Args>
628  Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
629  : Transformer(
630  std::forward<T>(mapping),
631  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
632  other...) {}
633 };
634 
637  public:
638  using filter_fn_t = std::function<std::string(std::string)>;
639 
641  template <typename... Args>
642  CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
643  : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
644 
646  template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
647 
650  template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
651 
652  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
653  "mapping must produce value pairs");
654  // Get the type of the contained item - requires a container have ::value_type
655  // if the type does not have first_type and second_type, these are both value_type
656  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
657  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
658  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
659  // (const char * to std::string)
660  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
661 
662  // Make a local copy of the filter function, using a std::function if not one already
663  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
664 
665  auto tfunc = [mapping]() {
666  std::string out("value in ");
667  out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
668  out += detail::join(
669  detail::smart_deref(mapping),
670  [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
671  ",");
672  out.push_back('}');
673  return out;
674  };
675 
676  desc_function_ = tfunc;
677 
678  func_ = [mapping, tfunc, filter_fn](std::string &input) {
680  local_item_t b;
681  bool converted = lexical_cast(input, b);
682  if(converted) {
683  if(filter_fn) {
684  b = filter_fn(b);
685  }
686  auto res = detail::search(mapping, b, filter_fn);
687  if(res.first) {
689  return std::string{};
690  }
691  }
692  for(const auto &v : detail::smart_deref(mapping)) {
694  if(output_string == input) {
695  return std::string();
696  }
697  }
698 
699  return "Check " + input + " " + tfunc() + " FAILED";
700  };
701  }
702 
704  template <typename T, typename... Args>
705  CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
707  std::forward<T>(mapping),
708  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
709  other...) {}
710 };
711 
713 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
714 
716 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
717 
719 inline std::string ignore_space(std::string item) {
720  item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
721  item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
722  return item;
723 }
724 
736 class AsNumberWithUnit : public Validator {
737  public:
742  enum Options {
748  };
749 
750  template <typename Number>
751  explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
752  Options opts = DEFAULT,
753  const std::string &unit_name = "UNIT") {
754  description(generate_description<Number>(unit_name, opts));
755  validate_mapping(mapping, opts);
756 
757  // transform function
758  func_ = [mapping, opts](std::string &input) -> std::string {
759  Number num{};
760 
761  detail::rtrim(input);
762  if(input.empty()) {
763  throw ValidationError("Input is empty");
764  }
765 
766  // Find split position between number and prefix
767  auto unit_begin = input.end();
768  while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
769  --unit_begin;
770  }
771 
772  std::string unit{unit_begin, input.end()};
773  input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
774  detail::trim(input);
775 
776  if(opts & UNIT_REQUIRED && unit.empty()) {
777  throw ValidationError("Missing mandatory unit");
778  }
779  if(opts & CASE_INSENSITIVE) {
780  unit = detail::to_lower(unit);
781  }
782  if(unit.empty()) {
784  if(!lexical_cast(input, num)) {
785  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
786  detail::type_name<Number>());
787  }
788  // No need to modify input if no unit passed
789  return {};
790  }
791 
792  // find corresponding factor
793  auto it = mapping.find(unit);
794  if(it == mapping.end()) {
795  throw ValidationError(unit +
796  " unit not recognized. "
797  "Allowed values: " +
798  detail::generate_map(mapping, true));
799  }
800 
801  if(!input.empty()) {
803  bool converted = lexical_cast(input, num);
804  if(!converted) {
805  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
806  detail::type_name<Number>());
807  }
808  // perform safe multiplication
809  bool ok = detail::checked_multiply(num, it->second);
810  if(!ok) {
811  throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
812  " factor would cause number overflow. Use smaller value.");
813  }
814  } else {
815  num = static_cast<Number>(it->second);
816  }
817 
818  input = detail::to_string(num);
819 
820  return {};
821  };
822  }
823 
824  private:
827  template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
828  for(auto &kv : mapping) {
829  if(kv.first.empty()) {
830  throw ValidationError("Unit must not be empty.");
831  }
832  if(!detail::isalpha(kv.first)) {
833  throw ValidationError("Unit must contain only letters.");
834  }
835  }
836 
837  // make all units lowercase if CASE_INSENSITIVE
838  if(opts & CASE_INSENSITIVE) {
839  std::map<std::string, Number> lower_mapping;
840  for(auto &kv : mapping) {
841  auto s = detail::to_lower(kv.first);
842  if(lower_mapping.count(s)) {
843  throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
844  s);
845  }
846  lower_mapping[detail::to_lower(kv.first)] = kv.second;
847  }
848  mapping = std::move(lower_mapping);
849  }
850  }
851 
853  template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
854  std::stringstream out;
855  out << detail::type_name<Number>() << ' ';
856  if(opts & UNIT_REQUIRED) {
857  out << name;
858  } else {
859  out << '[' << name << ']';
860  }
861  return out.str();
862  }
863 };
864 
866  return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
867 }
868 
881  public:
882  using result_t = std::uint64_t;
883 
891  explicit AsSizeValue(bool kb_is_1000);
892 
893  private:
895  static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
896 
898  static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
899 };
900 
901 namespace detail {
906 CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
907 
908 } // namespace detail
910 
911 // [CLI11:validators_hpp:end]
912 } // namespace CLI
913 
914 #ifndef CLI11_COMPILE
915 #include "impl/Validators_inl.hpp"
916 #endif
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
Definition: Validators.hpp:152
std::uint64_t result_t
Definition: Validators.hpp:882
Definition: Validators.hpp:736
path_type
CLI enumeration of different file types.
Definition: Validators.hpp:214
std::string name_
The name for search purposes of the Validator.
Definition: Validators.hpp:90
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:466
TypeValidator(const std::string &validator_name)
Definition: Validators.hpp:271
Options
Definition: Validators.hpp:742
Transformer(T mapping, F filter_function)
Definition: Validators.hpp:591
Validate the input as a particular type.
Definition: Validators.hpp:269
const detail::NonexistentPathValidator NonexistentPath
Check for an non-existing path.
Definition: Validators.hpp:263
Definition: App.hpp:34
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition: Validators.hpp:324
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition: TypeTools.hpp:109
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:628
enabler
Simple empty scoped class.
Definition: TypeTools.hpp:32
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:226
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition: Validators.hpp:104
bool non_modifying_
specify that a validator should not modify the input
Definition: Validators.hpp:96
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:719
Produce a bounded range (factory). Min and max are inclusive.
Definition: Validators.hpp:335
std::string generate_set(const T &set)
Generate a string representation of a set.
Definition: Validators.hpp:380
Class wrapping some of the accessors of Validator.
Definition: Validators.hpp:205
TypeValidator()
Definition: Validators.hpp:280
Definition: Validators.hpp:288
translate named items to other or a value set
Definition: Validators.hpp:636
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:642
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, 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};};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 > { 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) &&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_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 &&!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:799
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:509
AsNumberWithUnit(std::map< std::string, Number > mapping, Options opts=DEFAULT, const std::string &unit_name="UNIT")
Definition: Validators.hpp:751
Validator operator|(const Validator &other) const
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:713
Check for an non-existing path.
Definition: Validators.hpp:238
AsSizeValue(bool kb_is_1000)
std::function< std::string(std::string &)> func_
Definition: Validators.hpp:88
auto smart_deref(T value) -> decltype(*value)
Definition: Validators.hpp:369
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:583
typename std::remove_const< value_type >::type first_type
Definition: TypeTools.hpp:111
Validate the given string is a legal ipv4 address.
Definition: Validators.hpp:244
bool lexical_cast(const std::string &input, T &output)
Integer conversion.
Definition: TypeTools.hpp:913
constexpr enabler dummy
An instance to use in EnableIf.
Definition: TypeTools.hpp:35
Definition: Validators.hpp:880
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:638
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:281
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:705
std::integral_constant< bool, value > type
Definition: Validators.hpp:419
Definition: Validators.hpp:745
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: Validators.hpp:587
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition: Validators.hpp:92
static const auto value
Definition: Validators.hpp:418
Definition: Validators.hpp:413
FileOnDefaultPath(std::string default_path, bool enableErrorReturn=true)
IsMember(T set, F filter_function)
Definition: Validators.hpp:521
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:579
Validator operator &(const Validator &other) const
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition: Validators.hpp:159
#define CLI11_INLINE
Definition: Macros.hpp:73
const detail::IPV4Validator ValidIPV4
Check for an IP4 address.
Definition: Validators.hpp:266
Bound(T max_val)
Range of one value is 0 to value.
Definition: Validators.hpp:363
const detail::ExistingFileValidator ExistingFile
Check for existing file (returns error message if check fails)
Definition: Validators.hpp:254
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform. ...
Definition: Validators.hpp:716
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:51
Produce a range (factory). Min and max are inclusive.
Definition: Validators.hpp:294
Check for an existing path.
Definition: Validators.hpp:232
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:341
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: Validators.hpp:424
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:187
const detail::ExistingPathValidator ExistingPath
Check for an existing path.
Definition: Validators.hpp:260
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: StringTools.hpp:109
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:182
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition: Validators.hpp:106
Definition: Validators.hpp:743
Validator & name(std::string validator_name)
Specify the type string.
Definition: Validators.hpp:141
Translate named items to other or a value set.
Definition: Validators.hpp:577
typename std::enable_if< B, T >::type enable_if_t
Definition: TypeTools.hpp:43
std::vector< std::pair< std::string, T > > TransformPairs
definition of the default transformation object
Definition: Validators.hpp:574
std::string operator()(std::string &str) const
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: Validators.hpp:517
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition: Validators.hpp:513
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition: Validators.hpp:171
Definition: Validators.hpp:747
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:566
CLI11_INLINE std::pair< std::string, std::string > split_program_name(std::string commandline)
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Definition: Validators.hpp:182
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:174
Verify items are in a set.
Definition: Validators.hpp:507
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition: TypeTools.hpp:115
#define CLI11_NODISCARD
Definition: Macros.hpp:47
Some validators that are provided.
Definition: Validators.hpp:81
Validator(std::string validator_desc, std::function< std::string(std::string &)> func)
Definition: Validators.hpp:98
Definition: Validators.hpp:744
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition: Validators.hpp:94
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Definition: Validators.hpp:176
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: Validators.hpp:646
const Range PositiveNumber((std::numeric_limits< double >::min)(),(std::numeric_limits< double >::max)(), "POSITIVE")
Check for a positive valued number (val>0.0), <double>::min here is the smallest positive number...
std::string value_string(const T &value)
get a string as a convertible value for arithmetic types
Definition: TypeTools.hpp:351
const detail::ExistingDirectoryValidator ExistingDirectory
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:257
T type
Definition: TypeTools.hpp:78
Check for an existing file (returns error message if check fails)
Definition: Validators.hpp:220
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition: Validators.hpp:154
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
Definition: Validators.hpp:134
CheckedTransformer(T mapping, F filter_function)
Definition: Validators.hpp:650
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition: Validators.hpp:110
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition: Validators.hpp:84
std::string operator()(const std::string &str) const
Definition: Validators.hpp:120
const Range NonNegativeNumber((std::numeric_limits< double >::max)(), "NONNEGATIVE")
Check for a non negative number.
std::enable_if< std::is_integral< T >::value, bool >::type checked_multiply(T &a, T b)
Performs a *= b; if it doesn&#39;t cause integer overflow. Returns false otherwise.
Definition: Validators.hpp:479
typename T::value_type value_type
Definition: TypeTools.hpp:110
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition: Validators.hpp:166
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition: Validators.hpp:301
Validator()=default
std::string generate_map(const T &map, bool key_only=false)
Generate a string representation of a map.
Definition: Validators.hpp:393
AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b)
Definition: Validators.hpp:865
Definition: Validators.hpp:746
bool isalpha(const std::string &str)
Verify that str consists of letters only.
Definition: StringTools.hpp:169
T type
Definition: TypeTools.hpp:95
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Definition: Validators.hpp:184
Validator & description(std::string validator_desc)
Specify the type string.
Definition: Validators.hpp:126
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
Definition: Validators.hpp:146