Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-08 08:37:05

0001 // Copyright (c) 2017-2025, University of Cincinnati, developed by Henry Schreiner
0002 // under NSF AWARD 1414736 and by the respective contributors.
0003 // All rights reserved.
0004 //
0005 // SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #pragma once
0008 #if (defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS == 1) ||                                  \
0009     (!defined(CLI11_DISABLE_EXTRA_VALIDATORS) || CLI11_DISABLE_EXTRA_VALIDATORS == 0)
0010 // IWYU pragma: private, include "CLI/CLI.hpp"
0011 
0012 #include "Error.hpp"
0013 #include "Macros.hpp"
0014 #include "StringTools.hpp"
0015 #include "Validators.hpp"
0016 
0017 // [CLI11:public_includes:set]
0018 #include <cmath>
0019 #include <cstdint>
0020 #include <functional>
0021 #include <iostream>
0022 #include <limits>
0023 #include <map>
0024 #include <memory>
0025 #include <string>
0026 #include <utility>
0027 #include <vector>
0028 // [CLI11:public_includes:end]
0029 
0030 namespace CLI {
0031 // [CLI11:extra_validators_hpp:verbatim]
0032 // The implementation of the extra validators is using the Validator class;
0033 // the user is only expected to use the const (static) versions (since there's no setup).
0034 // Therefore, this is in detail.
0035 namespace detail {
0036 
0037 /// Validate the given string is a legal ipv4 address
0038 class IPV4Validator : public Validator {
0039   public:
0040     IPV4Validator();
0041 };
0042 
0043 }  // namespace detail
0044 
0045 /// Validate the input as a particular type
0046 template <typename DesiredType> class TypeValidator : public Validator {
0047   public:
0048     explicit TypeValidator(const std::string &validator_name)
0049         : Validator(validator_name, [](std::string &input_string) {
0050               using CLI::detail::lexical_cast;
0051               auto val = DesiredType();
0052               if(!lexical_cast(input_string, val)) {
0053                   return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
0054               }
0055               return std::string{};
0056           }) {}
0057     TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
0058 };
0059 
0060 /// Check for a number
0061 const TypeValidator<double> Number("NUMBER");
0062 
0063 /// Produce a bounded range (factory). Min and max are inclusive.
0064 class Bound : public Validator {
0065   public:
0066     /// This bounds a value with min and max inclusive.
0067     ///
0068     /// Note that the constructor is templated, but the struct is not, so C++17 is not
0069     /// needed to provide nice syntax for Range(a,b).
0070     template <typename T> Bound(T min_val, T max_val) {
0071         std::stringstream out;
0072         out << detail::type_name<T>() << " bounded to [" << min_val << " - " << max_val << "]";
0073         description(out.str());
0074 
0075         func_ = [min_val, max_val](std::string &input) {
0076             using CLI::detail::lexical_cast;
0077             T val;
0078             bool converted = lexical_cast(input, val);
0079             if(!converted) {
0080                 return std::string("Value ") + input + " could not be converted";
0081             }
0082             if(val < min_val)
0083                 input = detail::to_string(min_val);
0084             else if(val > max_val)
0085                 input = detail::to_string(max_val);
0086 
0087             return std::string{};
0088         };
0089     }
0090 
0091     /// Range of one value is 0 to value
0092     template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
0093 };
0094 
0095 // Static is not needed here, because global const implies static.
0096 
0097 /// Check for an IP4 address
0098 const detail::IPV4Validator ValidIPV4;
0099 
0100 namespace detail {
0101 template <typename T,
0102           enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
0103 auto smart_deref(T value) -> decltype(*value) {
0104     return *value;
0105 }
0106 
0107 template <
0108     typename T,
0109     enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
0110 typename std::remove_reference<T>::type &smart_deref(T &value) {
0111     // NOLINTNEXTLINE
0112     return value;
0113 }
0114 /// Generate a string representation of a set
0115 template <typename T> std::string generate_set(const T &set) {
0116     using element_t = typename detail::element_type<T>::type;
0117     using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type;  // the type of the object pair
0118     std::string out(1, '{');
0119     out.append(detail::join(
0120         detail::smart_deref(set),
0121         [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
0122         ","));
0123     out.push_back('}');
0124     return out;
0125 }
0126 
0127 /// Generate a string representation of a map
0128 template <typename T> std::string generate_map(const T &map, bool key_only = false) {
0129     using element_t = typename detail::element_type<T>::type;
0130     using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type;  // the type of the object pair
0131     std::string out(1, '{');
0132     out.append(detail::join(
0133         detail::smart_deref(map),
0134         [key_only](const iteration_type_t &v) {
0135             std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
0136 
0137             if(!key_only) {
0138                 res.append("->");
0139                 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
0140             }
0141             return res;
0142         },
0143         ","));
0144     out.push_back('}');
0145     return out;
0146 }
0147 
0148 template <typename C, typename V> struct has_find {
0149     template <typename CC, typename VV>
0150     static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
0151     template <typename, typename> static auto test(...) -> decltype(std::false_type());
0152 
0153     static const auto value = decltype(test<C, V>(0))::value;
0154     using type = std::integral_constant<bool, value>;
0155 };
0156 
0157 /// A search function
0158 template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
0159 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
0160     using element_t = typename detail::element_type<T>::type;
0161     auto &setref = detail::smart_deref(set);
0162     auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
0163         return (detail::pair_adaptor<element_t>::first(v) == val);
0164     });
0165     return {(it != std::end(setref)), it};
0166 }
0167 
0168 /// A search function that uses the built in find function
0169 template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
0170 auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
0171     auto &setref = detail::smart_deref(set);
0172     auto it = setref.find(val);
0173     return {(it != std::end(setref)), it};
0174 }
0175 
0176 /// A search function with a filter function
0177 template <typename T, typename V>
0178 auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
0179     -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
0180     using element_t = typename detail::element_type<T>::type;
0181     // do the potentially faster first search
0182     auto res = search(set, val);
0183     if((res.first) || (!(filter_function))) {
0184         return res;
0185     }
0186     // if we haven't found it do the longer linear search with all the element translations
0187     auto &setref = detail::smart_deref(set);
0188     auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
0189         V a{detail::pair_adaptor<element_t>::first(v)};
0190         a = filter_function(a);
0191         return (a == val);
0192     });
0193     return {(it != std::end(setref)), it};
0194 }
0195 
0196 }  // namespace detail
0197    /// Verify items are in a set
0198 class IsMember : public Validator {
0199   public:
0200     using filter_fn_t = std::function<std::string(std::string)>;
0201 
0202     /// This allows in-place construction using an initializer list
0203     template <typename T, typename... Args>
0204     IsMember(std::initializer_list<T> values, Args &&...args)
0205         : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
0206 
0207     /// This checks to see if an item is in a set (empty function)
0208     template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
0209 
0210     /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter
0211     /// both sides of the comparison before computing the comparison.
0212     template <typename T, typename F> explicit IsMember(T set, F filter_function) {
0213 
0214         // Get the type of the contained item - requires a container have ::value_type
0215         // if the type does not have first_type and second_type, these are both value_type
0216         using element_t = typename detail::element_type<T>::type;             // Removes (smart) pointers if needed
0217         using item_t = typename detail::pair_adaptor<element_t>::first_type;  // Is value_type if not a map
0218 
0219         using local_item_t = typename IsMemberType<item_t>::type;  // This will convert bad types to good ones
0220         // (const char * to std::string)
0221 
0222         // Make a local copy of the filter function, using a std::function if not one already
0223         std::function<local_item_t(local_item_t)> filter_fn = filter_function;
0224 
0225         // This is the type name for help, it will take the current version of the set contents
0226         desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
0227 
0228         // This is the function that validates
0229         // It stores a copy of the set pointer-like, so shared_ptr will stay alive
0230         func_ = [set, filter_fn](std::string &input) {
0231             using CLI::detail::lexical_cast;
0232             local_item_t b;
0233             if(!lexical_cast(input, b)) {
0234                 throw ValidationError(input);  // name is added later
0235             }
0236             if(filter_fn) {
0237                 b = filter_fn(b);
0238             }
0239             auto res = detail::search(set, b, filter_fn);
0240             if(res.first) {
0241                 // Make sure the version in the input string is identical to the one in the set
0242                 if(filter_fn) {
0243                     input = detail::value_string(detail::pair_adaptor<element_t>::first(*(res.second)));
0244                 }
0245 
0246                 // Return empty error string (success)
0247                 return std::string{};
0248             }
0249 
0250             // If you reach this point, the result was not found
0251             return input + " not in " + detail::generate_set(detail::smart_deref(set));
0252         };
0253     }
0254 
0255     /// You can pass in as many filter functions as you like, they nest (string only currently)
0256     template <typename T, typename... Args>
0257     IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
0258         : IsMember(
0259               std::forward<T>(set),
0260               [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
0261               other...) {}
0262 };
0263 
0264 /// definition of the default transformation object
0265 template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
0266 
0267 /// Translate named items to other or a value set
0268 class Transformer : public Validator {
0269   public:
0270     using filter_fn_t = std::function<std::string(std::string)>;
0271 
0272     /// This allows in-place construction
0273     template <typename... Args>
0274     Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
0275         : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
0276 
0277     /// direct map of std::string to std::string
0278     template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
0279 
0280     /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter
0281     /// both sides of the comparison before computing the comparison.
0282     template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
0283 
0284         static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
0285                       "mapping must produce value pairs");
0286         // Get the type of the contained item - requires a container have ::value_type
0287         // if the type does not have first_type and second_type, these are both value_type
0288         using element_t = typename detail::element_type<T>::type;             // Removes (smart) pointers if needed
0289         using item_t = typename detail::pair_adaptor<element_t>::first_type;  // Is value_type if not a map
0290         using local_item_t = typename IsMemberType<item_t>::type;             // Will convert bad types to good ones
0291         // (const char * to std::string)
0292 
0293         // Make a local copy of the filter function, using a std::function if not one already
0294         std::function<local_item_t(local_item_t)> filter_fn = filter_function;
0295 
0296         // This is the type name for help, it will take the current version of the set contents
0297         desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
0298 
0299         func_ = [mapping, filter_fn](std::string &input) {
0300             using CLI::detail::lexical_cast;
0301             local_item_t b;
0302             if(!lexical_cast(input, b)) {
0303                 return std::string();
0304                 // there is no possible way we can match anything in the mapping if we can't convert so just return
0305             }
0306             if(filter_fn) {
0307                 b = filter_fn(b);
0308             }
0309             auto res = detail::search(mapping, b, filter_fn);
0310             if(res.first) {
0311                 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
0312             }
0313             return std::string{};
0314         };
0315     }
0316 
0317     /// You can pass in as many filter functions as you like, they nest
0318     template <typename T, typename... Args>
0319     Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
0320         : Transformer(
0321               std::forward<T>(mapping),
0322               [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
0323               other...) {}
0324 };
0325 
0326 /// translate named items to other or a value set
0327 class CheckedTransformer : public Validator {
0328   public:
0329     using filter_fn_t = std::function<std::string(std::string)>;
0330 
0331     /// This allows in-place construction
0332     template <typename... Args>
0333     CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
0334         : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
0335 
0336     /// direct map of std::string to std::string
0337     template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
0338 
0339     /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter
0340     /// both sides of the comparison before computing the comparison.
0341     template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
0342 
0343         static_assert(detail::pair_adaptor<typename detail::element_type<T>::type>::value,
0344                       "mapping must produce value pairs");
0345         // Get the type of the contained item - requires a container have ::value_type
0346         // if the type does not have first_type and second_type, these are both value_type
0347         using element_t = typename detail::element_type<T>::type;             // Removes (smart) pointers if needed
0348         using item_t = typename detail::pair_adaptor<element_t>::first_type;  // Is value_type if not a map
0349         using local_item_t = typename IsMemberType<item_t>::type;             // Will convert bad types to good ones
0350         // (const char * to std::string)
0351         using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type;  // the type of the object pair
0352 
0353         // Make a local copy of the filter function, using a std::function if not one already
0354         std::function<local_item_t(local_item_t)> filter_fn = filter_function;
0355 
0356         auto tfunc = [mapping]() {
0357             std::string out("value in ");
0358             out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
0359             out += detail::join(
0360                 detail::smart_deref(mapping),
0361                 [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor<element_t>::second(v)); },
0362                 ",");
0363             out.push_back('}');
0364             return out;
0365         };
0366 
0367         desc_function_ = tfunc;
0368 
0369         func_ = [mapping, tfunc, filter_fn](std::string &input) {
0370             using CLI::detail::lexical_cast;
0371             local_item_t b;
0372             bool converted = lexical_cast(input, b);
0373             if(converted) {
0374                 if(filter_fn) {
0375                     b = filter_fn(b);
0376                 }
0377                 auto res = detail::search(mapping, b, filter_fn);
0378                 if(res.first) {
0379                     input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
0380                     return std::string{};
0381                 }
0382             }
0383             for(const auto &v : detail::smart_deref(mapping)) {
0384                 auto output_string = detail::value_string(detail::pair_adaptor<element_t>::second(v));
0385                 if(output_string == input) {
0386                     return std::string();
0387                 }
0388             }
0389 
0390             return "Check " + input + " " + tfunc() + " FAILED";
0391         };
0392     }
0393 
0394     /// You can pass in as many filter functions as you like, they nest
0395     template <typename T, typename... Args>
0396     CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
0397         : CheckedTransformer(
0398               std::forward<T>(mapping),
0399               [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
0400               other...) {}
0401 };
0402 
0403 /// Helper function to allow ignore_case to be passed to IsMember or Transform
0404 inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
0405 
0406 /// Helper function to allow ignore_underscore to be passed to IsMember or Transform
0407 inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
0408 
0409 /// Helper function to allow checks to ignore spaces to be passed to IsMember or Transform
0410 inline std::string ignore_space(std::string item) {
0411     item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
0412     item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
0413     return item;
0414 }
0415 
0416 /// Multiply a number by a factor using given mapping.
0417 /// Can be used to write transforms for SIZE or DURATION inputs.
0418 ///
0419 /// Example:
0420 ///   With mapping = `{"b"->1, "kb"->1024, "mb"->1024*1024}`
0421 ///   one can recognize inputs like "100", "12kb", "100 MB",
0422 ///   that will be automatically transformed to 100, 14448, 104857600.
0423 ///
0424 /// Output number type matches the type in the provided mapping.
0425 /// Therefore, if it is required to interpret real inputs like "0.42 s",
0426 /// the mapping should be of a type <string, float> or <string, double>.
0427 class AsNumberWithUnit : public Validator {
0428   public:
0429     /// Adjust AsNumberWithUnit behavior.
0430     /// CASE_SENSITIVE/CASE_INSENSITIVE controls how units are matched.
0431     /// UNIT_OPTIONAL/UNIT_REQUIRED throws ValidationError
0432     ///   if UNIT_REQUIRED is set and unit literal is not found.
0433     enum Options : std::uint8_t {
0434         CASE_SENSITIVE = 0,
0435         CASE_INSENSITIVE = 1,
0436         UNIT_OPTIONAL = 0,
0437         UNIT_REQUIRED = 2,
0438         DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
0439     };
0440 
0441     template <typename Number>
0442     explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
0443                               Options opts = DEFAULT,
0444                               const std::string &unit_name = "UNIT") {
0445         description(generate_description<Number>(unit_name, opts));
0446         validate_mapping(mapping, opts);
0447 
0448         // transform function
0449         func_ = [mapping, opts](std::string &input) -> std::string {
0450             Number num{};
0451 
0452             detail::rtrim(input);
0453             if(input.empty()) {
0454                 throw ValidationError("Input is empty");
0455             }
0456 
0457             // Find split position between number and prefix
0458             auto unit_begin = input.end();
0459             while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
0460                 --unit_begin;
0461             }
0462 
0463             std::string unit{unit_begin, input.end()};
0464             input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
0465             detail::trim(input);
0466 
0467             if(opts & UNIT_REQUIRED && unit.empty()) {
0468                 throw ValidationError("Missing mandatory unit");
0469             }
0470             if(opts & CASE_INSENSITIVE) {
0471                 unit = detail::to_lower(unit);
0472             }
0473             if(unit.empty()) {
0474                 using CLI::detail::lexical_cast;
0475                 if(!lexical_cast(input, num)) {
0476                     throw ValidationError(std::string("Value ") + input + " could not be converted to " +
0477                                           detail::type_name<Number>());
0478                 }
0479                 // No need to modify input if no unit passed
0480                 return {};
0481             }
0482 
0483             // find corresponding factor
0484             auto it = mapping.find(unit);
0485             if(it == mapping.end()) {
0486                 throw ValidationError(unit +
0487                                       " unit not recognized. "
0488                                       "Allowed values: " +
0489                                       detail::generate_map(mapping, true));
0490             }
0491 
0492             if(!input.empty()) {
0493                 using CLI::detail::lexical_cast;
0494                 bool converted = lexical_cast(input, num);
0495                 if(!converted) {
0496                     throw ValidationError(std::string("Value ") + input + " could not be converted to " +
0497                                           detail::type_name<Number>());
0498                 }
0499                 // perform safe multiplication
0500                 bool ok = detail::checked_multiply(num, it->second);
0501                 if(!ok) {
0502                     throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
0503                                           " factor would cause number overflow. Use smaller value.");
0504                 }
0505             } else {
0506                 num = static_cast<Number>(it->second);
0507             }
0508 
0509             input = detail::to_string(num);
0510 
0511             return {};
0512         };
0513     }
0514 
0515   private:
0516     /// Check that mapping contains valid units.
0517     /// Update mapping for CASE_INSENSITIVE mode.
0518     template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
0519         for(auto &kv : mapping) {
0520             if(kv.first.empty()) {
0521                 throw ValidationError("Unit must not be empty.");
0522             }
0523             if(!detail::isalpha(kv.first)) {
0524                 throw ValidationError("Unit must contain only letters.");
0525             }
0526         }
0527 
0528         // make all units lowercase if CASE_INSENSITIVE
0529         if(opts & CASE_INSENSITIVE) {
0530             std::map<std::string, Number> lower_mapping;
0531             for(auto &kv : mapping) {
0532                 auto s = detail::to_lower(kv.first);
0533                 if(lower_mapping.count(s)) {
0534                     throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
0535                                           s);
0536                 }
0537                 lower_mapping[detail::to_lower(kv.first)] = kv.second;
0538             }
0539             mapping = std::move(lower_mapping);
0540         }
0541     }
0542 
0543     /// Generate description like this: NUMBER [UNIT]
0544     template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
0545         std::stringstream out;
0546         out << detail::type_name<Number>() << ' ';
0547         if(opts & UNIT_REQUIRED) {
0548             out << name;
0549         } else {
0550             out << '[' << name << ']';
0551         }
0552         return out.str();
0553     }
0554 };
0555 
0556 inline AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b) {
0557     return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
0558 }
0559 
0560 /// Converts a human-readable size string (with unit literal) to uin64_t size.
0561 /// Example:
0562 ///   "100" => 100
0563 ///   "1 b" => 100
0564 ///   "10Kb" => 10240 // you can configure this to be interpreted as kilobyte (*1000) or kibibyte (*1024)
0565 ///   "10 KB" => 10240
0566 ///   "10 kb" => 10240
0567 ///   "10 kib" => 10240 // *i, *ib are always interpreted as *bibyte (*1024)
0568 ///   "10kb" => 10240
0569 ///   "2 MB" => 2097152
0570 ///   "2 EiB" => 2^61 // Units up to exibyte are supported
0571 class AsSizeValue : public AsNumberWithUnit {
0572   public:
0573     using result_t = std::uint64_t;
0574 
0575     /// If kb_is_1000 is true,
0576     /// interpret 'kb', 'k' as 1000 and 'kib', 'ki' as 1024
0577     /// (same applies to higher order units as well).
0578     /// Otherwise, interpret all literals as factors of 1024.
0579     /// The first option is formally correct, but
0580     /// the second interpretation is more wide-spread
0581     /// (see https://en.wikipedia.org/wiki/Binary_prefix).
0582     explicit AsSizeValue(bool kb_is_1000);
0583 
0584   private:
0585     /// Get <size unit, factor> mapping
0586     static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
0587 
0588     /// Cache calculated mapping
0589     static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
0590 };
0591 
0592 #if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
0593 // new extra validators
0594 #if CLI11_HAS_FILESYSTEM
0595 namespace detail {
0596 enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
0597 class PermissionValidator : public Validator {
0598   public:
0599     explicit PermissionValidator(Permission permission);
0600 };
0601 }  // namespace detail
0602 
0603 /// Check that the file exist and available for read
0604 const detail::PermissionValidator ReadPermissions(detail::Permission::read);
0605 
0606 /// Check that the file exist and available for write
0607 const detail::PermissionValidator WritePermissions(detail::Permission::write);
0608 
0609 /// Check that the file exist and available for write
0610 const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
0611 #endif
0612 
0613 #endif
0614 // [CLI11:extra_validators_hpp:end]
0615 }  // namespace CLI
0616 
0617 #ifndef CLI11_COMPILE
0618 #include "impl/ExtraValidators_inl.hpp"  // IWYU pragma: export
0619 #endif
0620 
0621 #endif