CLI11  2.1.0
Validators.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2021, 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 "Macros.hpp"
10 #include "StringTools.hpp"
11 #include "TypeTools.hpp"
12 
13 // [CLI11:public_includes:set]
14 #include <cmath>
15 #include <cstdint>
16 #include <functional>
17 #include <iostream>
18 #include <limits>
19 #include <map>
20 #include <memory>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 // [CLI11:public_includes:end]
25 
26 // [CLI11:validators_hpp_filesystem:verbatim]
27 
28 // C standard library
29 // Only needed for existence checking
30 #if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
31 #if __has_include(<filesystem>)
32 // Filesystem cannot be used if targeting macOS < 10.15
33 #if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
34 #define CLI11_HAS_FILESYSTEM 0
35 #else
36 #include <filesystem>
37 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
38 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
39 #define CLI11_HAS_FILESYSTEM 1
40 #elif defined(__GLIBCXX__)
41 // if we are using gcc and Version <9 default to no filesystem
42 #define CLI11_HAS_FILESYSTEM 0
43 #else
44 #define CLI11_HAS_FILESYSTEM 1
45 #endif
46 #else
47 #define CLI11_HAS_FILESYSTEM 0
48 #endif
49 #endif
50 #endif
51 #endif
52 
53 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
54 #include <filesystem> // NOLINT(build/include)
55 #else
56 #include <sys/stat.h>
57 #include <sys/types.h>
58 #endif
59 
60 // [CLI11:validators_hpp_filesystem:end]
61 
62 namespace CLI {
63 // [CLI11:validators_hpp:verbatim]
64 
65 class Option;
66 
68 
75 
77 class Validator {
78  protected:
80  std::function<std::string()> desc_function_{[]() { return std::string{}; }};
81 
84  std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
86  std::string name_{};
90  bool active_{true};
92  bool non_modifying_{false};
93 
94  public:
95  Validator() = default;
97  explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
99  Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
100  : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
101  name_(std::move(validator_name)) {}
103  Validator &operation(std::function<std::string(std::string &)> op) {
104  func_ = std::move(op);
105  return *this;
106  }
109  std::string operator()(std::string &str) const {
110  std::string retstring;
111  if(active_) {
112  if(non_modifying_) {
113  std::string value = str;
114  retstring = func_(value);
115  } else {
116  retstring = func_(str);
117  }
118  }
119  return retstring;
120  }
121 
124  std::string operator()(const std::string &str) const {
125  std::string value = str;
126  return (active_) ? func_(value) : std::string{};
127  }
128 
130  Validator &description(std::string validator_desc) {
131  desc_function_ = [validator_desc]() { return validator_desc; };
132  return *this;
133  }
135  Validator description(std::string validator_desc) const {
136  Validator newval(*this);
137  newval.desc_function_ = [validator_desc]() { return validator_desc; };
138  return newval;
139  }
141  std::string get_description() const {
142  if(active_) {
143  return desc_function_();
144  }
145  return std::string{};
146  }
148  Validator &name(std::string validator_name) {
149  name_ = std::move(validator_name);
150  return *this;
151  }
153  Validator name(std::string validator_name) const {
154  Validator newval(*this);
155  newval.name_ = std::move(validator_name);
156  return newval;
157  }
159  const std::string &get_name() const { return name_; }
161  Validator &active(bool active_val = true) {
162  active_ = active_val;
163  return *this;
164  }
166  Validator active(bool active_val = true) const {
167  Validator newval(*this);
168  newval.active_ = active_val;
169  return newval;
170  }
171 
173  Validator &non_modifying(bool no_modify = true) {
174  non_modifying_ = no_modify;
175  return *this;
176  }
178  Validator &application_index(int app_index) {
179  application_index_ = app_index;
180  return *this;
181  }
183  Validator application_index(int app_index) const {
184  Validator newval(*this);
185  newval.application_index_ = app_index;
186  return newval;
187  }
191  bool get_active() const { return active_; }
192 
194  bool get_modifying() const { return !non_modifying_; }
195 
198  Validator operator&(const Validator &other) const {
199  Validator newval;
200 
201  newval._merge_description(*this, other, " AND ");
202 
203  // Give references (will make a copy in lambda function)
204  const std::function<std::string(std::string & filename)> &f1 = func_;
205  const std::function<std::string(std::string & filename)> &f2 = other.func_;
206 
207  newval.func_ = [f1, f2](std::string &input) {
208  std::string s1 = f1(input);
209  std::string s2 = f2(input);
210  if(!s1.empty() && !s2.empty())
211  return std::string("(") + s1 + ") AND (" + s2 + ")";
212  else
213  return s1 + s2;
214  };
215 
216  newval.active_ = (active_ & other.active_);
218  return newval;
219  }
220 
223  Validator operator|(const Validator &other) const {
224  Validator newval;
225 
226  newval._merge_description(*this, other, " OR ");
227 
228  // Give references (will make a copy in lambda function)
229  const std::function<std::string(std::string &)> &f1 = func_;
230  const std::function<std::string(std::string &)> &f2 = other.func_;
231 
232  newval.func_ = [f1, f2](std::string &input) {
233  std::string s1 = f1(input);
234  std::string s2 = f2(input);
235  if(s1.empty() || s2.empty())
236  return std::string();
237 
238  return std::string("(") + s1 + ") OR (" + s2 + ")";
239  };
240  newval.active_ = (active_ & other.active_);
242  return newval;
243  }
244 
247  Validator newval;
248  const std::function<std::string()> &dfunc1 = desc_function_;
249  newval.desc_function_ = [dfunc1]() {
250  auto str = dfunc1();
251  return (!str.empty()) ? std::string("NOT ") + str : std::string{};
252  };
253  // Give references (will make a copy in lambda function)
254  const std::function<std::string(std::string & res)> &f1 = func_;
255 
256  newval.func_ = [f1, dfunc1](std::string &test) -> std::string {
257  std::string s1 = f1(test);
258  if(s1.empty()) {
259  return std::string("check ") + dfunc1() + " succeeded improperly";
260  }
261  return std::string{};
262  };
263  newval.active_ = active_;
265  return newval;
266  }
267 
268  private:
269  void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger) {
270 
271  const std::function<std::string()> &dfunc1 = val1.desc_function_;
272  const std::function<std::string()> &dfunc2 = val2.desc_function_;
273 
274  desc_function_ = [=]() {
275  std::string f1 = dfunc1();
276  std::string f2 = dfunc2();
277  if((f1.empty()) || (f2.empty())) {
278  return f1 + f2;
279  }
280  return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
281  };
282  }
283 }; // namespace CLI
284 
286 class CustomValidator : public Validator {
287  public:
288 };
289 // The implementation of the built in validators is using the Validator class;
290 // the user is only expected to use the const (static) versions (since there's no setup).
291 // Therefore, this is in detail.
292 namespace detail {
293 
296 
297 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
299 inline path_type check_path(const char *file) noexcept {
300  std::error_code ec;
301  auto stat = std::filesystem::status(file, ec);
302  if(ec) {
303  return path_type::nonexistent;
304  }
305  switch(stat.type()) {
306  case std::filesystem::file_type::none:
307  case std::filesystem::file_type::not_found:
308  return path_type::nonexistent;
309  case std::filesystem::file_type::directory:
310  return path_type::directory;
311  case std::filesystem::file_type::symlink:
312  case std::filesystem::file_type::block:
313  case std::filesystem::file_type::character:
314  case std::filesystem::file_type::fifo:
315  case std::filesystem::file_type::socket:
316  case std::filesystem::file_type::regular:
317  case std::filesystem::file_type::unknown:
318  default:
319  return path_type::file;
320  }
321 }
322 #else
324 inline path_type check_path(const char *file) noexcept {
325 #if defined(_MSC_VER)
326  struct __stat64 buffer;
327  if(_stat64(file, &buffer) == 0) {
328  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
329  }
330 #else
331  struct stat buffer;
332  if(stat(file, &buffer) == 0) {
333  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
334  }
335 #endif
336  return path_type::nonexistent;
337 }
338 #endif
341  public:
343  func_ = [](std::string &filename) {
344  auto path_result = check_path(filename.c_str());
345  if(path_result == path_type::nonexistent) {
346  return "File does not exist: " + filename;
347  }
348  if(path_result == path_type::directory) {
349  return "File is actually a directory: " + filename;
350  }
351  return std::string();
352  };
353  }
354 };
355 
358  public:
360  func_ = [](std::string &filename) {
361  auto path_result = check_path(filename.c_str());
362  if(path_result == path_type::nonexistent) {
363  return "Directory does not exist: " + filename;
364  }
365  if(path_result == path_type::file) {
366  return "Directory is actually a file: " + filename;
367  }
368  return std::string();
369  };
370  }
371 };
372 
375  public:
376  ExistingPathValidator() : Validator("PATH(existing)") {
377  func_ = [](std::string &filename) {
378  auto path_result = check_path(filename.c_str());
379  if(path_result == path_type::nonexistent) {
380  return "Path does not exist: " + filename;
381  }
382  return std::string();
383  };
384  }
385 };
386 
389  public:
390  NonexistentPathValidator() : Validator("PATH(non-existing)") {
391  func_ = [](std::string &filename) {
392  auto path_result = check_path(filename.c_str());
393  if(path_result != path_type::nonexistent) {
394  return "Path already exists: " + filename;
395  }
396  return std::string();
397  };
398  }
399 };
400 
402 class IPV4Validator : public Validator {
403  public:
404  IPV4Validator() : Validator("IPV4") {
405  func_ = [](std::string &ip_addr) {
406  auto result = CLI::detail::split(ip_addr, '.');
407  if(result.size() != 4) {
408  return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')';
409  }
410  int num;
411  for(const auto &var : result) {
412  bool retval = detail::lexical_cast(var, num);
413  if(!retval) {
414  return std::string("Failed parsing number (") + var + ')';
415  }
416  if(num < 0 || num > 255) {
417  return std::string("Each IP number must be between 0 and 255 ") + var;
418  }
419  }
420  return std::string();
421  };
422  }
423 };
424 
425 } // namespace detail
426 
427 // Static is not needed here, because global const implies static.
428 
431 
434 
437 
440 
443 
445 template <typename DesiredType> class TypeValidator : public Validator {
446  public:
447  explicit TypeValidator(const std::string &validator_name) : Validator(validator_name) {
448  func_ = [](std::string &input_string) {
449  auto val = DesiredType();
450  if(!detail::lexical_cast(input_string, val)) {
451  return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
452  }
453  return std::string();
454  };
455  }
456  TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
457 };
458 
461 
463 class Range : public Validator {
464  public:
469  template <typename T>
470  Range(T min, T max, const std::string &validator_name = std::string{}) : Validator(validator_name) {
471  if(validator_name.empty()) {
472  std::stringstream out;
473  out << detail::type_name<T>() << " in [" << min << " - " << max << "]";
474  description(out.str());
475  }
476 
477  func_ = [min, max](std::string &input) {
478  T val;
479  bool converted = detail::lexical_cast(input, val);
480  if((!converted) || (val < min || val > max))
481  return std::string("Value ") + input + " not in range " + std::to_string(min) + " to " +
482  std::to_string(max);
483 
484  return std::string();
485  };
486  }
487 
489  template <typename T>
490  explicit Range(T max, const std::string &validator_name = std::string{})
491  : Range(static_cast<T>(0), max, validator_name) {}
492 };
493 
495 const Range NonNegativeNumber(std::numeric_limits<double>::max(), "NONNEGATIVE");
496 
498 const Range PositiveNumber(std::numeric_limits<double>::min(), std::numeric_limits<double>::max(), "POSITIVE");
499 
501 class Bound : public Validator {
502  public:
507  template <typename T> Bound(T min, T max) {
508  std::stringstream out;
509  out << detail::type_name<T>() << " bounded to [" << min << " - " << max << "]";
510  description(out.str());
511 
512  func_ = [min, max](std::string &input) {
513  T val;
514  bool converted = detail::lexical_cast(input, val);
515  if(!converted) {
516  return std::string("Value ") + input + " could not be converted";
517  }
518  if(val < min)
519  input = detail::to_string(min);
520  else if(val > max)
521  input = detail::to_string(max);
522 
523  return std::string{};
524  };
525  }
526 
528  template <typename T> explicit Bound(T max) : Bound(static_cast<T>(0), max) {}
529 };
530 
531 namespace detail {
532 template <typename T,
533  enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
534 auto smart_deref(T value) -> decltype(*value) {
535  return *value;
536 }
537 
538 template <
539  typename T,
541 typename std::remove_reference<T>::type &smart_deref(T &value) {
542  return value;
543 }
545 template <typename T> std::string generate_set(const T &set) {
546  using element_t = typename detail::element_type<T>::type;
547  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
548  std::string out(1, '{');
549  out.append(detail::join(
550  detail::smart_deref(set),
551  [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
552  ","));
553  out.push_back('}');
554  return out;
555 }
556 
558 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
559  using element_t = typename detail::element_type<T>::type;
560  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
561  std::string out(1, '{');
562  out.append(detail::join(
563  detail::smart_deref(map),
564  [key_only](const iteration_type_t &v) {
566 
567  if(!key_only) {
568  res.append("->");
570  }
571  return res;
572  },
573  ","));
574  out.push_back('}');
575  return out;
576 }
577 
578 template <typename C, typename V> struct has_find {
579  template <typename CC, typename VV>
580  static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
581  template <typename, typename> static auto test(...) -> decltype(std::false_type());
582 
583  static const auto value = decltype(test<C, V>(0))::value;
584  using type = std::integral_constant<bool, value>;
585 };
586 
588 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
589 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
590  using element_t = typename detail::element_type<T>::type;
591  auto &setref = detail::smart_deref(set);
592  auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
593  return (detail::pair_adaptor<element_t>::first(v) == val);
594  });
595  return {(it != std::end(setref)), it};
596 }
597 
599 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
600 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
601  auto &setref = detail::smart_deref(set);
602  auto it = setref.find(val);
603  return {(it != std::end(setref)), it};
604 }
605 
607 template <typename T, typename V>
608 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
609  -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
610  using element_t = typename detail::element_type<T>::type;
611  // do the potentially faster first search
612  auto res = search(set, val);
613  if((res.first) || (!(filter_function))) {
614  return res;
615  }
616  // if we haven't found it do the longer linear search with all the element translations
617  auto &setref = detail::smart_deref(set);
618  auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
620  a = filter_function(a);
621  return (a == val);
622  });
623  return {(it != std::end(setref)), it};
624 }
625 
626 // the following suggestion was made by Nikita Ofitserov(@himikof)
627 // done in templates to prevent compiler warnings on negation of unsigned numbers
628 
630 template <typename T>
631 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
632  if((a > 0) == (b > 0)) {
633  return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
634  } else {
635  return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
636  }
637 }
639 template <typename T>
640 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
641  return ((std::numeric_limits<T>::max)() / a < b);
642 }
643 
645 template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
646  if(a == 0 || b == 0 || a == 1 || b == 1) {
647  a *= b;
648  return true;
649  }
650  if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
651  return false;
652  }
653  if(overflowCheck(a, b)) {
654  return false;
655  }
656  a *= b;
657  return true;
658 }
659 
661 template <typename T>
662 typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
663  T c = a * b;
664  if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
665  return false;
666  }
667  a = c;
668  return true;
669 }
670 
671 } // namespace detail
673 class IsMember : public Validator {
674  public:
675  using filter_fn_t = std::function<std::string(std::string)>;
676 
678  template <typename T, typename... Args>
679  IsMember(std::initializer_list<T> values, Args &&... args)
680  : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
681 
683  template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
684 
687  template <typename T, typename F> explicit IsMember(T set, F filter_function) {
688 
689  // Get the type of the contained item - requires a container have ::value_type
690  // if the type does not have first_type and second_type, these are both value_type
691  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
692  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
693 
694  using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
695  // (const char * to std::string)
696 
697  // Make a local copy of the filter function, using a std::function if not one already
698  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
699 
700  // This is the type name for help, it will take the current version of the set contents
701  desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
702 
703  // This is the function that validates
704  // It stores a copy of the set pointer-like, so shared_ptr will stay alive
705  func_ = [set, filter_fn](std::string &input) {
706  local_item_t b;
707  if(!detail::lexical_cast(input, b)) {
708  throw ValidationError(input); // name is added later
709  }
710  if(filter_fn) {
711  b = filter_fn(b);
712  }
713  auto res = detail::search(set, b, filter_fn);
714  if(res.first) {
715  // Make sure the version in the input string is identical to the one in the set
716  if(filter_fn) {
718  }
719 
720  // Return empty error string (success)
721  return std::string{};
722  }
723 
724  // If you reach this point, the result was not found
725  return input + " not in " + detail::generate_set(detail::smart_deref(set));
726  };
727  }
728 
730  template <typename T, typename... Args>
731  IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
732  : IsMember(
733  std::forward<T>(set),
734  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
735  other...) {}
736 };
737 
739 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
740 
742 class Transformer : public Validator {
743  public:
744  using filter_fn_t = std::function<std::string(std::string)>;
745 
747  template <typename... Args>
748  Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&... args)
749  : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
750 
752  template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
753 
756  template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
757 
758  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
759  "mapping must produce value pairs");
760  // Get the type of the contained item - requires a container have ::value_type
761  // if the type does not have first_type and second_type, these are both value_type
762  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
763  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
764  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
765  // (const char * to std::string)
766 
767  // Make a local copy of the filter function, using a std::function if not one already
768  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
769 
770  // This is the type name for help, it will take the current version of the set contents
771  desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
772 
773  func_ = [mapping, filter_fn](std::string &input) {
774  local_item_t b;
775  if(!detail::lexical_cast(input, b)) {
776  return std::string();
777  // there is no possible way we can match anything in the mapping if we can't convert so just return
778  }
779  if(filter_fn) {
780  b = filter_fn(b);
781  }
782  auto res = detail::search(mapping, b, filter_fn);
783  if(res.first) {
785  }
786  return std::string{};
787  };
788  }
789 
791  template <typename T, typename... Args>
792  Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
793  : Transformer(
794  std::forward<T>(mapping),
795  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
796  other...) {}
797 };
798 
801  public:
802  using filter_fn_t = std::function<std::string(std::string)>;
803 
805  template <typename... Args>
806  CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&... args)
807  : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
808 
810  template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
811 
814  template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
815 
816  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
817  "mapping must produce value pairs");
818  // Get the type of the contained item - requires a container have ::value_type
819  // if the type does not have first_type and second_type, these are both value_type
820  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
821  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
822  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
823  // (const char * to std::string)
824  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
825 
826  // Make a local copy of the filter function, using a std::function if not one already
827  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
828 
829  auto tfunc = [mapping]() {
830  std::string out("value in ");
831  out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
832  out += detail::join(
833  detail::smart_deref(mapping),
834  [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
835  ",");
836  out.push_back('}');
837  return out;
838  };
839 
840  desc_function_ = tfunc;
841 
842  func_ = [mapping, tfunc, filter_fn](std::string &input) {
843  local_item_t b;
844  bool converted = detail::lexical_cast(input, b);
845  if(converted) {
846  if(filter_fn) {
847  b = filter_fn(b);
848  }
849  auto res = detail::search(mapping, b, filter_fn);
850  if(res.first) {
852  return std::string{};
853  }
854  }
855  for(const auto &v : detail::smart_deref(mapping)) {
857  if(output_string == input) {
858  return std::string();
859  }
860  }
861 
862  return "Check " + input + " " + tfunc() + " FAILED";
863  };
864  }
865 
867  template <typename T, typename... Args>
868  CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&... other)
870  std::forward<T>(mapping),
871  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
872  other...) {}
873 };
874 
876 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
877 
879 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
880 
882 inline std::string ignore_space(std::string item) {
883  item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
884  item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
885  return item;
886 }
887 
899 class AsNumberWithUnit : public Validator {
900  public:
905  enum Options {
911  };
912 
913  template <typename Number>
914  explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
915  Options opts = DEFAULT,
916  const std::string &unit_name = "UNIT") {
917  description(generate_description<Number>(unit_name, opts));
918  validate_mapping(mapping, opts);
919 
920  // transform function
921  func_ = [mapping, opts](std::string &input) -> std::string {
922  Number num;
923 
924  detail::rtrim(input);
925  if(input.empty()) {
926  throw ValidationError("Input is empty");
927  }
928 
929  // Find split position between number and prefix
930  auto unit_begin = input.end();
931  while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
932  --unit_begin;
933  }
934 
935  std::string unit{unit_begin, input.end()};
936  input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
937  detail::trim(input);
938 
939  if(opts & UNIT_REQUIRED && unit.empty()) {
940  throw ValidationError("Missing mandatory unit");
941  }
942  if(opts & CASE_INSENSITIVE) {
943  unit = detail::to_lower(unit);
944  }
945  if(unit.empty()) {
946  if(!detail::lexical_cast(input, num)) {
947  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
948  detail::type_name<Number>());
949  }
950  // No need to modify input if no unit passed
951  return {};
952  }
953 
954  // find corresponding factor
955  auto it = mapping.find(unit);
956  if(it == mapping.end()) {
957  throw ValidationError(unit +
958  " unit not recognized. "
959  "Allowed values: " +
960  detail::generate_map(mapping, true));
961  }
962 
963  if(!input.empty()) {
964  bool converted = detail::lexical_cast(input, num);
965  if(!converted) {
966  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
967  detail::type_name<Number>());
968  }
969  // perform safe multiplication
970  bool ok = detail::checked_multiply(num, it->second);
971  if(!ok) {
972  throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
973  " factor would cause number overflow. Use smaller value.");
974  }
975  } else {
976  num = static_cast<Number>(it->second);
977  }
978 
979  input = detail::to_string(num);
980 
981  return {};
982  };
983  }
984 
985  private:
988  template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
989  for(auto &kv : mapping) {
990  if(kv.first.empty()) {
991  throw ValidationError("Unit must not be empty.");
992  }
993  if(!detail::isalpha(kv.first)) {
994  throw ValidationError("Unit must contain only letters.");
995  }
996  }
997 
998  // make all units lowercase if CASE_INSENSITIVE
999  if(opts & CASE_INSENSITIVE) {
1000  std::map<std::string, Number> lower_mapping;
1001  for(auto &kv : mapping) {
1002  auto s = detail::to_lower(kv.first);
1003  if(lower_mapping.count(s)) {
1004  throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
1005  s);
1006  }
1007  lower_mapping[detail::to_lower(kv.first)] = kv.second;
1008  }
1009  mapping = std::move(lower_mapping);
1010  }
1011  }
1012 
1014  template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
1015  std::stringstream out;
1016  out << detail::type_name<Number>() << ' ';
1017  if(opts & UNIT_REQUIRED) {
1018  out << name;
1019  } else {
1020  out << '[' << name << ']';
1021  }
1022  return out.str();
1023  }
1024 };
1025 
1038  public:
1039  using result_t = std::uint64_t;
1040 
1048  explicit AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) {
1049  if(kb_is_1000) {
1050  description("SIZE [b, kb(=1000b), kib(=1024b), ...]");
1051  } else {
1052  description("SIZE [b, kb(=1024b), ...]");
1053  }
1054  }
1055 
1056  private:
1058  static std::map<std::string, result_t> init_mapping(bool kb_is_1000) {
1059  std::map<std::string, result_t> m;
1060  result_t k_factor = kb_is_1000 ? 1000 : 1024;
1061  result_t ki_factor = 1024;
1062  result_t k = 1;
1063  result_t ki = 1;
1064  m["b"] = 1;
1065  for(std::string p : {"k", "m", "g", "t", "p", "e"}) {
1066  k *= k_factor;
1067  ki *= ki_factor;
1068  m[p] = k;
1069  m[p + "b"] = k;
1070  m[p + "i"] = ki;
1071  m[p + "ib"] = ki;
1072  }
1073  return m;
1074  }
1075 
1077  static std::map<std::string, result_t> get_mapping(bool kb_is_1000) {
1078  if(kb_is_1000) {
1079  static auto m = init_mapping(true);
1080  return m;
1081  } else {
1082  static auto m = init_mapping(false);
1083  return m;
1084  }
1085  }
1086 };
1087 
1088 namespace detail {
1093 inline std::pair<std::string, std::string> split_program_name(std::string commandline) {
1094  // try to determine the programName
1095  std::pair<std::string, std::string> vals;
1096  trim(commandline);
1097  auto esp = commandline.find_first_of(' ', 1);
1098  while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
1099  esp = commandline.find_first_of(' ', esp + 1);
1100  if(esp == std::string::npos) {
1101  // if we have reached the end and haven't found a valid file just assume the first argument is the
1102  // program name
1103  if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') {
1104  bool embeddedQuote = false;
1105  auto keyChar = commandline[0];
1106  auto end = commandline.find_first_of(keyChar, 1);
1107  while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes
1108  end = commandline.find_first_of(keyChar, end + 1);
1109  embeddedQuote = true;
1110  }
1111  if(end != std::string::npos) {
1112  vals.first = commandline.substr(1, end - 1);
1113  esp = end + 1;
1114  if(embeddedQuote) {
1115  vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar));
1116  }
1117  } else {
1118  esp = commandline.find_first_of(' ', 1);
1119  }
1120  } else {
1121  esp = commandline.find_first_of(' ', 1);
1122  }
1123 
1124  break;
1125  }
1126  }
1127  if(vals.first.empty()) {
1128  vals.first = commandline.substr(0, esp);
1129  rtrim(vals.first);
1130  }
1131 
1132  // strip the program name
1133  vals.second = (esp != std::string::npos) ? commandline.substr(esp + 1) : std::string{};
1134  ltrim(vals.second);
1135  return vals;
1136 }
1137 
1138 } // namespace detail
1140 
1141 // [CLI11:validators_hpp:end]
1142 } // namespace CLI
Definition: Validators.hpp:899
Options
Definition: Validators.hpp:905
@ UNIT_OPTIONAL
Definition: Validators.hpp:908
@ CASE_INSENSITIVE
Definition: Validators.hpp:907
@ DEFAULT
Definition: Validators.hpp:910
@ UNIT_REQUIRED
Definition: Validators.hpp:909
@ CASE_SENSITIVE
Definition: Validators.hpp:906
AsNumberWithUnit(std::map< std::string, Number > mapping, Options opts=DEFAULT, const std::string &unit_name="UNIT")
Definition: Validators.hpp:914
Definition: Validators.hpp:1037
AsSizeValue(bool kb_is_1000)
Definition: Validators.hpp:1048
std::uint64_t result_t
Definition: Validators.hpp:1039
Produce a bounded range (factory). Min and max are inclusive.
Definition: Validators.hpp:501
Bound(T max)
Range of one value is 0 to value.
Definition: Validators.hpp:528
Bound(T min, T max)
Definition: Validators.hpp:507
translate named items to other or a value set
Definition: Validators.hpp:800
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: Validators.hpp:810
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:868
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:802
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&... args)
This allows in-place construction.
Definition: Validators.hpp:806
CheckedTransformer(T mapping, F filter_function)
Definition: Validators.hpp:814
Class wrapping some of the accessors of Validator.
Definition: Validators.hpp:286
Verify items are in a set.
Definition: Validators.hpp:673
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: Validators.hpp:683
IsMember(T set, F filter_function)
Definition: Validators.hpp:687
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:731
IsMember(std::initializer_list< T > values, Args &&... args)
This allows in-place construction using an initializer list.
Definition: Validators.hpp:679
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:675
Produce a range (factory). Min and max are inclusive.
Definition: Validators.hpp:463
Range(T min, T max, const std::string &validator_name=std::string{})
Definition: Validators.hpp:470
Range(T max, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition: Validators.hpp:490
Translate named items to other or a value set.
Definition: Validators.hpp:742
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&... args)
This allows in-place construction.
Definition: Validators.hpp:748
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:744
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: Validators.hpp:752
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:792
Transformer(T mapping, F filter_function)
Definition: Validators.hpp:756
Validate the input as a particular type.
Definition: Validators.hpp:445
TypeValidator()
Definition: Validators.hpp:456
TypeValidator(const std::string &validator_name)
Definition: Validators.hpp:447
Thrown when validation of results fails.
Definition: Error.hpp:212
Some validators that are provided.
Definition: Validators.hpp:77
bool get_active() const
Get a boolean if the validator is active.
Definition: Validators.hpp:191
Validator & description(std::string validator_desc)
Specify the type string.
Definition: Validators.hpp:130
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition: Validators.hpp:88
std::string operator()(const std::string &str) const
Definition: Validators.hpp:124
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition: Validators.hpp:103
Validator operator&(const Validator &other) const
Definition: Validators.hpp:198
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition: Validators.hpp:90
Validator name(std::string validator_name) const
Specify the type string.
Definition: Validators.hpp:153
Validator application_index(int app_index) const
Specify the application index of a validator.
Definition: Validators.hpp:183
bool non_modifying_
specify that a validator should not modify the input
Definition: Validators.hpp:92
Validator & name(std::string validator_name)
Specify the type string.
Definition: Validators.hpp:148
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition: Validators.hpp:97
std::string get_description() const
Generate type description information for the Validator.
Definition: Validators.hpp:141
Validator()=default
std::string operator()(std::string &str) const
Definition: Validators.hpp:109
Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition: Validators.hpp:166
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition: Validators.hpp:80
int get_application_index() const
Get the current value of the application index.
Definition: Validators.hpp:189
std::function< std::string(std::string &)> func_
Definition: Validators.hpp:84
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition: Validators.hpp:246
const std::string & get_name() const
Get the name of the Validator.
Definition: Validators.hpp:159
Validator operator|(const Validator &other) const
Definition: Validators.hpp:223
std::string name_
The name for search purposes of the Validator.
Definition: Validators.hpp:86
Validator description(std::string validator_desc) const
Specify the type string.
Definition: Validators.hpp:135
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition: Validators.hpp:161
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:194
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition: Validators.hpp:99
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition: Validators.hpp:178
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition: Validators.hpp:173
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:357
ExistingDirectoryValidator()
Definition: Validators.hpp:359
Check for an existing file (returns error message if check fails)
Definition: Validators.hpp:340
ExistingFileValidator()
Definition: Validators.hpp:342
Check for an existing path.
Definition: Validators.hpp:374
ExistingPathValidator()
Definition: Validators.hpp:376
Validate the given string is a legal ipv4 address.
Definition: Validators.hpp:402
IPV4Validator()
Definition: Validators.hpp:404
Check for an non-existing path.
Definition: Validators.hpp:388
NonexistentPathValidator()
Definition: Validators.hpp:390
constexpr enabler dummy
An instance to use in EnableIf.
Definition: TypeTools.hpp:33
auto smart_deref(T value) -> decltype(*value)
Definition: Validators.hpp:534
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:269
path_type check_path(const char *file) noexcept
get the type of the path from a file name
Definition: Validators.hpp:324
path_type
CLI enumeration of different file types.
Definition: Validators.hpp:295
std::string generate_map(const T &map, bool key_only=false)
Generate a string representation of a map.
Definition: Validators.hpp:558
std::pair< std::string, std::string > split_program_name(std::string commandline)
Definition: Validators.hpp:1093
std::string remove_underscore(std::string str)
remove underscores from a string
Definition: StringTools.hpp:267
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))>::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() { std::string 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:773
std::string generate_set(const T &set)
Generate a string representation of a set.
Definition: Validators.hpp:545
std::string value_string(const T &value)
get a string as a convertible value for arithmetic types
Definition: TypeTools.hpp:336
std::vector< std::string > split(const std::string &s, char delim)
Split a string by a delim.
Definition: StringTools.hpp:46
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: Validators.hpp:589
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:63
std::string find_and_replace(std::string str, std::string from, std::string to)
Find and replace a substring with another substring.
Definition: StringTools.hpp:273
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:645
bool isalpha(const std::string &str)
Verify that str consists of letters only.
Definition: StringTools.hpp:254
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:631
std::string & ltrim(std::string &str)
Trim whitespace from left of string.
Definition: StringTools.hpp:109
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: StringTools.hpp:138
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:259
std::string & rtrim(std::string &str)
Trim whitespace from right of string.
Definition: StringTools.hpp:123
enabler
Simple empty scoped class.
Definition: TypeTools.hpp:30
bool lexical_cast(const std::string &input, T &output)
Integer conversion.
Definition: TypeTools.hpp:862
Definition: App.hpp:34
const Range PositiveNumber(std::numeric_limits< double >::min(), std::numeric_limits< double >::max(), "POSITIVE")
Check for a positive valued number (val>0.0), min() her is the smallest positive number.
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: Validators.hpp:876
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform.
Definition: Validators.hpp:879
typename std::enable_if< B, T >::type enable_if_t
Definition: TypeTools.hpp:41
const detail::ExistingDirectoryValidator ExistingDirectory
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:433
const detail::NonexistentPathValidator NonexistentPath
Check for an non-existing path.
Definition: Validators.hpp:439
const Range NonNegativeNumber(std::numeric_limits< double >::max(), "NONNEGATIVE")
Check for a non negative number.
const detail::IPV4Validator ValidIPV4
Check for an IP4 address.
Definition: Validators.hpp:442
const detail::ExistingPathValidator ExistingPath
Check for an existing path.
Definition: Validators.hpp:436
std::vector< std::pair< std::string, T > > TransformPairs
definition of the default transformation object
Definition: Validators.hpp:739
const detail::ExistingFileValidator ExistingFile
Check for existing file (returns error message if check fails)
Definition: Validators.hpp:430
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:882
const TypeValidator< double > Number("NUMBER")
Check for a number.
T type
Definition: TypeTools.hpp:73
T type
Definition: TypeTools.hpp:86
Definition: Validators.hpp:578
static const auto value
Definition: Validators.hpp:583
std::integral_constant< bool, value > type
Definition: Validators.hpp:584
static auto test(int) -> decltype(std::declval< CC >().find(std::declval< VV >()), std::true_type())
static auto test(...) -> decltype(std::false_type())
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition: TypeTools.hpp:97
typename T::value_type value_type
Definition: TypeTools.hpp:98
typename std::remove_const< value_type >::type first_type
Definition: TypeTools.hpp:99
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition: TypeTools.hpp:103