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