arg_router  1.4.0
C++ command line argument parsing and routing
multi_arg_base.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/policy/min_max_count.hpp"
8 #include "arg_router/tree_node.hpp"
9 
10 namespace arg_router
11 {
24 template <typename T, std::size_t MinCount, typename... Policies>
25 class multi_arg_base_t : public add_missing_min_max_policy<MinCount, Policies...>::type
26 {
27  static_assert(policy::is_all_policies_v<std::tuple<std::decay_t<Policies>...>>,
28  "Arg must only contain policies (not other nodes)");
29 
30  using parent_type = typename add_missing_min_max_policy<MinCount, Policies...>::type;
31 
32  template <std::size_t N>
33  constexpr static bool has_fixed_count = []() {
34  return (parent_type::minimum_count() == N) && (parent_type::maximum_count() == N);
35  }();
36 
37  static_assert(!has_fixed_count<0>, "Cannot have a fixed count of zero");
38  static_assert(has_fixed_count<1> || traits::has_push_back_method_v<T>,
39  "value_type must have a push_back() method");
40 
41  static_assert(traits::has_long_name_method_v<multi_arg_base_t> ||
42  traits::has_short_name_method_v<multi_arg_base_t> ||
43  traits::has_none_name_method_v<multi_arg_base_t> ||
44  traits::has_display_name_method_v<multi_arg_base_t>,
45  "Arg must be named");
46 
47 protected:
48  using typename parent_type::policies_type;
49 
51  using value_type = T;
52 
54  template <bool Flatten>
55  using help_data_type = typename parent_type::template default_leaf_help_data_type<Flatten>;
56 
61  template <auto has_min_max = add_missing_min_max_policy<MinCount, Policies...>::has_min_max>
62  constexpr explicit multi_arg_base_t(Policies... policies,
63  // NOLINTNEXTLINE(*-named-parameter)
64  std::enable_if_t<has_min_max>* = nullptr) noexcept :
65  parent_type{std::move(policies)...}
66  {
67  }
68 
69  template <auto has_min_max = add_missing_min_max_policy<MinCount, Policies...>::has_min_max>
70  constexpr explicit multi_arg_base_t(Policies... policies,
71  // NOLINTNEXTLINE(*-named-parameter)
72  std::enable_if_t<!has_min_max>* = nullptr) noexcept :
73  parent_type{policy::min_max_count_t<
74  traits::integral_constant<MinCount>,
75  traits::integral_constant<std::numeric_limits<std::size_t>::max()>>{},
76  std::move(policies)...}
77  {
78  }
79 
80  template <typename Validator, bool HasTarget, typename... Parents>
81  [[nodiscard]] std::optional<parsing::parse_target> pre_parse(
82  parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
83  const Parents&... parents) const
84  {
85  return parent_type::pre_parse(pre_parse_data, *this, parents...);
86  }
87 
97  template <typename... Parents>
98  [[nodiscard]] value_type parse(parsing::parse_target target, const Parents&... parents) const
99  {
100  auto result = value_type{};
101  if constexpr (traits::has_push_back_method_v<value_type> &&
102  !traits::is_specialisation_of_v<value_type, std::basic_string> &&
103  !std::is_same_v<T, string>) {
104  for (auto token : target.tokens()) {
105  result.push_back(
106  parent_type::template parse<value_type>(token.name, *this, parents...));
107  }
108  } else if (!target.tokens().empty()) {
109  result = parent_type::template parse<value_type>(target.tokens().front().name,
110  *this,
111  parents...);
112  }
113 
114  // Validation
115  std::apply(
116  [&](auto&&... ancestors) {
117  utility::tuple_type_iterator<policies_type>([&](auto i) {
118  using policy_type = std::tuple_element_t<i, policies_type>;
119  if constexpr (policy::has_validation_phase_method_v<policy_type, value_type>) {
120  this->policy_type::validation_phase(result, ancestors.get()...);
121  }
122  });
123  },
124  parsing::clean_node_ancestry_list(*this, parents...));
125 
126  // Routing
127  using routing_policy =
128  typename parent_type::template phase_finder_t<policy::has_routing_phase_method>;
129  if constexpr (!std::is_void_v<routing_policy>) {
130  this->routing_policy::routing_phase(std::move(result));
131  }
132 
133  return result;
134  }
135 };
136 } // namespace arg_router
value_type parse(parsing::parse_target target, const Parents &... parents) const
constexpr multi_arg_base_t(Policies... policies, std::enable_if_t< has_min_max > *=nullptr) noexcept
typename parent_type::template default_leaf_help_data_type< Flatten > help_data_type
vector< token_type > & tokens() noexcept
constexpr auto clean_node_ancestry_list(const BaseNode &base_node, const DerivedAndParents &... derived_and_parents)
Definition: parsing.hpp:105
constexpr auto is_all_policies_v
Definition: policy.hpp:53