CLI11  2.2.0
Validators.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2022, 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 #elif defined(__wasi__)
36 // As of wasi-sdk-14, filesystem is not implemented
37 #define CLI11_HAS_FILESYSTEM 0
38 #else
39 #include <filesystem>
40 #if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
41 #if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
42 #define CLI11_HAS_FILESYSTEM 1
43 #elif defined(__GLIBCXX__)
44 // if we are using gcc and Version <9 default to no filesystem
45 #define CLI11_HAS_FILESYSTEM 0
46 #else
47 #define CLI11_HAS_FILESYSTEM 1
48 #endif
49 #else
50 #define CLI11_HAS_FILESYSTEM 0
51 #endif
52 #endif
53 #endif
54 #endif
55 
56 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
57 #include <filesystem> // NOLINT(build/include)
58 #else
59 #include <sys/stat.h>
60 #include <sys/types.h>
61 #endif
62 
63 // [CLI11:validators_hpp_filesystem:end]
64 
65 namespace CLI {
66 // [CLI11:validators_hpp:verbatim]
67 
68 class Option;
69 
71 
78 
80 class Validator {
81  protected:
83  std::function<std::string()> desc_function_{[]() { return std::string{}; }};
84 
87  std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
89  std::string name_{};
93  bool active_{true};
95  bool non_modifying_{false};
96 
97  public:
98  Validator() = default;
100  explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
102  Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
103  : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
104  name_(std::move(validator_name)) {}
106  Validator &operation(std::function<std::string(std::string &)> op) {
107  func_ = std::move(op);
108  return *this;
109  }
112  std::string operator()(std::string &str) const {
113  std::string retstring;
114  if(active_) {
115  if(non_modifying_) {
116  std::string value = str;
117  retstring = func_(value);
118  } else {
119  retstring = func_(str);
120  }
121  }
122  return retstring;
123  }
124 
127  std::string operator()(const std::string &str) const {
128  std::string value = str;
129  return (active_) ? func_(value) : std::string{};
130  }
131 
133  Validator &description(std::string validator_desc) {
134  desc_function_ = [validator_desc]() { return validator_desc; };
135  return *this;
136  }
138  Validator description(std::string validator_desc) const {
139  Validator newval(*this);
140  newval.desc_function_ = [validator_desc]() { return validator_desc; };
141  return newval;
142  }
144  std::string get_description() const {
145  if(active_) {
146  return desc_function_();
147  }
148  return std::string{};
149  }
151  Validator &name(std::string validator_name) {
152  name_ = std::move(validator_name);
153  return *this;
154  }
156  Validator name(std::string validator_name) const {
157  Validator newval(*this);
158  newval.name_ = std::move(validator_name);
159  return newval;
160  }
162  const std::string &get_name() const { return name_; }
164  Validator &active(bool active_val = true) {
165  active_ = active_val;
166  return *this;
167  }
169  Validator active(bool active_val = true) const {
170  Validator newval(*this);
171  newval.active_ = active_val;
172  return newval;
173  }
174 
176  Validator &non_modifying(bool no_modify = true) {
177  non_modifying_ = no_modify;
178  return *this;
179  }
181  Validator &application_index(int app_index) {
182  application_index_ = app_index;
183  return *this;
184  }
186  Validator application_index(int app_index) const {
187  Validator newval(*this);
188  newval.application_index_ = app_index;
189  return newval;
190  }
194  bool get_active() const { return active_; }
195 
197  bool get_modifying() const { return !non_modifying_; }
198 
201  Validator operator&(const Validator &other) const {
202  Validator newval;
203 
204  newval._merge_description(*this, other, " AND ");
205 
206  // Give references (will make a copy in lambda function)
207  const std::function<std::string(std::string & filename)> &f1 = func_;
208  const std::function<std::string(std::string & filename)> &f2 = other.func_;
209 
210  newval.func_ = [f1, f2](std::string &input) {
211  std::string s1 = f1(input);
212  std::string s2 = f2(input);
213  if(!s1.empty() && !s2.empty())
214  return std::string("(") + s1 + ") AND (" + s2 + ")";
215  else
216  return s1 + s2;
217  };
218 
219  newval.active_ = (active_ & other.active_);
221  return newval;
222  }
223 
226  Validator operator|(const Validator &other) const {
227  Validator newval;
228 
229  newval._merge_description(*this, other, " OR ");
230 
231  // Give references (will make a copy in lambda function)
232  const std::function<std::string(std::string &)> &f1 = func_;
233  const std::function<std::string(std::string &)> &f2 = other.func_;
234 
235  newval.func_ = [f1, f2](std::string &input) {
236  std::string s1 = f1(input);
237  std::string s2 = f2(input);
238  if(s1.empty() || s2.empty())
239  return std::string();
240 
241  return std::string("(") + s1 + ") OR (" + s2 + ")";
242  };
243  newval.active_ = (active_ & other.active_);
245  return newval;
246  }
247 
250  Validator newval;
251  const std::function<std::string()> &dfunc1 = desc_function_;
252  newval.desc_function_ = [dfunc1]() {
253  auto str = dfunc1();
254  return (!str.empty()) ? std::string("NOT ") + str : std::string{};
255  };
256  // Give references (will make a copy in lambda function)
257  const std::function<std::string(std::string & res)> &f1 = func_;
258 
259  newval.func_ = [f1, dfunc1](std::string &test) -> std::string {
260  std::string s1 = f1(test);
261  if(s1.empty()) {
262  return std::string("check ") + dfunc1() + " succeeded improperly";
263  }
264  return std::string{};
265  };
266  newval.active_ = active_;
268  return newval;
269  }
270 
271  private:
272  void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger) {
273 
274  const std::function<std::string()> &dfunc1 = val1.desc_function_;
275  const std::function<std::string()> &dfunc2 = val2.desc_function_;
276 
277  desc_function_ = [=]() {
278  std::string f1 = dfunc1();
279  std::string f2 = dfunc2();
280  if((f1.empty()) || (f2.empty())) {
281  return f1 + f2;
282  }
283  return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
284  };
285  }
286 }; // namespace CLI
287 
289 class CustomValidator : public Validator {
290  public:
291 };
292 // The implementation of the built in validators is using the Validator class;
293 // the user is only expected to use the const (static) versions (since there's no setup).
294 // Therefore, this is in detail.
295 namespace detail {
296 
299 
300 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
302 inline path_type check_path(const char *file) noexcept {
303  std::error_code ec;
304  auto stat = std::filesystem::status(file, ec);
305  if(ec) {
306  return path_type::nonexistent;
307  }
308  switch(stat.type()) {
309  case std::filesystem::file_type::none:
310  case std::filesystem::file_type::not_found:
311  return path_type::nonexistent;
312  case std::filesystem::file_type::directory:
313  return path_type::directory;
314  case std::filesystem::file_type::symlink:
315  case std::filesystem::file_type::block:
316  case std::filesystem::file_type::character:
317  case std::filesystem::file_type::fifo:
318  case std::filesystem::file_type::socket:
319  case std::filesystem::file_type::regular:
320  case std::filesystem::file_type::unknown:
321  default:
322  return path_type::file;
323  }
324 }
325 #else
327 inline path_type check_path(const char *file) noexcept {
328 #if defined(_MSC_VER)
329  struct __stat64 buffer;
330  if(_stat64(file, &buffer) == 0) {
331  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
332  }
333 #else
334  struct stat buffer;
335  if(stat(file, &buffer) == 0) {
336  return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
337  }
338 #endif
339  return path_type::nonexistent;
340 }
341 #endif
344  public:
346  func_ = [](std::string &filename) {
347  auto path_result = check_path(filename.c_str());
348  if(path_result == path_type::nonexistent) {
349  return "File does not exist: " + filename;
350  }
351  if(path_result == path_type::directory) {
352  return "File is actually a directory: " + filename;
353  }
354  return std::string();
355  };
356  }
357 };
358 
361  public:
363  func_ = [](std::string &filename) {
364  auto path_result = check_path(filename.c_str());
365  if(path_result == path_type::nonexistent) {
366  return "Directory does not exist: " + filename;
367  }
368  if(path_result == path_type::file) {
369  return "Directory is actually a file: " + filename;
370  }
371  return std::string();
372  };
373  }
374 };
375 
378  public:
379  ExistingPathValidator() : Validator("PATH(existing)") {
380  func_ = [](std::string &filename) {
381  auto path_result = check_path(filename.c_str());
382  if(path_result == path_type::nonexistent) {
383  return "Path does not exist: " + filename;
384  }
385  return std::string();
386  };
387  }
388 };
389 
392  public:
393  NonexistentPathValidator() : Validator("PATH(non-existing)") {
394  func_ = [](std::string &filename) {
395  auto path_result = check_path(filename.c_str());
396  if(path_result != path_type::nonexistent) {
397  return "Path already exists: " + filename;
398  }
399  return std::string();
400  };
401  }
402 };
403 
405 class IPV4Validator : public Validator {
406  public:
407  IPV4Validator() : Validator("IPV4") {
408  func_ = [](std::string &ip_addr) {
409  auto result = CLI::detail::split(ip_addr, '.');
410  if(result.size() != 4) {
411  return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')';
412  }
413  int num;
414  for(const auto &var : result) {
415  bool retval = detail::lexical_cast(var, num);
416  if(!retval) {
417  return std::string("Failed parsing number (") + var + ')';
418  }
419  if(num < 0 || num > 255) {
420  return std::string("Each IP number must be between 0 and 255 ") + var;
421  }
422  }
423  return std::string();
424  };
425  }
426 };
427 
428 } // namespace detail
429 
430 // Static is not needed here, because global const implies static.
431 
434 
437 
440 
443 
446 
448 template <typename DesiredType> class TypeValidator : public Validator {
449  public:
450  explicit TypeValidator(const std::string &validator_name) : Validator(validator_name) {
451  func_ = [](std::string &input_string) {
452  auto val = DesiredType();
453  if(!detail::lexical_cast(input_string, val)) {
454  return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
455  }
456  return std::string();
457  };
458  }
459  TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
460 };
461 
464 
467 class FileOnDefaultPath : public Validator {
468  public:
469  explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true) : Validator("FILE") {
470  func_ = [default_path, enableErrorReturn](std::string &filename) {
471  auto path_result = detail::check_path(filename.c_str());
472  if(path_result == detail::path_type::nonexistent) {
473  std::string test_file_path = default_path;
474  if(default_path.back() != '/' && default_path.back() != '\\') {
475  // Add folder separator
476  test_file_path += '/';
477  }
478  test_file_path.append(filename);
479  path_result = detail::check_path(test_file_path.c_str());
480  if(path_result == detail::path_type::file) {
481  filename = test_file_path;
482  } else {
483  if(enableErrorReturn) {
484  return "File does not exist: " + filename;
485  }
486  }
487  }
488  return std::string{};
489  };
490  }
491 };
492 
494 class Range : public Validator {
495  public:
500  template <typename T>
501  Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) {
502  if(validator_name.empty()) {
503  std::stringstream out;
504  out << detail::type_name<T>() << " in [" << min_val << " - " << max_val << "]";
505  description(out.str());
506  }
507 
508  func_ = [min_val, max_val](std::string &input) {
509  T val;
510  bool converted = detail::lexical_cast(input, val);
511  if((!converted) || (val < min_val || val > max_val)) {
512  std::stringstream out;
513  out << "Value " << input << " not in range [";
514  out << min_val << " - " << max_val << "]";
515  return out.str();
516  }
517  return std::string{};
518  };
519  }
520 
522  template <typename T>
523  explicit Range(T max_val, const std::string &validator_name = std::string{})
524  : Range(static_cast<T>(0), max_val, validator_name) {}
525 };
526 
528 const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
529 
531 const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
532 
534 class Bound : public Validator {
535  public:
540  template <typename T> Bound(T min_val, T max_val) {
541  std::stringstream out;
542  out << detail::type_name<T>() << " bounded to [" << min_val << " - " << max_val << "]";
543  description(out.str());
544 
545  func_ = [min_val, max_val](std::string &input) {
546  T val;
547  bool converted = detail::lexical_cast(input, val);
548  if(!converted) {
549  return std::string("Value ") + input + " could not be converted";
550  }
551  if(val < min_val)
552  input = detail::to_string(min_val);
553  else if(val > max_val)
554  input = detail::to_string(max_val);
555 
556  return std::string{};
557  };
558  }
559 
561  template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
562 };
563 
564 namespace detail {
565 template <typename T,
566  enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
567 auto smart_deref(T value) -> decltype(*value) {
568  return *value;
569 }
570 
571 template <
572  typename T,
574 typename std::remove_reference<T>::type &smart_deref(T &value) {
575  return value;
576 }
578 template <typename T> std::string generate_set(const T &set) {
579  using element_t = typename detail::element_type<T>::type;
580  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
581  std::string out(1, '{');
582  out.append(detail::join(
583  detail::smart_deref(set),
584  [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
585  ","));
586  out.push_back('}');
587  return out;
588 }
589 
591 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
592  using element_t = typename detail::element_type<T>::type;
593  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
594  std::string out(1, '{');
595  out.append(detail::join(
596  detail::smart_deref(map),
597  [key_only](const iteration_type_t &v) {
599 
600  if(!key_only) {
601  res.append("->");
603  }
604  return res;
605  },
606  ","));
607  out.push_back('}');
608  return out;
609 }
610 
611 template <typename C, typename V> struct has_find {
612  template <typename CC, typename VV>
613  static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
614  template <typename, typename> static auto test(...) -> decltype(std::false_type());
615 
616  static const auto value = decltype(test<C, V>(0))::value;
617  using type = std::integral_constant<bool, value>;
618 };
619 
621 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
622 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
623  using element_t = typename detail::element_type<T>::type;
624  auto &setref = detail::smart_deref(set);
625  auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
626  return (detail::pair_adaptor<element_t>::first(v) == val);
627  });
628  return {(it != std::end(setref)), it};
629 }
630 
632 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
633 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
634  auto &setref = detail::smart_deref(set);
635  auto it = setref.find(val);
636  return {(it != std::end(setref)), it};
637 }
638 
640 template <typename T, typename V>
641 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
642  -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
643  using element_t = typename detail::element_type<T>::type;
644  // do the potentially faster first search
645  auto res = search(set, val);
646  if((res.first) || (!(filter_function))) {
647  return res;
648  }
649  // if we haven't found it do the longer linear search with all the element translations
650  auto &setref = detail::smart_deref(set);
651  auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
653  a = filter_function(a);
654  return (a == val);
655  });
656  return {(it != std::end(setref)), it};
657 }
658 
659 // the following suggestion was made by Nikita Ofitserov(@himikof)
660 // done in templates to prevent compiler warnings on negation of unsigned numbers
661 
663 template <typename T>
664 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
665  if((a > 0) == (b > 0)) {
666  return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
667  } else {
668  return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
669  }
670 }
672 template <typename T>
673 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
674  return ((std::numeric_limits<T>::max)() / a < b);
675 }
676 
678 template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
679  if(a == 0 || b == 0 || a == 1 || b == 1) {
680  a *= b;
681  return true;
682  }
683  if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
684  return false;
685  }
686  if(overflowCheck(a, b)) {
687  return false;
688  }
689  a *= b;
690  return true;
691 }
692 
694 template <typename T>
695 typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
696  T c = a * b;
697  if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
698  return false;
699  }
700  a = c;
701  return true;
702 }
703 
704 } // namespace detail
706 class IsMember : public Validator {
707  public:
708  using filter_fn_t = std::function<std::string(std::string)>;
709 
711  template <typename T, typename... Args>
712  IsMember(std::initializer_list<T> values, Args &&...args)
713  : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
714 
716  template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
717 
720  template <typename T, typename F> explicit IsMember(T set, F filter_function) {
721 
722  // Get the type of the contained item - requires a container have ::value_type
723  // if the type does not have first_type and second_type, these are both value_type
724  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
725  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
726 
727  using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
728  // (const char * to std::string)
729 
730  // Make a local copy of the filter function, using a std::function if not one already
731  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
732 
733  // This is the type name for help, it will take the current version of the set contents
734  desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
735 
736  // This is the function that validates
737  // It stores a copy of the set pointer-like, so shared_ptr will stay alive
738  func_ = [set, filter_fn](std::string &input) {
739  local_item_t b;
740  if(!detail::lexical_cast(input, b)) {
741  throw ValidationError(input); // name is added later
742  }
743  if(filter_fn) {
744  b = filter_fn(b);
745  }
746  auto res = detail::search(set, b, filter_fn);
747  if(res.first) {
748  // Make sure the version in the input string is identical to the one in the set
749  if(filter_fn) {
751  }
752 
753  // Return empty error string (success)
754  return std::string{};
755  }
756 
757  // If you reach this point, the result was not found
758  return input + " not in " + detail::generate_set(detail::smart_deref(set));
759  };
760  }
761 
763  template <typename T, typename... Args>
764  IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
765  : IsMember(
766  std::forward<T>(set),
767  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
768  other...) {}
769 };
770 
772 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
773 
775 class Transformer : public Validator {
776  public:
777  using filter_fn_t = std::function<std::string(std::string)>;
778 
780  template <typename... Args>
781  Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
782  : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
783 
785  template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
786 
789  template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
790 
791  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
792  "mapping must produce value pairs");
793  // Get the type of the contained item - requires a container have ::value_type
794  // if the type does not have first_type and second_type, these are both value_type
795  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
796  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
797  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
798  // (const char * to std::string)
799 
800  // Make a local copy of the filter function, using a std::function if not one already
801  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
802 
803  // This is the type name for help, it will take the current version of the set contents
804  desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
805 
806  func_ = [mapping, filter_fn](std::string &input) {
807  local_item_t b;
808  if(!detail::lexical_cast(input, b)) {
809  return std::string();
810  // there is no possible way we can match anything in the mapping if we can't convert so just return
811  }
812  if(filter_fn) {
813  b = filter_fn(b);
814  }
815  auto res = detail::search(mapping, b, filter_fn);
816  if(res.first) {
818  }
819  return std::string{};
820  };
821  }
822 
824  template <typename T, typename... Args>
825  Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
826  : Transformer(
827  std::forward<T>(mapping),
828  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
829  other...) {}
830 };
831 
834  public:
835  using filter_fn_t = std::function<std::string(std::string)>;
836 
838  template <typename... Args>
839  CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
840  : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
841 
843  template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
844 
847  template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
848 
849  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
850  "mapping must produce value pairs");
851  // Get the type of the contained item - requires a container have ::value_type
852  // if the type does not have first_type and second_type, these are both value_type
853  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
854  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
855  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
856  // (const char * to std::string)
857  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
858 
859  // Make a local copy of the filter function, using a std::function if not one already
860  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
861 
862  auto tfunc = [mapping]() {
863  std::string out("value in ");
864  out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
865  out += detail::join(
866  detail::smart_deref(mapping),
867  [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
868  ",");
869  out.push_back('}');
870  return out;
871  };
872 
873  desc_function_ = tfunc;
874 
875  func_ = [mapping, tfunc, filter_fn](std::string &input) {
876  local_item_t b;
877  bool converted = detail::lexical_cast(input, b);
878  if(converted) {
879  if(filter_fn) {
880  b = filter_fn(b);
881  }
882  auto res = detail::search(mapping, b, filter_fn);
883  if(res.first) {
885  return std::string{};
886  }
887  }
888  for(const auto &v : detail::smart_deref(mapping)) {
890  if(output_string == input) {
891  return std::string();
892  }
893  }
894 
895  return "Check " + input + " " + tfunc() + " FAILED";
896  };
897  }
898 
900  template <typename T, typename... Args>
901  CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
903  std::forward<T>(mapping),
904  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
905  other...) {}
906 };
907 
909 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
910 
912 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
913 
915 inline std::string ignore_space(std::string item) {
916  item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
917  item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
918  return item;
919 }
920 
932 class AsNumberWithUnit : public Validator {
933  public:
938  enum Options {
944  };
945 
946  template <typename Number>
947  explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
948  Options opts = DEFAULT,
949  const std::string &unit_name = "UNIT") {
950  description(generate_description<Number>(unit_name, opts));
951  validate_mapping(mapping, opts);
952 
953  // transform function
954  func_ = [mapping, opts](std::string &input) -> std::string {
955  Number num;
956 
957  detail::rtrim(input);
958  if(input.empty()) {
959  throw ValidationError("Input is empty");
960  }
961 
962  // Find split position between number and prefix
963  auto unit_begin = input.end();
964  while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
965  --unit_begin;
966  }
967 
968  std::string unit{unit_begin, input.end()};
969  input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
970  detail::trim(input);
971 
972  if(opts & UNIT_REQUIRED && unit.empty()) {
973  throw ValidationError("Missing mandatory unit");
974  }
975  if(opts & CASE_INSENSITIVE) {
976  unit = detail::to_lower(unit);
977  }
978  if(unit.empty()) {
979  if(!detail::lexical_cast(input, num)) {
980  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
981  detail::type_name<Number>());
982  }
983  // No need to modify input if no unit passed
984  return {};
985  }
986 
987  // find corresponding factor
988  auto it = mapping.find(unit);
989  if(it == mapping.end()) {
990  throw ValidationError(unit +
991  " unit not recognized. "
992  "Allowed values: " +
993  detail::generate_map(mapping, true));
994  }
995 
996  if(!input.empty()) {
997  bool converted = detail::lexical_cast(input, num);
998  if(!converted) {
999  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
1000  detail::type_name<Number>());
1001  }
1002  // perform safe multiplication
1003  bool ok = detail::checked_multiply(num, it->second);
1004  if(!ok) {
1005  throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
1006  " factor would cause number overflow. Use smaller value.");
1007  }
1008  } else {
1009  num = static_cast<Number>(it->second);
1010  }
1011 
1012  input = detail::to_string(num);
1013 
1014  return {};
1015  };
1016  }
1017 
1018  private:
1021  template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
1022  for(auto &kv : mapping) {
1023  if(kv.first.empty()) {
1024  throw ValidationError("Unit must not be empty.");
1025  }
1026  if(!detail::isalpha(kv.first)) {
1027  throw ValidationError("Unit must contain only letters.");
1028  }
1029  }
1030 
1031  // make all units lowercase if CASE_INSENSITIVE
1032  if(opts & CASE_INSENSITIVE) {
1033  std::map<std::string, Number> lower_mapping;
1034  for(auto &kv : mapping) {
1035  auto s = detail::to_lower(kv.first);
1036  if(lower_mapping.count(s)) {
1037  throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
1038  s);
1039  }
1040  lower_mapping[detail::to_lower(kv.first)] = kv.second;
1041  }
1042  mapping = std::move(lower_mapping);
1043  }
1044  }
1045 
1047  template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
1048  std::stringstream out;
1049  out << detail::type_name<Number>() << ' ';
1050  if(opts & UNIT_REQUIRED) {
1051  out << name;
1052  } else {
1053  out << '[' << name << ']';
1054  }
1055  return out.str();
1056  }
1057 };
1058 
1071  public:
1072  using result_t = std::uint64_t;
1073 
1081  explicit AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) {
1082  if(kb_is_1000) {
1083  description("SIZE [b, kb(=1000b), kib(=1024b), ...]");
1084  } else {
1085  description("SIZE [b, kb(=1024b), ...]");
1086  }
1087  }
1088 
1089  private:
1091  static std::map<std::string, result_t> init_mapping(bool kb_is_1000) {
1092  std::map<std::string, result_t> m;
1093  result_t k_factor = kb_is_1000 ? 1000 : 1024;
1094  result_t ki_factor = 1024;
1095  result_t k = 1;
1096  result_t ki = 1;
1097  m["b"] = 1;
1098  for(std::string p : {"k", "m", "g", "t", "p", "e"}) {
1099  k *= k_factor;
1100  ki *= ki_factor;
1101  m[p] = k;
1102  m[p + "b"] = k;
1103  m[p + "i"] = ki;
1104  m[p + "ib"] = ki;
1105  }
1106  return m;
1107  }
1108 
1110  static std::map<std::string, result_t> get_mapping(bool kb_is_1000) {
1111  if(kb_is_1000) {
1112  static auto m = init_mapping(true);
1113  return m;
1114  } else {
1115  static auto m = init_mapping(false);
1116  return m;
1117  }
1118  }
1119 };
1120 
1121 namespace detail {
1126 inline std::pair<std::string, std::string> split_program_name(std::string commandline) {
1127  // try to determine the programName
1128  std::pair<std::string, std::string> vals;
1129  trim(commandline);
1130  auto esp = commandline.find_first_of(' ', 1);
1131  while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
1132  esp = commandline.find_first_of(' ', esp + 1);
1133  if(esp == std::string::npos) {
1134  // if we have reached the end and haven't found a valid file just assume the first argument is the
1135  // program name
1136  if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') {
1137  bool embeddedQuote = false;
1138  auto keyChar = commandline[0];
1139  auto end = commandline.find_first_of(keyChar, 1);
1140  while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes
1141  end = commandline.find_first_of(keyChar, end + 1);
1142  embeddedQuote = true;
1143  }
1144  if(end != std::string::npos) {
1145  vals.first = commandline.substr(1, end - 1);
1146  esp = end + 1;
1147  if(embeddedQuote) {
1148  vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar));
1149  }
1150  } else {
1151  esp = commandline.find_first_of(' ', 1);
1152  }
1153  } else {
1154  esp = commandline.find_first_of(' ', 1);
1155  }
1156 
1157  break;
1158  }
1159  }
1160  if(vals.first.empty()) {
1161  vals.first = commandline.substr(0, esp);
1162  rtrim(vals.first);
1163  }
1164 
1165  // strip the program name
1166  vals.second = (esp != std::string::npos) ? commandline.substr(esp + 1) : std::string{};
1167  ltrim(vals.second);
1168  return vals;
1169 }
1170 
1171 } // namespace detail
1173 
1174 // [CLI11:validators_hpp:end]
1175 } // namespace CLI
Definition: Validators.hpp:932
Options
Definition: Validators.hpp:938
@ UNIT_OPTIONAL
Definition: Validators.hpp:941
@ CASE_INSENSITIVE
Definition: Validators.hpp:940
@ DEFAULT
Definition: Validators.hpp:943
@ UNIT_REQUIRED
Definition: Validators.hpp:942
@ CASE_SENSITIVE
Definition: Validators.hpp:939
AsNumberWithUnit(std::map< std::string, Number > mapping, Options opts=DEFAULT, const std::string &unit_name="UNIT")
Definition: Validators.hpp:947
Definition: Validators.hpp:1070
AsSizeValue(bool kb_is_1000)
Definition: Validators.hpp:1081
std::uint64_t result_t
Definition: Validators.hpp:1072
Produce a bounded range (factory). Min and max are inclusive.
Definition: Validators.hpp:534
Bound(T min_val, T max_val)
Definition: Validators.hpp:540
Bound(T max_val)
Range of one value is 0 to value.
Definition: Validators.hpp:561
translate named items to other or a value set
Definition: Validators.hpp:833
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: Validators.hpp:843
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:901
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:835
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:839
CheckedTransformer(T mapping, F filter_function)
Definition: Validators.hpp:847
Class wrapping some of the accessors of Validator.
Definition: Validators.hpp:289
Definition: Validators.hpp:467
FileOnDefaultPath(std::string default_path, bool enableErrorReturn=true)
Definition: Validators.hpp:469
Verify items are in a set.
Definition: Validators.hpp:706
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: Validators.hpp:716
IsMember(T set, F filter_function)
Definition: Validators.hpp:720
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:764
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition: Validators.hpp:712
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:708
Produce a range (factory). Min and max are inclusive.
Definition: Validators.hpp:494
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition: Validators.hpp:501
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition: Validators.hpp:523
Translate named items to other or a value set.
Definition: Validators.hpp:775
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:825
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: Validators.hpp:781
std::function< std::string(std::string)> filter_fn_t
Definition: Validators.hpp:777
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: Validators.hpp:785
Transformer(T mapping, F filter_function)
Definition: Validators.hpp:789
Validate the input as a particular type.
Definition: Validators.hpp:448
TypeValidator()
Definition: Validators.hpp:459
TypeValidator(const std::string &validator_name)
Definition: Validators.hpp:450
Thrown when validation of results fails.
Definition: Error.hpp:212
Some validators that are provided.
Definition: Validators.hpp:80
bool get_active() const
Get a boolean if the validator is active.
Definition: Validators.hpp:194
Validator & description(std::string validator_desc)
Specify the type string.
Definition: Validators.hpp:133
int application_index_
A Validator will only apply to an indexed value (-1 is all elements)
Definition: Validators.hpp:91
std::string operator()(const std::string &str) const
Definition: Validators.hpp:127
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition: Validators.hpp:106
Validator operator&(const Validator &other) const
Definition: Validators.hpp:201
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition: Validators.hpp:93
Validator name(std::string validator_name) const
Specify the type string.
Definition: Validators.hpp:156
Validator application_index(int app_index) const
Specify the application index of a validator.
Definition: Validators.hpp:186
bool non_modifying_
specify that a validator should not modify the input
Definition: Validators.hpp:95
Validator & name(std::string validator_name)
Specify the type string.
Definition: Validators.hpp:151
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition: Validators.hpp:100
std::string get_description() const
Generate type description information for the Validator.
Definition: Validators.hpp:144
Validator()=default
std::string operator()(std::string &str) const
Definition: Validators.hpp:112
Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition: Validators.hpp:169
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition: Validators.hpp:83
int get_application_index() const
Get the current value of the application index.
Definition: Validators.hpp:192
std::function< std::string(std::string &)> func_
Definition: Validators.hpp:87
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition: Validators.hpp:249
const std::string & get_name() const
Get the name of the Validator.
Definition: Validators.hpp:162
Validator operator|(const Validator &other) const
Definition: Validators.hpp:226
std::string name_
The name for search purposes of the Validator.
Definition: Validators.hpp:89
Validator description(std::string validator_desc) const
Specify the type string.
Definition: Validators.hpp:138
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition: Validators.hpp:164
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:197
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition: Validators.hpp:102
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition: Validators.hpp:181
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition: Validators.hpp:176
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:360
ExistingDirectoryValidator()
Definition: Validators.hpp:362
Check for an existing file (returns error message if check fails)
Definition: Validators.hpp:343
ExistingFileValidator()
Definition: Validators.hpp:345
Check for an existing path.
Definition: Validators.hpp:377
ExistingPathValidator()
Definition: Validators.hpp:379
Validate the given string is a legal ipv4 address.
Definition: Validators.hpp:405
IPV4Validator()
Definition: Validators.hpp:407
Check for an non-existing path.
Definition: Validators.hpp:391
NonexistentPathValidator()
Definition: Validators.hpp:393
constexpr enabler dummy
An instance to use in EnableIf.
Definition: TypeTools.hpp:34
auto smart_deref(T value) -> decltype(*value)
Definition: Validators.hpp:567
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:270
path_type check_path(const char *file) noexcept
get the type of the path from a file name
Definition: Validators.hpp:327
path_type
CLI enumeration of different file types.
Definition: Validators.hpp:298
std::string generate_map(const T &map, bool key_only=false)
Generate a string representation of a map.
Definition: Validators.hpp:591
std::pair< std::string, std::string > split_program_name(std::string commandline)
Definition: Validators.hpp:1126
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:777
std::string generate_set(const T &set)
Generate a string representation of a set.
Definition: Validators.hpp:578
std::string value_string(const T &value)
get a string as a convertible value for arithmetic types
Definition: TypeTools.hpp:340
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:622
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:678
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:664
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:31
bool lexical_cast(const std::string &input, T &output)
Integer conversion.
Definition: TypeTools.hpp:883
Definition: App.hpp:34
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: Validators.hpp:909
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform.
Definition: Validators.hpp:912
typename std::enable_if< B, T >::type enable_if_t
Definition: TypeTools.hpp:42
const detail::ExistingDirectoryValidator ExistingDirectory
Check for an existing directory (returns error message if check fails)
Definition: Validators.hpp:436
const detail::NonexistentPathValidator NonexistentPath
Check for an non-existing path.
Definition: Validators.hpp:442
const detail::IPV4Validator ValidIPV4
Check for an IP4 address.
Definition: Validators.hpp:445
const detail::ExistingPathValidator ExistingPath
Check for an existing path.
Definition: Validators.hpp:439
std::vector< std::pair< std::string, T > > TransformPairs
definition of the default transformation object
Definition: Validators.hpp:772
const detail::ExistingFileValidator ExistingFile
Check for existing file (returns error message if check fails)
Definition: Validators.hpp:433
const Range NonNegativeNumber((std::numeric_limits< double >::max)(), "NONNEGATIVE")
Check for a non negative 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:915
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.
const TypeValidator< double > Number("NUMBER")
Check for a number.
T type
Definition: TypeTools.hpp:74
T type
Definition: TypeTools.hpp:87
Definition: Validators.hpp:611
static const auto value
Definition: Validators.hpp:616
std::integral_constant< bool, value > type
Definition: Validators.hpp:617
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:98
typename T::value_type value_type
Definition: TypeTools.hpp:99
typename std::remove_const< value_type >::type first_type
Definition: TypeTools.hpp:100
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition: TypeTools.hpp:104