File indexing completed on 2024-09-28 07:02:19
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010 #include <cstdint>
0011 #include <exception>
0012 #include <memory>
0013 #include <string>
0014 #include <type_traits>
0015 #include <utility>
0016 #include <vector>
0017
0018
0019 #include "StringTools.hpp"
0020
0021 namespace CLI {
0022
0023
0024
0025
0026
0027 namespace detail {
0028
0029
0030 enum class enabler {};
0031
0032
0033 constexpr enabler dummy = {};
0034 }
0035
0036
0037
0038
0039
0040
0041 template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
0042
0043
0044 template <typename... Ts> struct make_void { using type = void; };
0045
0046
0047 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
0048
0049
0050 template <bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;
0051
0052
0053 template <typename T> struct is_bool : std::false_type {};
0054
0055
0056 template <> struct is_bool<bool> : std::true_type {};
0057
0058
0059 template <typename T> struct is_shared_ptr : std::false_type {};
0060
0061
0062 template <typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
0063
0064
0065 template <typename T> struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
0066
0067
0068 template <typename T> struct is_copyable_ptr {
0069 static bool const value = is_shared_ptr<T>::value || std::is_pointer<T>::value;
0070 };
0071
0072
0073 template <typename T> struct IsMemberType { using type = T; };
0074
0075
0076 template <> struct IsMemberType<const char *> { using type = std::string; };
0077
0078 namespace detail {
0079
0080
0081
0082
0083
0084
0085
0086 template <typename T, typename Enable = void> struct element_type { using type = T; };
0087
0088 template <typename T> struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
0089 using type = typename std::pointer_traits<T>::element_type;
0090 };
0091
0092
0093
0094 template <typename T> struct element_value_type { using type = typename element_type<T>::type::value_type; };
0095
0096
0097 template <typename T, typename _ = void> struct pair_adaptor : std::false_type {
0098 using value_type = typename T::value_type;
0099 using first_type = typename std::remove_const<value_type>::type;
0100 using second_type = typename std::remove_const<value_type>::type;
0101
0102
0103 template <typename Q> static auto first(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
0104 return std::forward<Q>(pair_value);
0105 }
0106
0107 template <typename Q> static auto second(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
0108 return std::forward<Q>(pair_value);
0109 }
0110 };
0111
0112
0113
0114 template <typename T>
0115 struct pair_adaptor<
0116 T,
0117 conditional_t<false, void_t<typename T::value_type::first_type, typename T::value_type::second_type>, void>>
0118 : std::true_type {
0119 using value_type = typename T::value_type;
0120 using first_type = typename std::remove_const<typename value_type::first_type>::type;
0121 using second_type = typename std::remove_const<typename value_type::second_type>::type;
0122
0123
0124 template <typename Q> static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward<Q>(pair_value))) {
0125 return std::get<0>(std::forward<Q>(pair_value));
0126 }
0127
0128 template <typename Q> static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward<Q>(pair_value))) {
0129 return std::get<1>(std::forward<Q>(pair_value));
0130 }
0131 };
0132
0133
0134
0135
0136
0137
0138
0139 #ifdef __GNUC__
0140 #pragma GCC diagnostic push
0141 #pragma GCC diagnostic ignored "-Wnarrowing"
0142 #endif
0143
0144 template <typename T, typename C> class is_direct_constructible {
0145 template <typename TT, typename CC>
0146 static auto test(int, std::true_type) -> decltype(
0147
0148 #ifdef __CUDACC__
0149 #pragma diag_suppress 2361
0150 #endif
0151 TT { std::declval<CC>() }
0152 #ifdef __CUDACC__
0153 #pragma diag_default 2361
0154 #endif
0155 ,
0156 std::is_move_assignable<TT>());
0157
0158 template <typename TT, typename CC> static auto test(int, std::false_type) -> std::false_type;
0159
0160 template <typename, typename> static auto test(...) -> std::false_type;
0161
0162 public:
0163 static constexpr bool value = decltype(test<T, C>(0, typename std::is_constructible<T, C>::type()))::value;
0164 };
0165 #ifdef __GNUC__
0166 #pragma GCC diagnostic pop
0167 #endif
0168
0169
0170
0171
0172 template <typename T, typename S = std::ostringstream> class is_ostreamable {
0173 template <typename TT, typename SS>
0174 static auto test(int) -> decltype(std::declval<SS &>() << std::declval<TT>(), std::true_type());
0175
0176 template <typename, typename> static auto test(...) -> std::false_type;
0177
0178 public:
0179 static constexpr bool value = decltype(test<T, S>(0))::value;
0180 };
0181
0182
0183 template <typename T, typename S = std::istringstream> class is_istreamable {
0184 template <typename TT, typename SS>
0185 static auto test(int) -> decltype(std::declval<SS &>() >> std::declval<TT &>(), std::true_type());
0186
0187 template <typename, typename> static auto test(...) -> std::false_type;
0188
0189 public:
0190 static constexpr bool value = decltype(test<T, S>(0))::value;
0191 };
0192
0193
0194 template <typename T> class is_complex {
0195 template <typename TT>
0196 static auto test(int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
0197
0198 template <typename> static auto test(...) -> std::false_type;
0199
0200 public:
0201 static constexpr bool value = decltype(test<T>(0))::value;
0202 };
0203
0204
0205 template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
0206 bool from_stream(const std::string &istring, T &obj) {
0207 std::istringstream is;
0208 is.str(istring);
0209 is >> obj;
0210 return !is.fail() && !is.rdbuf()->in_avail();
0211 }
0212
0213 template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
0214 bool from_stream(const std::string & , T & ) {
0215 return false;
0216 }
0217
0218
0219 template <typename T, typename _ = void> struct is_mutable_container : std::false_type {};
0220
0221
0222
0223
0224 template <typename T>
0225 struct is_mutable_container<
0226 T,
0227 conditional_t<false,
0228 void_t<typename T::value_type,
0229 decltype(std::declval<T>().end()),
0230 decltype(std::declval<T>().clear()),
0231 decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
0232 std::declval<const typename T::value_type &>()))>,
0233 void>>
0234 : public conditional_t<std::is_constructible<T, std::string>::value, std::false_type, std::true_type> {};
0235
0236
0237 template <typename T, typename _ = void> struct is_readable_container : std::false_type {};
0238
0239
0240
0241
0242 template <typename T>
0243 struct is_readable_container<
0244 T,
0245 conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
0246 : public std::true_type {};
0247
0248
0249 template <typename T, typename _ = void> struct is_wrapper : std::false_type {};
0250
0251
0252 template <typename T>
0253 struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> : public std::true_type {};
0254
0255
0256 template <typename S> class is_tuple_like {
0257 template <typename SS>
0258
0259
0260 static auto test(int) -> decltype(std::tuple_size<typename std::decay<SS>::type>::value, std::true_type{});
0261 template <typename> static auto test(...) -> std::false_type;
0262
0263 public:
0264 static constexpr bool value = decltype(test<S>(0))::value;
0265 };
0266
0267
0268 template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
0269 auto to_string(T &&value) -> decltype(std::forward<T>(value)) {
0270 return std::forward<T>(value);
0271 }
0272
0273
0274 template <typename T,
0275 enable_if_t<std::is_constructible<std::string, T>::value && !std::is_convertible<T, std::string>::value,
0276 detail::enabler> = detail::dummy>
0277 std::string to_string(const T &value) {
0278 return std::string(value);
0279 }
0280
0281
0282 template <typename T,
0283 enable_if_t<!std::is_convertible<std::string, T>::value && !std::is_constructible<std::string, T>::value &&
0284 is_ostreamable<T>::value,
0285 detail::enabler> = detail::dummy>
0286 std::string to_string(T &&value) {
0287 std::stringstream stream;
0288 stream << value;
0289 return stream.str();
0290 }
0291
0292
0293 template <typename T,
0294 enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
0295 !is_readable_container<typename std::remove_const<T>::type>::value,
0296 detail::enabler> = detail::dummy>
0297 std::string to_string(T &&) {
0298 return std::string{};
0299 }
0300
0301
0302 template <typename T,
0303 enable_if_t<!std::is_constructible<std::string, T>::value && !is_ostreamable<T>::value &&
0304 is_readable_container<T>::value,
0305 detail::enabler> = detail::dummy>
0306 std::string to_string(T &&variable) {
0307 std::vector<std::string> defaults;
0308 auto cval = variable.begin();
0309 auto end = variable.end();
0310 while(cval != end) {
0311 defaults.emplace_back(CLI::detail::to_string(*cval));
0312 ++cval;
0313 }
0314 return std::string("[" + detail::join(defaults) + "]");
0315 }
0316
0317
0318 template <typename T1,
0319 typename T2,
0320 typename T,
0321 enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
0322 auto checked_to_string(T &&value) -> decltype(to_string(std::forward<T>(value))) {
0323 return to_string(std::forward<T>(value));
0324 }
0325
0326
0327 template <typename T1,
0328 typename T2,
0329 typename T,
0330 enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
0331 std::string checked_to_string(T &&) {
0332 return std::string{};
0333 }
0334
0335 template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
0336 std::string value_string(const T &value) {
0337 return std::to_string(value);
0338 }
0339
0340 template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
0341 std::string value_string(const T &value) {
0342 return std::to_string(static_cast<typename std::underlying_type<T>::type>(value));
0343 }
0344
0345 template <typename T,
0346 enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
0347 auto value_string(const T &value) -> decltype(to_string(value)) {
0348 return to_string(value);
0349 }
0350
0351
0352 template <typename T, typename def, typename Enable = void> struct wrapped_type { using type = def; };
0353
0354
0355 template <typename T, typename def> struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
0356 using type = typename T::value_type;
0357 };
0358
0359
0360 template <typename T, typename Enable = void> struct type_count_base { static const int value{0}; };
0361
0362
0363 template <typename T>
0364 struct type_count_base<T,
0365 typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
0366 !std::is_void<T>::value>::type> {
0367 static constexpr int value{1};
0368 };
0369
0370
0371 template <typename T>
0372 struct type_count_base<T, typename std::enable_if<is_tuple_like<T>::value && !is_mutable_container<T>::value>::type> {
0373 static constexpr int value{std::tuple_size<T>::value};
0374 };
0375
0376
0377 template <typename T> struct type_count_base<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
0378 static constexpr int value{type_count_base<typename T::value_type>::value};
0379 };
0380
0381
0382
0383
0384 template <typename T> struct subtype_count;
0385
0386
0387 template <typename T> struct subtype_count_min;
0388
0389
0390 template <typename T, typename Enable = void> struct type_count { static const int value{0}; };
0391
0392
0393 template <typename T>
0394 struct type_count<T,
0395 typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
0396 !std::is_void<T>::value>::type> {
0397 static constexpr int value{1};
0398 };
0399
0400
0401 template <typename T> struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
0402 static constexpr int value{2};
0403 };
0404
0405
0406 template <typename T> struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
0407 static constexpr int value{subtype_count<typename T::value_type>::value};
0408 };
0409
0410
0411 template <typename T>
0412 struct type_count<T,
0413 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
0414 !is_mutable_container<T>::value>::type> {
0415 static constexpr int value{type_count<typename T::value_type>::value};
0416 };
0417
0418
0419 template <typename T, std::size_t I>
0420 constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size() {
0421 return 0;
0422 }
0423
0424
0425 template <typename T, std::size_t I>
0426 constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size() {
0427 return subtype_count<typename std::tuple_element<I, T>::type>::value + tuple_type_size<T, I + 1>();
0428 }
0429
0430
0431 template <typename T> struct type_count<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
0432 static constexpr int value{tuple_type_size<T, 0>()};
0433 };
0434
0435
0436 template <typename T> struct subtype_count {
0437 static constexpr int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
0438 };
0439
0440
0441 template <typename T, typename Enable = void> struct type_count_min { static const int value{0}; };
0442
0443
0444 template <typename T>
0445 struct type_count_min<
0446 T,
0447 typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
0448 !is_complex<T>::value && !std::is_void<T>::value>::type> {
0449 static constexpr int value{type_count<T>::value};
0450 };
0451
0452
0453 template <typename T> struct type_count_min<T, typename std::enable_if<is_complex<T>::value>::type> {
0454 static constexpr int value{1};
0455 };
0456
0457
0458 template <typename T>
0459 struct type_count_min<
0460 T,
0461 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>::type> {
0462 static constexpr int value{subtype_count_min<typename T::value_type>::value};
0463 };
0464
0465
0466 template <typename T, std::size_t I>
0467 constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size_min() {
0468 return 0;
0469 }
0470
0471
0472 template <typename T, std::size_t I>
0473 constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size_min() {
0474 return subtype_count_min<typename std::tuple_element<I, T>::type>::value + tuple_type_size_min<T, I + 1>();
0475 }
0476
0477
0478 template <typename T> struct type_count_min<T, typename std::enable_if<is_tuple_like<T>::value>::type> {
0479 static constexpr int value{tuple_type_size_min<T, 0>()};
0480 };
0481
0482
0483 template <typename T> struct subtype_count_min {
0484 static constexpr int value{is_mutable_container<T>::value
0485 ? ((type_count<T>::value < expected_max_vector_size) ? type_count<T>::value : 0)
0486 : type_count_min<T>::value};
0487 };
0488
0489
0490 template <typename T, typename Enable = void> struct expected_count { static const int value{0}; };
0491
0492
0493 template <typename T>
0494 struct expected_count<T,
0495 typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
0496 !std::is_void<T>::value>::type> {
0497 static constexpr int value{1};
0498 };
0499
0500 template <typename T> struct expected_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
0501 static constexpr int value{expected_max_vector_size};
0502 };
0503
0504
0505 template <typename T>
0506 struct expected_count<T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>::type> {
0507 static constexpr int value{expected_count<typename T::value_type>::value};
0508 };
0509
0510
0511 enum class object_category : int {
0512 char_value = 1,
0513 integral_value = 2,
0514 unsigned_integral = 4,
0515 enumeration = 6,
0516 boolean_value = 8,
0517 floating_point = 10,
0518 number_constructible = 12,
0519 double_constructible = 14,
0520 integer_constructible = 16,
0521
0522 string_assignable = 23,
0523 string_constructible = 24,
0524 other = 45,
0525
0526 wrapper_value = 50,
0527 complex_number = 60,
0528 tuple_value = 70,
0529 container_value = 80,
0530
0531 };
0532
0533
0534
0535
0536 template <typename T, typename Enable = void> struct classify_object {
0537 static constexpr object_category value{object_category::other};
0538 };
0539
0540
0541 template <typename T>
0542 struct classify_object<
0543 T,
0544 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
0545 !is_bool<T>::value && !std::is_enum<T>::value>::type> {
0546 static constexpr object_category value{object_category::integral_value};
0547 };
0548
0549
0550 template <typename T>
0551 struct classify_object<T,
0552 typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
0553 !std::is_same<T, char>::value && !is_bool<T>::value>::type> {
0554 static constexpr object_category value{object_category::unsigned_integral};
0555 };
0556
0557
0558 template <typename T>
0559 struct classify_object<T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>::type> {
0560 static constexpr object_category value{object_category::char_value};
0561 };
0562
0563
0564 template <typename T> struct classify_object<T, typename std::enable_if<is_bool<T>::value>::type> {
0565 static constexpr object_category value{object_category::boolean_value};
0566 };
0567
0568
0569 template <typename T> struct classify_object<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
0570 static constexpr object_category value{object_category::floating_point};
0571 };
0572
0573
0574 template <typename T>
0575 struct classify_object<T,
0576 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
0577 std::is_assignable<T &, std::string>::value>::type> {
0578 static constexpr object_category value{object_category::string_assignable};
0579 };
0580
0581
0582 template <typename T>
0583 struct classify_object<
0584 T,
0585 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
0586 !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
0587 std::is_constructible<T, std::string>::value>::type> {
0588 static constexpr object_category value{object_category::string_constructible};
0589 };
0590
0591
0592 template <typename T> struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
0593 static constexpr object_category value{object_category::enumeration};
0594 };
0595
0596 template <typename T> struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
0597 static constexpr object_category value{object_category::complex_number};
0598 };
0599
0600
0601
0602 template <typename T> struct uncommon_type {
0603 using type = typename std::conditional<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
0604 !std::is_assignable<T &, std::string>::value &&
0605 !std::is_constructible<T, std::string>::value && !is_complex<T>::value &&
0606 !is_mutable_container<T>::value && !std::is_enum<T>::value,
0607 std::true_type,
0608 std::false_type>::type;
0609 static constexpr bool value = type::value;
0610 };
0611
0612
0613 template <typename T>
0614 struct classify_object<T,
0615 typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
0616 !is_tuple_like<T>::value && uncommon_type<T>::value)>::type> {
0617 static constexpr object_category value{object_category::wrapper_value};
0618 };
0619
0620
0621 template <typename T>
0622 struct classify_object<T,
0623 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
0624 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
0625 is_direct_constructible<T, int>::value>::type> {
0626 static constexpr object_category value{object_category::number_constructible};
0627 };
0628
0629
0630 template <typename T>
0631 struct classify_object<T,
0632 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
0633 !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
0634 is_direct_constructible<T, int>::value>::type> {
0635 static constexpr object_category value{object_category::integer_constructible};
0636 };
0637
0638
0639 template <typename T>
0640 struct classify_object<T,
0641 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
0642 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
0643 !is_direct_constructible<T, int>::value>::type> {
0644 static constexpr object_category value{object_category::double_constructible};
0645 };
0646
0647
0648 template <typename T>
0649 struct classify_object<
0650 T,
0651 typename std::enable_if<is_tuple_like<T>::value &&
0652 ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
0653 (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
0654 !is_direct_constructible<T, int>::value))>::type> {
0655 static constexpr object_category value{object_category::tuple_value};
0656
0657
0658
0659
0660
0661 };
0662
0663
0664 template <typename T> struct classify_object<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
0665 static constexpr object_category value{object_category::container_value};
0666 };
0667
0668
0669
0670
0671
0672
0673
0674 template <typename T,
0675 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
0676 constexpr const char *type_name() {
0677 return "CHAR";
0678 }
0679
0680 template <typename T,
0681 enable_if_t<classify_object<T>::value == object_category::integral_value ||
0682 classify_object<T>::value == object_category::integer_constructible,
0683 detail::enabler> = detail::dummy>
0684 constexpr const char *type_name() {
0685 return "INT";
0686 }
0687
0688 template <typename T,
0689 enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
0690 constexpr const char *type_name() {
0691 return "UINT";
0692 }
0693
0694 template <typename T,
0695 enable_if_t<classify_object<T>::value == object_category::floating_point ||
0696 classify_object<T>::value == object_category::number_constructible ||
0697 classify_object<T>::value == object_category::double_constructible,
0698 detail::enabler> = detail::dummy>
0699 constexpr const char *type_name() {
0700 return "FLOAT";
0701 }
0702
0703
0704 template <typename T,
0705 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
0706 constexpr const char *type_name() {
0707 return "ENUM";
0708 }
0709
0710
0711 template <typename T,
0712 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
0713 constexpr const char *type_name() {
0714 return "BOOLEAN";
0715 }
0716
0717
0718 template <typename T,
0719 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
0720 constexpr const char *type_name() {
0721 return "COMPLEX";
0722 }
0723
0724
0725 template <typename T,
0726 enable_if_t<classify_object<T>::value >= object_category::string_assignable &&
0727 classify_object<T>::value <= object_category::other,
0728 detail::enabler> = detail::dummy>
0729 constexpr const char *type_name() {
0730 return "TEXT";
0731 }
0732
0733 template <typename T,
0734 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
0735 detail::enabler> = detail::dummy>
0736 std::string type_name();
0737
0738
0739 template <typename T,
0740 enable_if_t<classify_object<T>::value == object_category::container_value ||
0741 classify_object<T>::value == object_category::wrapper_value,
0742 detail::enabler> = detail::dummy>
0743 std::string type_name();
0744
0745
0746 template <typename T,
0747 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value == 1,
0748 detail::enabler> = detail::dummy>
0749 inline std::string type_name() {
0750 return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
0751 }
0752
0753
0754 template <typename T, std::size_t I>
0755 inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
0756 return std::string{};
0757 }
0758
0759
0760 template <typename T, std::size_t I>
0761 inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_name() {
0762 std::string str = std::string(type_name<typename std::decay<typename std::tuple_element<I, T>::type>::type>()) +
0763 ',' + tuple_name<T, I + 1>();
0764 if(str.back() == ',')
0765 str.pop_back();
0766 return str;
0767 }
0768
0769
0770 template <typename T,
0771 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
0772 detail::enabler>>
0773 inline std::string type_name() {
0774 auto tname = std::string(1, '[') + tuple_name<T, 0>();
0775 tname.push_back(']');
0776 return tname;
0777 }
0778
0779
0780 template <typename T,
0781 enable_if_t<classify_object<T>::value == object_category::container_value ||
0782 classify_object<T>::value == object_category::wrapper_value,
0783 detail::enabler>>
0784 inline std::string type_name() {
0785 return type_name<typename T::value_type>();
0786 }
0787
0788
0789
0790
0791 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
0792 bool integral_conversion(const std::string &input, T &output) noexcept {
0793 if(input.empty()) {
0794 return false;
0795 }
0796 char *val = nullptr;
0797 std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
0798 output = static_cast<T>(output_ll);
0799 return val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll;
0800 }
0801
0802
0803 template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
0804 bool integral_conversion(const std::string &input, T &output) noexcept {
0805 if(input.empty()) {
0806 return false;
0807 }
0808 char *val = nullptr;
0809 std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
0810 output = static_cast<T>(output_ll);
0811 return val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll;
0812 }
0813
0814
0815 inline std::int64_t to_flag_value(std::string val) {
0816 static const std::string trueString("true");
0817 static const std::string falseString("false");
0818 if(val == trueString) {
0819 return 1;
0820 }
0821 if(val == falseString) {
0822 return -1;
0823 }
0824 val = detail::to_lower(val);
0825 std::int64_t ret;
0826 if(val.size() == 1) {
0827 if(val[0] >= '1' && val[0] <= '9') {
0828 return (static_cast<std::int64_t>(val[0]) - '0');
0829 }
0830 switch(val[0]) {
0831 case '0':
0832 case 'f':
0833 case 'n':
0834 case '-':
0835 ret = -1;
0836 break;
0837 case 't':
0838 case 'y':
0839 case '+':
0840 ret = 1;
0841 break;
0842 default:
0843 throw std::invalid_argument("unrecognized character");
0844 }
0845 return ret;
0846 }
0847 if(val == trueString || val == "on" || val == "yes" || val == "enable") {
0848 ret = 1;
0849 } else if(val == falseString || val == "off" || val == "no" || val == "disable") {
0850 ret = -1;
0851 } else {
0852 ret = std::stoll(val);
0853 }
0854 return ret;
0855 }
0856
0857
0858 template <typename T,
0859 enable_if_t<classify_object<T>::value == object_category::integral_value ||
0860 classify_object<T>::value == object_category::unsigned_integral,
0861 detail::enabler> = detail::dummy>
0862 bool lexical_cast(const std::string &input, T &output) {
0863 return integral_conversion(input, output);
0864 }
0865
0866
0867 template <typename T,
0868 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
0869 bool lexical_cast(const std::string &input, T &output) {
0870 if(input.size() == 1) {
0871 output = static_cast<T>(input[0]);
0872 return true;
0873 }
0874 return integral_conversion(input, output);
0875 }
0876
0877
0878 template <typename T,
0879 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
0880 bool lexical_cast(const std::string &input, T &output) {
0881 try {
0882 auto out = to_flag_value(input);
0883 output = (out > 0);
0884 return true;
0885 } catch(const std::invalid_argument &) {
0886 return false;
0887 } catch(const std::out_of_range &) {
0888
0889
0890 output = (input[0] != '-');
0891 return true;
0892 }
0893 }
0894
0895
0896 template <typename T,
0897 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
0898 bool lexical_cast(const std::string &input, T &output) {
0899 if(input.empty()) {
0900 return false;
0901 }
0902 char *val = nullptr;
0903 auto output_ld = std::strtold(input.c_str(), &val);
0904 output = static_cast<T>(output_ld);
0905 return val == (input.c_str() + input.size());
0906 }
0907
0908
0909 template <typename T,
0910 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
0911 bool lexical_cast(const std::string &input, T &output) {
0912 using XC = typename wrapped_type<T, double>::type;
0913 XC x{0.0}, y{0.0};
0914 auto str1 = input;
0915 bool worked = false;
0916 auto nloc = str1.find_last_of("+-");
0917 if(nloc != std::string::npos && nloc > 0) {
0918 worked = detail::lexical_cast(str1.substr(0, nloc), x);
0919 str1 = str1.substr(nloc);
0920 if(str1.back() == 'i' || str1.back() == 'j')
0921 str1.pop_back();
0922 worked = worked && detail::lexical_cast(str1, y);
0923 } else {
0924 if(str1.back() == 'i' || str1.back() == 'j') {
0925 str1.pop_back();
0926 worked = detail::lexical_cast(str1, y);
0927 x = XC{0};
0928 } else {
0929 worked = detail::lexical_cast(str1, x);
0930 y = XC{0};
0931 }
0932 }
0933 if(worked) {
0934 output = T{x, y};
0935 return worked;
0936 }
0937 return from_stream(input, output);
0938 }
0939
0940
0941 template <typename T,
0942 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
0943 bool lexical_cast(const std::string &input, T &output) {
0944 output = input;
0945 return true;
0946 }
0947
0948
0949 template <
0950 typename T,
0951 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
0952 bool lexical_cast(const std::string &input, T &output) {
0953 output = T(input);
0954 return true;
0955 }
0956
0957
0958 template <typename T,
0959 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
0960 bool lexical_cast(const std::string &input, T &output) {
0961 typename std::underlying_type<T>::type val;
0962 if(!integral_conversion(input, val)) {
0963 return false;
0964 }
0965 output = static_cast<T>(val);
0966 return true;
0967 }
0968
0969
0970 template <typename T,
0971 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
0972 std::is_assignable<T &, typename T::value_type>::value,
0973 detail::enabler> = detail::dummy>
0974 bool lexical_cast(const std::string &input, T &output) {
0975 typename T::value_type val;
0976 if(lexical_cast(input, val)) {
0977 output = val;
0978 return true;
0979 }
0980 return from_stream(input, output);
0981 }
0982
0983 template <typename T,
0984 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
0985 !std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
0986 detail::enabler> = detail::dummy>
0987 bool lexical_cast(const std::string &input, T &output) {
0988 typename T::value_type val;
0989 if(lexical_cast(input, val)) {
0990 output = T{val};
0991 return true;
0992 }
0993 return from_stream(input, output);
0994 }
0995
0996
0997 template <
0998 typename T,
0999 enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> = detail::dummy>
1000 bool lexical_cast(const std::string &input, T &output) {
1001 int val;
1002 if(integral_conversion(input, val)) {
1003 output = T(val);
1004 return true;
1005 } else {
1006 double dval;
1007 if(lexical_cast(input, dval)) {
1008 output = T{dval};
1009 return true;
1010 }
1011 }
1012 return from_stream(input, output);
1013 }
1014
1015
1016 template <
1017 typename T,
1018 enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> = detail::dummy>
1019 bool lexical_cast(const std::string &input, T &output) {
1020 int val;
1021 if(integral_conversion(input, val)) {
1022 output = T(val);
1023 return true;
1024 }
1025 return from_stream(input, output);
1026 }
1027
1028
1029 template <
1030 typename T,
1031 enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> = detail::dummy>
1032 bool lexical_cast(const std::string &input, T &output) {
1033 double val;
1034 if(lexical_cast(input, val)) {
1035 output = T{val};
1036 return true;
1037 }
1038 return from_stream(input, output);
1039 }
1040
1041
1042 template <typename T,
1043 enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
1044 detail::enabler> = detail::dummy>
1045 bool lexical_cast(const std::string &input, T &output) {
1046 int val;
1047 if(integral_conversion(input, val)) {
1048 #ifdef _MSC_VER
1049 #pragma warning(push)
1050 #pragma warning(disable : 4800)
1051 #endif
1052
1053
1054 output = val;
1055 #ifdef _MSC_VER
1056 #pragma warning(pop)
1057 #endif
1058 return true;
1059 }
1060
1061
1062
1063 return from_stream(input, output);
1064
1065 }
1066
1067
1068 template <typename T,
1069 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value,
1070 detail::enabler> = detail::dummy>
1071 bool lexical_cast(const std::string &input, T &output) {
1072 static_assert(is_istreamable<T>::value,
1073 "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it "
1074 "is convertible from another type use the add_option<T, XC>(...) with XC being the known type");
1075 return from_stream(input, output);
1076 }
1077
1078
1079
1080 template <typename AssignTo,
1081 typename ConvertTo,
1082 enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
1083 (classify_object<AssignTo>::value == object_category::string_assignable ||
1084 classify_object<AssignTo>::value == object_category::string_constructible),
1085 detail::enabler> = detail::dummy>
1086 bool lexical_assign(const std::string &input, AssignTo &output) {
1087 return lexical_cast(input, output);
1088 }
1089
1090
1091 template <typename AssignTo,
1092 typename ConvertTo,
1093 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
1094 classify_object<AssignTo>::value != object_category::string_assignable &&
1095 classify_object<AssignTo>::value != object_category::string_constructible,
1096 detail::enabler> = detail::dummy>
1097 bool lexical_assign(const std::string &input, AssignTo &output) {
1098 if(input.empty()) {
1099 output = AssignTo{};
1100 return true;
1101 }
1102
1103 return lexical_cast(input, output);
1104 }
1105
1106
1107 template <typename AssignTo,
1108 typename ConvertTo,
1109 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
1110 classify_object<AssignTo>::value == object_category::wrapper_value,
1111 detail::enabler> = detail::dummy>
1112 bool lexical_assign(const std::string &input, AssignTo &output) {
1113 if(input.empty()) {
1114 typename AssignTo::value_type emptyVal{};
1115 output = emptyVal;
1116 return true;
1117 }
1118 return lexical_cast(input, output);
1119 }
1120
1121
1122
1123 template <typename AssignTo,
1124 typename ConvertTo,
1125 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
1126 classify_object<AssignTo>::value != object_category::wrapper_value &&
1127 std::is_assignable<AssignTo &, int>::value,
1128 detail::enabler> = detail::dummy>
1129 bool lexical_assign(const std::string &input, AssignTo &output) {
1130 if(input.empty()) {
1131 output = 0;
1132 return true;
1133 }
1134 int val;
1135 if(lexical_cast(input, val)) {
1136 output = val;
1137 return true;
1138 }
1139 return false;
1140 }
1141
1142
1143 template <typename AssignTo,
1144 typename ConvertTo,
1145 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
1146 detail::enabler> = detail::dummy>
1147 bool lexical_assign(const std::string &input, AssignTo &output) {
1148 ConvertTo val{};
1149 bool parse_result = (!input.empty()) ? lexical_cast<ConvertTo>(input, val) : true;
1150 if(parse_result) {
1151 output = val;
1152 }
1153 return parse_result;
1154 }
1155
1156
1157 template <
1158 typename AssignTo,
1159 typename ConvertTo,
1160 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, ConvertTo &>::value &&
1161 std::is_move_assignable<AssignTo>::value,
1162 detail::enabler> = detail::dummy>
1163 bool lexical_assign(const std::string &input, AssignTo &output) {
1164 ConvertTo val{};
1165 bool parse_result = input.empty() ? true : lexical_cast<ConvertTo>(input, val);
1166 if(parse_result) {
1167 output = AssignTo(val);
1168 }
1169 return parse_result;
1170 }
1171
1172
1173 template <typename AssignTo,
1174 typename ConvertTo,
1175 enable_if_t<classify_object<ConvertTo>::value <= object_category::other &&
1176 classify_object<AssignTo>::value <= object_category::wrapper_value,
1177 detail::enabler> = detail::dummy>
1178 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1179 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
1180 }
1181
1182
1183
1184 template <typename AssignTo,
1185 typename ConvertTo,
1186 enable_if_t<(type_count<AssignTo>::value <= 2) && expected_count<AssignTo>::value == 1 &&
1187 is_tuple_like<ConvertTo>::value && type_count_base<ConvertTo>::value == 2,
1188 detail::enabler> = detail::dummy>
1189 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1190
1191 typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type v1;
1192 typename std::tuple_element<1, ConvertTo>::type v2;
1193 bool retval = lexical_assign<decltype(v1), decltype(v1)>(strings[0], v1);
1194 if(strings.size() > 1) {
1195 retval = retval && lexical_assign<decltype(v2), decltype(v2)>(strings[1], v2);
1196 }
1197 if(retval) {
1198 output = AssignTo{v1, v2};
1199 }
1200 return retval;
1201 }
1202
1203
1204 template <class AssignTo,
1205 class ConvertTo,
1206 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
1207 type_count<ConvertTo>::value == 1,
1208 detail::enabler> = detail::dummy>
1209 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1210 output.erase(output.begin(), output.end());
1211 for(const auto &elem : strings) {
1212 typename AssignTo::value_type out;
1213 bool retval = lexical_assign<typename AssignTo::value_type, typename ConvertTo::value_type>(elem, out);
1214 if(!retval) {
1215 return false;
1216 }
1217 output.insert(output.end(), std::move(out));
1218 }
1219 return (!output.empty());
1220 }
1221
1222
1223 template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
1224 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
1225
1226 if(strings.size() >= 2 && !strings[1].empty()) {
1227 using XC2 = typename wrapped_type<ConvertTo, double>::type;
1228 XC2 x{0.0}, y{0.0};
1229 auto str1 = strings[1];
1230 if(str1.back() == 'i' || str1.back() == 'j') {
1231 str1.pop_back();
1232 }
1233 auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y);
1234 if(worked) {
1235 output = ConvertTo{x, y};
1236 }
1237 return worked;
1238 } else {
1239 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
1240 }
1241 }
1242
1243
1244 template <class AssignTo,
1245 class ConvertTo,
1246 enable_if_t<is_mutable_container<AssignTo>::value && (expected_count<ConvertTo>::value == 1) &&
1247 (type_count<ConvertTo>::value == 1),
1248 detail::enabler> = detail::dummy>
1249 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1250 bool retval = true;
1251 output.clear();
1252 output.reserve(strings.size());
1253 for(const auto &elem : strings) {
1254
1255 output.emplace_back();
1256 retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
1257 }
1258 return (!output.empty()) && retval;
1259 }
1260
1261
1262
1263
1264 template <class AssignTo,
1265 class ConvertTo,
1266 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
1267 type_count_base<ConvertTo>::value == 2,
1268 detail::enabler> = detail::dummy>
1269 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
1270
1271
1272 template <class AssignTo,
1273 class ConvertTo,
1274 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
1275 type_count_base<ConvertTo>::value != 2 &&
1276 ((type_count<ConvertTo>::value > 2) ||
1277 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
1278 detail::enabler> = detail::dummy>
1279 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output);
1280
1281
1282 template <class AssignTo,
1283 class ConvertTo,
1284 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
1285 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
1286 type_count<ConvertTo>::value > 2),
1287 detail::enabler> = detail::dummy>
1288 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output);
1289
1290
1291
1292 template <typename AssignTo,
1293 typename ConvertTo,
1294 enable_if_t<!is_tuple_like<AssignTo>::value && !is_mutable_container<AssignTo>::value &&
1295 classify_object<ConvertTo>::value != object_category::wrapper_value &&
1296 (is_mutable_container<ConvertTo>::value || type_count<ConvertTo>::value > 2),
1297 detail::enabler> = detail::dummy>
1298 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1299
1300 if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
1301 ConvertTo val;
1302 auto retval = lexical_conversion<ConvertTo, ConvertTo>(strings, val);
1303 output = AssignTo{val};
1304 return retval;
1305 }
1306 output = AssignTo{};
1307 return true;
1308 }
1309
1310
1311 template <class AssignTo, class ConvertTo, std::size_t I>
1312 inline typename std::enable_if<(I >= type_count_base<AssignTo>::value), bool>::type
1313 tuple_conversion(const std::vector<std::string> &, AssignTo &) {
1314 return true;
1315 }
1316
1317
1318 template <class AssignTo, class ConvertTo>
1319 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1, bool>::type
1320 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
1321 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
1322 strings.erase(strings.begin());
1323 return retval;
1324 }
1325
1326
1327 template <class AssignTo, class ConvertTo>
1328 inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
1329 type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
1330 bool>::type
1331 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
1332 auto retval = lexical_conversion<AssignTo, ConvertTo>(strings, output);
1333 strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
1334 return retval;
1335 }
1336
1337
1338 template <class AssignTo, class ConvertTo>
1339 inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
1340 type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
1341 bool>::type
1342 tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
1343
1344 std::size_t index{subtype_count_min<ConvertTo>::value};
1345 const std::size_t mx_count{subtype_count<ConvertTo>::value};
1346 const std::size_t mx{(std::max)(mx_count, strings.size())};
1347
1348 while(index < mx) {
1349 if(is_separator(strings[index])) {
1350 break;
1351 }
1352 ++index;
1353 }
1354 bool retval = lexical_conversion<AssignTo, ConvertTo>(
1355 std::vector<std::string>(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index)), output);
1356 strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
1357 return retval;
1358 }
1359
1360
1361 template <class AssignTo, class ConvertTo, std::size_t I>
1362 inline typename std::enable_if<(I < type_count_base<AssignTo>::value), bool>::type
1363 tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
1364 bool retval = true;
1365 using ConvertToElement = typename std::
1366 conditional<is_tuple_like<ConvertTo>::value, typename std::tuple_element<I, ConvertTo>::type, ConvertTo>::type;
1367 if(!strings.empty()) {
1368 retval = retval && tuple_type_conversion<typename std::tuple_element<I, AssignTo>::type, ConvertToElement>(
1369 strings, std::get<I>(output));
1370 }
1371 retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
1372 return retval;
1373 }
1374
1375
1376 template <class AssignTo,
1377 class ConvertTo,
1378 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
1379 type_count_base<ConvertTo>::value == 2,
1380 detail::enabler>>
1381 bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
1382 output.clear();
1383 while(!strings.empty()) {
1384
1385 typename std::remove_const<typename std::tuple_element<0, typename ConvertTo::value_type>::type>::type v1;
1386 typename std::tuple_element<1, typename ConvertTo::value_type>::type v2;
1387 bool retval = tuple_type_conversion<decltype(v1), decltype(v1)>(strings, v1);
1388 if(!strings.empty()) {
1389 retval = retval && tuple_type_conversion<decltype(v2), decltype(v2)>(strings, v2);
1390 }
1391 if(retval) {
1392 output.insert(output.end(), typename AssignTo::value_type{v1, v2});
1393 } else {
1394 return false;
1395 }
1396 }
1397 return (!output.empty());
1398 }
1399
1400
1401 template <class AssignTo,
1402 class ConvertTo,
1403 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
1404 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
1405 type_count<ConvertTo>::value > 2),
1406 detail::enabler>>
1407 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1408 static_assert(
1409 !is_tuple_like<ConvertTo>::value || type_count_base<AssignTo>::value == type_count_base<ConvertTo>::value,
1410 "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
1411 return tuple_conversion<AssignTo, ConvertTo, 0>(strings, output);
1412 }
1413
1414
1415 template <class AssignTo,
1416 class ConvertTo,
1417 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
1418 type_count_base<ConvertTo>::value != 2 &&
1419 ((type_count<ConvertTo>::value > 2) ||
1420 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
1421 detail::enabler>>
1422 bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
1423 bool retval = true;
1424 output.clear();
1425 std::vector<std::string> temp;
1426 std::size_t ii{0};
1427 std::size_t icount{0};
1428 std::size_t xcm{type_count<ConvertTo>::value};
1429 auto ii_max = strings.size();
1430 while(ii < ii_max) {
1431 temp.push_back(strings[ii]);
1432 ++ii;
1433 ++icount;
1434 if(icount == xcm || is_separator(temp.back()) || ii == ii_max) {
1435 if(static_cast<int>(xcm) > type_count_min<ConvertTo>::value && is_separator(temp.back())) {
1436 temp.pop_back();
1437 }
1438 typename AssignTo::value_type temp_out;
1439 retval = retval &&
1440 lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
1441 temp.clear();
1442 if(!retval) {
1443 return false;
1444 }
1445 output.insert(output.end(), std::move(temp_out));
1446 icount = 0;
1447 }
1448 }
1449 return retval;
1450 }
1451
1452
1453 template <typename AssignTo,
1454 class ConvertTo,
1455 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
1456 std::is_assignable<ConvertTo &, ConvertTo>::value,
1457 detail::enabler> = detail::dummy>
1458 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
1459 if(strings.empty() || strings.front().empty()) {
1460 output = ConvertTo{};
1461 return true;
1462 }
1463 typename ConvertTo::value_type val;
1464 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
1465 output = ConvertTo{val};
1466 return true;
1467 }
1468 return false;
1469 }
1470
1471
1472 template <typename AssignTo,
1473 class ConvertTo,
1474 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
1475 !std::is_assignable<AssignTo &, ConvertTo>::value,
1476 detail::enabler> = detail::dummy>
1477 bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
1478 using ConvertType = typename ConvertTo::value_type;
1479 if(strings.empty() || strings.front().empty()) {
1480 output = ConvertType{};
1481 return true;
1482 }
1483 ConvertType val;
1484 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
1485 output = val;
1486 return true;
1487 }
1488 return false;
1489 }
1490
1491
1492
1493
1494
1495
1496 template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
1497 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
1498 std::int64_t count{0};
1499 for(auto &flag : flags) {
1500 count += detail::to_flag_value(flag);
1501 }
1502 output = (count > 0) ? static_cast<T>(count) : T{0};
1503 }
1504
1505
1506
1507
1508
1509
1510 template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
1511 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
1512 std::int64_t count{0};
1513 for(auto &flag : flags) {
1514 count += detail::to_flag_value(flag);
1515 }
1516 output = static_cast<T>(count);
1517 }
1518
1519 #ifdef _MSC_VER
1520 #pragma warning(push)
1521 #pragma warning(disable : 4800)
1522 #endif
1523
1524
1525
1526
1527
1528
1529
1530
1531 template <typename T,
1532 enable_if_t<!std::is_signed<T>::value && !std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
1533 void sum_flag_vector(const std::vector<std::string> &flags, T &output) {
1534 std::int64_t count{0};
1535 for(auto &flag : flags) {
1536 count += detail::to_flag_value(flag);
1537 }
1538 std::string out = detail::to_string(count);
1539 lexical_cast(out, output);
1540 }
1541
1542 #ifdef _MSC_VER
1543 #pragma warning(pop)
1544 #endif
1545
1546 }
1547
1548 }