CLI11  2.6.2
ExtraValidators.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2026, 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 #if (defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS == 1) || \
9  (!defined(CLI11_DISABLE_EXTRA_VALIDATORS) || CLI11_DISABLE_EXTRA_VALIDATORS == 0)
10 // IWYU pragma: private, include "CLI/CLI.hpp"
11 
12 #include "Error.hpp"
13 #include "Macros.hpp"
14 #include "StringTools.hpp"
15 #include "Validators.hpp"
16 
17 // [CLI11:public_includes:set]
18 #include <cmath>
19 #include <cstdint>
20 #include <functional>
21 #include <iostream>
22 #include <limits>
23 #include <map>
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 // [CLI11:public_includes:end]
29 
30 namespace CLI {
31 // [CLI11:extra_validators_hpp:verbatim]
32 // The implementation of the extra validators is using the Validator class;
33 // the user is only expected to use the const (static) versions (since there's no setup).
34 // Therefore, this is in detail.
35 namespace detail {
36 
38 class IPV4Validator : public Validator {
39  public:
40  IPV4Validator();
41 };
42 
43 } // namespace detail
44 
46 template <typename DesiredType> class TypeValidator : public Validator {
47  public:
48  explicit TypeValidator(const std::string &validator_name)
49  : Validator(validator_name, [](std::string &input_string) {
51  auto val = DesiredType();
52  if(!lexical_cast(input_string, val)) {
53  return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
54  }
55  return std::string{};
56  }) {}
57  TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
58 };
59 
61 const TypeValidator<double> Number("NUMBER");
62 
64 class Bound : public Validator {
65  public:
70  template <typename T> Bound(T min_val, T max_val) {
71  std::stringstream out;
72  out << detail::type_name<T>() << " bounded to [" << min_val << " - " << max_val << "]";
73  description(out.str());
74 
75  func_ = [min_val, max_val](std::string &input) {
77  T val;
78  bool converted = lexical_cast(input, val);
79  if(!converted) {
80  return std::string("Value ") + input + " could not be converted";
81  }
82  if(val < min_val)
83  input = detail::to_string(min_val);
84  else if(val > max_val)
85  input = detail::to_string(max_val);
86 
87  return std::string{};
88  };
89  }
90 
92  template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
93 };
94 
95 // Static is not needed here, because global const implies static.
96 
99 
100 namespace detail {
101 template <typename T,
103 auto smart_deref(T value) -> decltype(*value) {
104  return *value;
105 }
106 
107 template <
108  typename T,
110 typename std::remove_reference<T>::type &smart_deref(T &value) {
111  // NOLINTNEXTLINE
112  return value;
113 }
115 template <typename T> std::string generate_set(const T &set) {
116  using element_t = typename detail::element_type<T>::type;
117  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
118  std::string out(1, '{');
119  out.append(detail::join(
120  detail::smart_deref(set),
121  [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
122  ","));
123  out.push_back('}');
124  return out;
125 }
126 
128 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
129  using element_t = typename detail::element_type<T>::type;
130  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
131  std::string out(1, '{');
132  out.append(detail::join(
133  detail::smart_deref(map),
134  [key_only](const iteration_type_t &v) {
136 
137  if(!key_only) {
138  res.append("->");
140  }
141  return res;
142  },
143  ","));
144  out.push_back('}');
145  return out;
146 }
147 
148 template <typename C, typename V> struct has_find {
149  template <typename CC, typename VV>
150  static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
151  template <typename, typename> static auto test(...) -> decltype(std::false_type());
152 
153  static const auto value = decltype(test<C, V>(0))::value;
154  using type = std::integral_constant<bool, value>;
155 };
156 
158 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
159 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
160  using element_t = typename detail::element_type<T>::type;
161  auto &setref = detail::smart_deref(set);
162  auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
163  return (detail::pair_adaptor<element_t>::first(v) == val);
164  });
165  return {(it != std::end(setref)), it};
166 }
167 
169 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
170 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
171  auto &setref = detail::smart_deref(set);
172  auto it = setref.find(val);
173  return {(it != std::end(setref)), it};
174 }
175 
177 template <typename T, typename V>
178 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
179  -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
180  using element_t = typename detail::element_type<T>::type;
181  // do the potentially faster first search
182  auto res = search(set, val);
183  if((res.first) || (!(filter_function))) {
184  return res;
185  }
186  // if we haven't found it do the longer linear search with all the element translations
187  auto &setref = detail::smart_deref(set);
188  auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
190  a = filter_function(a);
191  return (a == val);
192  });
193  return {(it != std::end(setref)), it};
194 }
195 
196 } // namespace detail
198 class IsMember : public Validator {
199  public:
200  using filter_fn_t = std::function<std::string(std::string)>;
201 
203  template <typename T, typename... Args>
204  IsMember(std::initializer_list<T> values, Args &&...args)
205  : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
206 
208  template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
209 
212  template <typename T, typename F> explicit IsMember(T set, F filter_function) {
213 
214  // Get the type of the contained item - requires a container have ::value_type
215  // if the type does not have first_type and second_type, these are both value_type
216  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
217  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
218 
219  using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
220  // (const char * to std::string)
221 
222  // Make a local copy of the filter function, using a std::function if not one already
223  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
224 
225  // This is the type name for help, it will take the current version of the set contents
226  desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
227 
228  // This is the function that validates
229  // It stores a copy of the set pointer-like, so shared_ptr will stay alive
230  func_ = [set, filter_fn](std::string &input) {
232  local_item_t b;
233  if(!lexical_cast(input, b)) {
234  throw ValidationError(input); // name is added later
235  }
236  if(filter_fn) {
237  b = filter_fn(b);
238  }
239  auto res = detail::search(set, b, filter_fn);
240  if(res.first) {
241  // Make sure the version in the input string is identical to the one in the set
242  if(filter_fn) {
244  }
245 
246  // Return empty error string (success)
247  return std::string{};
248  }
249 
250  // If you reach this point, the result was not found
251  return input + " not in " + detail::generate_set(detail::smart_deref(set));
252  };
253  }
254 
256  template <typename T, typename... Args>
257  IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
258  : IsMember(
259  std::forward<T>(set),
260  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
261  other...) {}
262 };
263 
265 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
266 
268 class Transformer : public Validator {
269  public:
270  using filter_fn_t = std::function<std::string(std::string)>;
271 
273  template <typename... Args>
274  Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
275  : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
276 
278  template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
279 
282  template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
283 
284  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
285  "mapping must produce value pairs");
286  // Get the type of the contained item - requires a container have ::value_type
287  // if the type does not have first_type and second_type, these are both value_type
288  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
289  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
290  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
291  // (const char * to std::string)
292 
293  // Make a local copy of the filter function, using a std::function if not one already
294  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
295 
296  // This is the type name for help, it will take the current version of the set contents
297  desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
298 
299  func_ = [mapping, filter_fn](std::string &input) {
301  local_item_t b;
302  if(!lexical_cast(input, b)) {
303  return std::string();
304  // there is no possible way we can match anything in the mapping if we can't convert so just return
305  }
306  if(filter_fn) {
307  b = filter_fn(b);
308  }
309  auto res = detail::search(mapping, b, filter_fn);
310  if(res.first) {
312  }
313  return std::string{};
314  };
315  }
316 
318  template <typename T, typename... Args>
319  Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
320  : Transformer(
321  std::forward<T>(mapping),
322  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
323  other...) {}
324 };
325 
328  public:
329  using filter_fn_t = std::function<std::string(std::string)>;
330 
332  template <typename... Args>
333  CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
334  : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
335 
337  template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
338 
341  template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
342 
343  static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
344  "mapping must produce value pairs");
345  // Get the type of the contained item - requires a container have ::value_type
346  // if the type does not have first_type and second_type, these are both value_type
347  using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
348  using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
349  using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
350  // (const char * to std::string)
351  using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
352 
353  // Make a local copy of the filter function, using a std::function if not one already
354  std::function<local_item_t(local_item_t)> filter_fn = filter_function;
355 
356  auto tfunc = [mapping]() {
357  std::string out("value in ");
358  out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
359  out += detail::join(
360  detail::smart_deref(mapping),
361  [](const iteration_type_t &v) {
363  },
364  ",");
365  out.push_back('}');
366  return out;
367  };
368 
369  desc_function_ = tfunc;
370 
371  func_ = [mapping, tfunc, filter_fn](std::string &input) {
373  local_item_t b;
374  bool converted = lexical_cast(input, b);
375  if(converted) {
376  if(filter_fn) {
377  b = filter_fn(b);
378  }
379  auto res = detail::search(mapping, b, filter_fn);
380  if(res.first) {
382  return std::string{};
383  }
384  }
385  for(const auto &v : detail::smart_deref(mapping)) {
387  if(output_string == input) {
388  return std::string();
389  }
390  }
391 
392  return "Check " + input + " " + tfunc() + " FAILED";
393  };
394  }
395 
397  template <typename T, typename... Args>
398  CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
400  std::forward<T>(mapping),
401  [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
402  other...) {}
403 };
404 
406 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
407 
409 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
410 
412 inline std::string ignore_space(std::string item) {
413  item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
414  item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
415  return item;
416 }
417 
429 class AsNumberWithUnit : public Validator {
430  public:
435  enum Options : std::uint8_t {
436  CASE_SENSITIVE = 0,
437  CASE_INSENSITIVE = 1,
438  UNIT_OPTIONAL = 0,
439  UNIT_REQUIRED = 2,
440  DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
441  };
442 
443  template <typename Number>
444  explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
445  Options opts = DEFAULT,
446  const std::string &unit_name = "UNIT") {
447  description(generate_description<Number>(unit_name, opts));
448  validate_mapping(mapping, opts);
449 
450  // transform function
451  func_ = [mapping, opts](std::string &input) -> std::string {
452  Number num{};
453 
454  detail::rtrim(input);
455  if(input.empty()) {
456  throw ValidationError("Input is empty");
457  }
458 
459  // Find split position between number and prefix
460  auto unit_begin = input.end();
461  while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
462  --unit_begin;
463  }
464 
465  std::string unit{unit_begin, input.end()};
466  input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
467  detail::trim(input);
468 
469  if(opts & UNIT_REQUIRED && unit.empty()) {
470  throw ValidationError("Missing mandatory unit");
471  }
472  if(opts & CASE_INSENSITIVE) {
473  unit = detail::to_lower(unit);
474  }
475  if(unit.empty()) {
477  if(!lexical_cast(input, num)) {
478  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
479  detail::type_name<Number>());
480  }
481  // No need to modify input if no unit passed
482  return {};
483  }
484 
485  // find corresponding factor
486  auto it = mapping.find(unit);
487  if(it == mapping.end()) {
488  throw ValidationError(unit +
489  " unit not recognized. "
490  "Allowed values: " +
491  detail::generate_map(mapping, true));
492  }
493 
494  if(!input.empty()) {
496  bool converted = lexical_cast(input, num);
497  if(!converted) {
498  throw ValidationError(std::string("Value ") + input + " could not be converted to " +
499  detail::type_name<Number>());
500  }
501  // perform safe multiplication
502  bool ok = detail::checked_multiply(num, it->second);
503  if(!ok) {
504  throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
505  " factor would cause number overflow. Use smaller value.");
506  }
507  } else {
508  num = static_cast<Number>(it->second);
509  }
510 
511  input = detail::to_string(num);
512 
513  return {};
514  };
515  }
516 
517  private:
520  template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
521  for(auto &kv : mapping) {
522  if(kv.first.empty()) {
523  throw ValidationError("Unit must not be empty.");
524  }
525  if(!detail::isalpha(kv.first)) {
526  throw ValidationError("Unit must contain only letters.");
527  }
528  }
529 
530  // make all units lowercase if CASE_INSENSITIVE
531  if(opts & CASE_INSENSITIVE) {
532  std::map<std::string, Number> lower_mapping;
533  for(auto &kv : mapping) {
534  auto s = detail::to_lower(kv.first);
535  if(lower_mapping.count(s)) {
536  throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
537  s);
538  }
539  lower_mapping[detail::to_lower(kv.first)] = kv.second;
540  }
541  mapping = std::move(lower_mapping);
542  }
543  }
544 
546  template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
547  std::stringstream out;
548  out << detail::type_name<Number>() << ' ';
549  if(opts & UNIT_REQUIRED) {
550  out << name;
551  } else {
552  out << '[' << name << ']';
553  }
554  return out.str();
555  }
556 };
557 
559  return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
560 }
561 
574  public:
575  using result_t = std::uint64_t;
576 
584  explicit AsSizeValue(bool kb_is_1000);
585 
586  private:
588  static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
589 
591  static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
592 };
593 
594 #if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
595 // new extra validators
596 #if CLI11_HAS_FILESYSTEM
597 namespace detail {
598 enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
599 class PermissionValidator : public Validator {
600  public:
601  explicit PermissionValidator(Permission permission);
602 };
603 } // namespace detail
604 
606 const detail::PermissionValidator ReadPermissions(detail::Permission::read);
607 
609 const detail::PermissionValidator WritePermissions(detail::Permission::write);
610 
612 const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
613 #endif
614 
615 #endif
616 // [CLI11:extra_validators_hpp:end]
617 } // namespace CLI
618 
619 #ifndef CLI11_COMPILE
620 #include "impl/ExtraValidators_inl.hpp" // IWYU pragma: export
621 #endif
622 
623 #endif
std::uint64_t result_t
Definition: ExtraValidators.hpp:575
Definition: ExtraValidators.hpp:429
TypeValidator(const std::string &validator_name)
Definition: ExtraValidators.hpp:48
Transformer(T mapping, F filter_function)
Definition: ExtraValidators.hpp:282
Validate the input as a particular type.
Definition: ExtraValidators.hpp:46
Definition: App.hpp:36
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition: TypeTools.hpp:130
Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest.
Definition: ExtraValidators.hpp:319
const TypeValidator< double > Number("NUMBER")
Check for a number.
std::string ignore_space(std::string item)
Helper function to allow checks to ignore spaces to be passed to IsMember or Transform.
Definition: ExtraValidators.hpp:412
Produce a bounded range (factory). Min and max are inclusive.
Definition: ExtraValidators.hpp:64
std::string generate_set(const T &set)
Generate a string representation of a set.
Definition: ExtraValidators.hpp:115
TypeValidator()
Definition: ExtraValidators.hpp:57
translate named items to other or a value set
Definition: ExtraValidators.hpp:327
enabler
Simple empty scoped class.
Definition: TypeTools.hpp:36
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: ExtraValidators.hpp:333
std::function< std::string(std::string)> filter_fn_t
Definition: ExtraValidators.hpp:200
AsNumberWithUnit(std::map< std::string, Number > mapping, Options opts=DEFAULT, const std::string &unit_name="UNIT")
Definition: ExtraValidators.hpp:444
STL namespace.
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: ExtraValidators.hpp:406
std::function< std::string(std::string &)> func_
Definition: Validators.hpp:61
auto smart_deref(T value) -> decltype(*value)
Definition: ExtraValidators.hpp:103
Transformer(std::initializer_list< std::pair< std::string, std::string >> values, Args &&...args)
This allows in-place construction.
Definition: ExtraValidators.hpp:274
typename std::remove_const< value_type >::type first_type
Definition: TypeTools.hpp:132
Validate the given string is a legal ipv4 address.
Definition: ExtraValidators.hpp:38
bool lexical_cast(const std::string &input, T &output)
Integer conversion.
Definition: TypeTools.hpp:1123
Definition: ExtraValidators.hpp:573
std::function< std::string(std::string)> filter_fn_t
Definition: ExtraValidators.hpp:329
auto to_string(T &&value) -> decltype(std::forward< T >(value))
Convert an object to a string (directly forward if this can become a string)
Definition: TypeTools.hpp:337
CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest.
Definition: ExtraValidators.hpp:398
std::integral_constant< bool, value > type
Definition: ExtraValidators.hpp:154
Transformer(T &&mapping)
direct map of std::string to std::string
Definition: ExtraValidators.hpp:278
static const auto value
Definition: ExtraValidators.hpp:153
Definition: ExtraValidators.hpp:148
IsMember(T set, F filter_function)
Definition: ExtraValidators.hpp:212
std::function< std::string(std::string)> filter_fn_t
Definition: ExtraValidators.hpp:270
Bound(T max_val)
Range of one value is 0 to value.
Definition: ExtraValidators.hpp:92
std::string ignore_underscore(std::string item)
Helper function to allow ignore_underscore to be passed to IsMember or Transform. ...
Definition: ExtraValidators.hpp:409
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:54
CLI11_MODULE_INLINE const detail::IPV4Validator ValidIPV4
Check for an IP4 address.
Definition: ExtraValidators.hpp:98
static auto test(int) -> decltype(std::declval< CC >().find(std::declval< VV >()), std::true_type())
Bound(T min_val, T max_val)
Definition: ExtraValidators.hpp:70
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: ExtraValidators.hpp:159
Thrown when validation of results fails.
Definition: Error.hpp:221
std::string & trim(std::string &str)
Trim whitespace from string.
Definition: StringTools.hpp:117
CLI11_INLINE std::string & rtrim(std::string &str)
Trim whitespace from right of string.
std::string remove_underscore(std::string str)
remove underscores from a string
Definition: StringTools.hpp:190
#define CLI11_MODULE_INLINE
Definition: Macros.hpp:183
Translate named items to other or a value set.
Definition: ExtraValidators.hpp:268
typename std::enable_if< B, T >::type enable_if_t
Definition: TypeTools.hpp:47
IsMember(T &&set)
This checks to see if an item is in a set (empty function)
Definition: ExtraValidators.hpp:208
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition: ExtraValidators.hpp:204
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: ExtraValidators.hpp:257
Options
Definition: ExtraValidators.hpp:435
std::string to_lower(std::string str)
Return a lower case version of a string.
Definition: StringTools.hpp:182
Verify items are in a set.
Definition: ExtraValidators.hpp:198
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value)
Definition: TypeTools.hpp:136
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 &&!is_complex< 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 &&!is_complex< 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:std::uint8_t{char_value=1, integral_value=2, unsigned_integral=4, enumeration=6, boolean_value=8, floating_point=10, number_constructible=12, double_constructible=14, integer_constructible=16, string_assignable=23, string_constructible=24, wstring_assignable=25, wstring_constructible=26, other=45, wrapper_value=50, complex_number=60, tuple_value=70, container_value=80,};template< typename T, typename Enable=void > struct classify_object{static constexpr object_category value{object_category::other};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&!std::is_same< T, char >::value &&std::is_signed< T >::value &&!is_bool< T >::value &&!std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::integral_value};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&!std::is_same< T, char >::value &&!is_bool< T >::value >::type >{static constexpr object_category value{object_category::unsigned_integral};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_same< T, char >::value &&!std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::char_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_bool< T >::value >::type >{static constexpr object_category value{object_category::boolean_value};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_floating_point< T >::value >::type >{static constexpr object_category value{object_category::floating_point};};#define WIDE_STRING_CHECK#define STRING_CHECKtemplate< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&WIDE_STRING_CHECK &&std::is_assignable< T &, std::string >::value >::type >{static constexpr object_category value{object_category::string_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&(type_count< T >::value==1)&&WIDE_STRING_CHECK &&std::is_constructible< T, std::string >::value >::type >{static constexpr object_category value{object_category::string_constructible};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&STRING_CHECK &&std::is_assignable< T &, std::wstring >::value >::type >{static constexpr object_category value{object_category::wstring_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::wstring >::value &&(type_count< T >::value==1)&&STRING_CHECK &&std::is_constructible< T, std::wstring >::value >::type >{static constexpr object_category value{object_category::wstring_constructible};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_enum< T >::value >::type >{static constexpr object_category value{object_category::enumeration};};template< typename T > struct classify_object< T, typename std::enable_if< is_complex< T >::value >::type >{static constexpr object_category value{object_category::complex_number};};template< typename T > struct uncommon_type{using type=typename std::conditional< !std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&!std::is_constructible< T, std::string >::value &&!std::is_assignable< T &, std::wstring >::value &&!std::is_constructible< T, std::wstring >::value &&!is_complex< T >::value &&!is_mutable_container< T >::value &&!std::is_enum< T >::value, std::true_type, std::false_type >::type;static constexpr bool value=type::value;};template< typename T >struct classify_object< T, typename std::enable_if<(!is_mutable_container< T >::value &&is_wrapper< T >::value &&!is_tuple_like< T >::value &&uncommon_type< T >::value)>::type >{static constexpr object_category value{object_category::wrapper_value};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::number_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&!is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::integer_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value >::type >{static constexpr object_category value{object_category::double_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< is_tuple_like< T >::value &&((type_count< T >::value >=2 &&!is_wrapper< T >::value)||(uncommon_type< T >::value &&!is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value)||(uncommon_type< T >::value &&type_count< T >::value >=2))>::type >{static constexpr object_category value{object_category::tuple_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_mutable_container< T >::value >::type >{static constexpr object_category value{object_category::container_value};};template< typename T, enable_if_t< classify_object< T >::value==object_category::char_value, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"CHAR";}template< typename T, enable_if_t< classify_object< T >::value==object_category::integral_value||classify_object< T >::value==object_category::integer_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"INT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::unsigned_integral, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"UINT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::floating_point||classify_object< T >::value==object_category::number_constructible||classify_object< T >::value==object_category::double_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"FLOAT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::enumeration, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"ENUM";}template< typename T, enable_if_t< classify_object< T >::value==object_category::boolean_value, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"BOOLEAN";}template< typename T, enable_if_t< classify_object< T >::value==object_category::complex_number, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"COMPLEX";}template< typename T, enable_if_t< classify_object< T >::value >=object_category::string_assignable &&classify_object< T >::value<=object_category::other, detail::enabler >=detail::dummy >constexpr const char *type_name(){return"TEXT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value||classify_object< T >::value==object_category::wrapper_value, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value==1, detail::enabler >=detail::dummy >inline std::string type_name(){return type_name< typename std::decay< typename std::tuple_element< 0, T >::type >::type >);}template< typename T, std::size_t I >inline typename std::enable_if< I==type_count_base< T >::value, std::string >::type tuple_name(){return std::string{};}template< typename T, std::size_t I >inline typename std::enable_if<(I< type_count_base< T >::value), std::string >::type tuple_name(){auto str=std::string{type_name< typename std::decay< typename std::tuple_element< I, T >::type >::type >)}+ ','+tuple_name< T, I+1 >);if(str.back()== ',') str.pop_back();return str;}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler > > std::string type_name()
Recursively generate the tuple type name.
Definition: TypeTools.hpp:927
Some validators that are provided.
Definition: Validators.hpp:54
std::vector< std::pair< std::string, T >> TransformPairs
definition of the default transformation object
Definition: ExtraValidators.hpp:265
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition: ExtraValidators.hpp:337
std::string value_string(const T &value)
get a string as a convertible value for arithmetic types
Definition: TypeTools.hpp:470
T type
Definition: TypeTools.hpp:82
CLI11_MODULE_INLINE constexpr enabler dummy
An instance to use in EnableIf.
Definition: TypeTools.hpp:39
CheckedTransformer(T mapping, F filter_function)
Definition: ExtraValidators.hpp:341
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:307
typename T::value_type value_type
Definition: TypeTools.hpp:131
std::string generate_map(const T &map, bool key_only=false)
Generate a string representation of a map.
Definition: ExtraValidators.hpp:128
AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b)
Definition: ExtraValidators.hpp:558
bool isalpha(const std::string &str)
Verify that str consists of letters only.
Definition: StringTools.hpp:177
T type
Definition: TypeTools.hpp:116
Validator & description(std::string validator_desc)
Specify the type string.
Definition: Validators.hpp:99