arg_router  1.4.0
C++ command line argument parsing and routing
global_parser.hpp
1 // Copyright (C) 2022-2023 by Camden Mannett.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
4 
5 #pragma once
6 
7 #include "arg_router/exception.hpp"
8 #include "arg_router/traits.hpp"
9 #include "arg_router/utility/string_view_ops.hpp"
10 
11 #include <boost/lexical_cast/try_lexical_convert.hpp>
12 
13 namespace arg_router
14 {
25 template <typename T, typename Enable = void>
26 struct parser {
27  [[noreturn]] constexpr static T parse([[maybe_unused]] std::string_view token) noexcept
28  {
29  static_assert(traits::always_false_v<T>,
30  "No parse function for this type, use a custom_parser policy "
31  "or define a parser<T>::parse(std::string_view) specialisation");
32  }
33 };
34 
35 template <typename T>
36 struct parser<T, typename std::enable_if_t<std::is_arithmetic_v<T>>> {
37  [[nodiscard]] static T parse(std::string_view token)
38  {
39  using namespace utility::string_view_ops;
40  using namespace std::string_view_literals;
41 
42  auto result = T{};
43  if (!boost::conversion::try_lexical_convert(token, result)) {
44  throw multi_lang_exception{error_code::failed_to_parse,
45  parsing::token_type{parsing::prefix_type::none, token}};
46  }
47 
48  return result;
49  }
50 };
51 
52 template <typename T>
53 struct parser<T, typename std::enable_if_t<std::is_constructible_v<T, std::string_view>>> {
54  [[nodiscard]] static T parse(std::string_view token) { return T{token}; }
55 };
56 
57 template <>
58 struct parser<bool> {
59  [[nodiscard]] static inline bool parse(std::string_view token)
60  {
61  using namespace utility::string_view_ops;
62  using namespace std::string_view_literals;
63 
64  constexpr auto true_tokens = std::array{
65  "true"sv,
66  "yes"sv,
67  "y"sv,
68  "on"sv,
69  "1"sv,
70  "enable"sv,
71  };
72 
73  constexpr auto false_tokens = std::array{
74  "false"sv,
75  "no"sv,
76  "n"sv,
77  "off"sv,
78  "0"sv,
79  "disable"sv,
80  };
81 
82  const auto match = [&](const auto& list) {
83  return std::find(list.begin(), list.end(), token) != list.end();
84  };
85 
86  if (match(true_tokens)) {
87  return true;
88  }
89  if (match(false_tokens)) {
90  return false;
91  }
92 
93  throw multi_lang_exception{error_code::failed_to_parse,
94  parsing::token_type{parsing::prefix_type::none, token}};
95  }
96 };
97 
98 template <typename T>
99 struct parser<std::optional<T>> {
100  [[nodiscard]] static std::optional<T> parse(std::string_view token)
101  {
102  return parser<T>::parse(token);
103  }
104 };
105 
106 // The default vector-like container parser just forwards onto the value_type parser, this is
107 // because an argument that can be parsed as a complete container will need a custom parser. In
108 // other words, this is only used for positional arg parsing
109 template <typename T>
110 struct parser<T,
111  typename std::enable_if_t<traits::has_push_back_method_v<T> &&
112  !traits::is_specialisation_of_v<T, std::basic_string> &&
113  !std::is_same_v<T, string>>> {
114  [[nodiscard]] static typename T::value_type parse(std::string_view token)
115  {
116  return parser<typename T::value_type>::parse(token);
117  }
118 };
119 } // namespace arg_router
constexpr bool match(token_type token) noexcept
Definition: parsing.hpp:36
@ failed_to_parse
A value token could not be converted into its target value.