arg_router  1.4.0
C++ command line argument parsing and routing
string_to_policy.hpp
1 // Copyright (C) 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/algorithm.hpp"
8 #include "arg_router/policy/policy.hpp"
10 
14 {
15 namespace detail
16 {
17 template <typename T>
18 struct is_second_element_policy_or_child {
19  using second_type = boost::mp11::mp_second<T>;
20  constexpr static bool value = policy::is_policy_v<second_type> || is_tree_node_v<second_type>;
21 };
22 
23 template <typename T>
25 
26 template <typename T>
27 using multi_char_finder = traits::integral_constant<(utility::utf8::count(T::get()) > 1)>;
28 
29 template <typename T>
30 using single_char_finder = traits::integral_constant<(utility::utf8::count(T::get()) == 1)>;
31 
32 template <typename Strings>
33 struct mapping_fn {
34  template <typename Mapping>
35  using fn = typename Mapping::template type<Strings>;
36 };
37 
38 template <typename U, typename... I>
39 [[nodiscard]] constexpr auto tuple_builder(U&& input, [[maybe_unused]] std::tuple<I...> Is) noexcept
40 {
41  return std::tuple{std::get<I::value>(std::forward<U>(input))...};
42 }
43 } // namespace detail
44 
50 template <template <typename> typename Policy>
52 {
53  template <typename Strings>
54  struct inner {
55  using index = boost::mp11::mp_find_if<Strings, detail::multi_char_finder>;
56  using string_type = boost::mp11::mp_eval_if_c<index::value == std::tuple_size_v<Strings>,
57  void,
58  boost::mp11::mp_at,
59  Strings,
60  index>;
61  using type = boost::mp11::
62  mp_eval_if_c<std::is_void_v<string_type>, string_type, Policy, string_type>;
63  };
64 
65 public:
67  template <typename Strings>
68  using type = typename inner<Strings>::type;
69 };
70 
76 template <template <typename> typename Policy>
78 {
79  template <typename Strings>
80  struct inner {
81  constexpr static std::size_t first_index =
82  boost::mp11::mp_find_if<Strings, detail::multi_char_finder>::value;
83  using dropped_first_strings =
84  boost::mp11::mp_eval_if_c<first_index == std::tuple_size_v<Strings>,
85  std::tuple<>,
86  boost::mp11::mp_drop,
87  Strings,
89 
90  using index = boost::mp11::mp_find_if<dropped_first_strings, detail::multi_char_finder>;
91  using string_type =
92  boost::mp11::mp_eval_if_c<index::value == std::tuple_size_v<dropped_first_strings>,
93  void,
94  boost::mp11::mp_at,
95  dropped_first_strings,
96  index>;
97  using type = boost::mp11::
98  mp_eval_if_c<std::is_void_v<string_type>, string_type, Policy, string_type>;
99  };
100 
101 public:
103  template <typename Strings>
104  using type = typename inner<Strings>::type;
105 };
106 
112 template <template <typename> typename Policy>
114 {
115  template <typename Strings>
116  struct inner {
117  using index = boost::mp11::mp_find_if<Strings, detail::single_char_finder>;
118  using string_type = boost::mp11::mp_eval_if_c<index::value == std::tuple_size_v<Strings>,
119  void,
120  boost::mp11::mp_at,
121  Strings,
122  index>;
123  using type = boost::mp11::
124  mp_eval_if_c<std::is_void_v<string_type>, string_type, Policy, string_type>;
125  };
126 
127 public:
129  template <typename Strings>
130  using type = typename inner<Strings>::type;
131 };
132 
138 template <template <typename> typename Policy>
140 {
141  template <typename Strings>
142  struct inner {
143  using string_type = boost::mp11::
144  mp_eval_if_c<(std::tuple_size_v<Strings> < 1), void, boost::mp11::mp_first, Strings>;
145  using type = boost::mp11::
146  mp_eval_if_c<std::is_void_v<string_type>, string_type, Policy, string_type>;
147  };
148 
149 public:
151  template <typename Strings>
152  using type = typename inner<Strings>::type;
153 };
154 
160 template <template <typename> typename Policy>
162 {
163  template <typename Strings>
164  struct inner {
165  using string_type = boost::mp11::
166  mp_eval_if_c<(std::tuple_size_v<Strings> < 2), void, boost::mp11::mp_second, Strings>;
167  using type = boost::mp11::
168  mp_eval_if_c<std::is_void_v<string_type>, string_type, Policy, string_type>;
169  };
170 
171 public:
173  template <typename Strings>
174  using type = typename inner<Strings>::type;
175 };
176 
185 template <typename... Mappings, typename... Params>
186 [[nodiscard]] constexpr auto convert(Params&&... params) noexcept
187 {
188  // Zip together an index-sequence of ParamTuple and the elements of it
189  using zipped = algorithm::zip_t<boost::mp11::mp_iota_c<sizeof...(Params)>,
190  std::tuple<std::decay_t<Params>...>>;
191 
192  // Get a tuple of the indices of things that are not strings
193  using not_string_indices = typename algorithm::unzip<
194  boost::mp11::mp_filter_q<boost::mp11::mp_not_fn<detail::string_finder>,
195  zipped>>::first_type;
196 
197  // Get a tuple of the string types. We don't use the indices here as the string content is a
198  // part of the type
199  using strings = typename algorithm::unzip<
200  boost::mp11::mp_filter<detail::string_finder, zipped>>::second_type;
201 
202  // Iterate over the mappings, and pass the strings to each. Any valid mapping will have a
203  // non-void type, use those to populate the new policies tuple
204  using mapped_tuple = boost::mp11::mp_remove_if<
205  boost::mp11::mp_transform_q<detail::mapping_fn<strings>, std::tuple<Mappings...>>,
206  std::is_void>;
207 
208  static_assert(std::tuple_size_v<strings> == std::tuple_size_v<mapped_tuple>,
209  "Unhandled bare strings passed");
210 
211  return std::tuple_cat(
212  mapped_tuple{},
213  detail::tuple_builder(std::tuple{std::forward<Params>(params)...}, not_string_indices{}));
214 }
215 } // namespace arg_router::utility::string_to_policy
typename zip< First, Second >::type zip_t
Definition: algorithm.hpp:158
std::integral_constant< decltype(Value), Value > integral_constant
Definition: traits.hpp:210
constexpr auto convert(Params &&... params) noexcept
constexpr std::size_t count(std::string_view str) noexcept
Definition: utf8.hpp:278