arg_router  1.4.0
C++ command line argument parsing and routing
counting_flag.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/policy/description.hpp"
8 #include "arg_router/policy/long_name.hpp"
9 #include "arg_router/policy/min_max_count.hpp"
10 #include "arg_router/policy/multi_stage_value.hpp"
11 #include "arg_router/policy/short_form_expander.hpp"
12 #include "arg_router/policy/short_name.hpp"
13 #include "arg_router/tree_node.hpp"
14 #include "arg_router/utility/string_to_policy.hpp"
15 
16 namespace arg_router
17 {
29 template <typename T, typename... Policies>
31  public tree_node<policy::multi_stage_value<T, bool>,
32  policy::min_max_count_t<traits::integral_constant<std::size_t{0}>,
33  traits::integral_constant<std::size_t{0}>>,
34  std::decay_t<Policies>...>
35 {
36  static_assert(policy::is_all_policies_v<std::tuple<std::decay_t<Policies>...>>,
37  "Counting flags must only contain policies (not other nodes)");
38  static_assert(traits::has_long_name_method_v<counting_flag_t> ||
39  traits::has_short_name_method_v<counting_flag_t>,
40  "Counting flag must have a long and/or short name policy");
41  static_assert(!traits::has_display_name_method_v<counting_flag_t>,
42  "Counting flag must not have a display name policy");
43  static_assert(!traits::has_none_name_method_v<counting_flag_t>,
44  "Counting flag must not have a none name policy");
45  static_assert(traits::supports_static_cast_conversion_v<T, std::size_t>,
46  "T must be explicitly convertible to std::size_t");
47 
48  using parent_type =
51  traits::integral_constant<std::size_t{0}>>,
52  std::decay_t<Policies>...>;
53 
54 public:
55  using typename parent_type::policies_type;
56 
58  using value_type = T;
59 
61  template <bool Flatten>
62  using help_data_type = typename parent_type::template default_leaf_help_data_type<Flatten>;
63 
68  constexpr explicit counting_flag_t(Policies... policies) noexcept :
71  traits::integral_constant<std::size_t{0}>>{},
72  std::move(policies)...}
73  {
74  }
75 
76  template <typename Validator, bool HasTarget, typename... Parents>
77  [[nodiscard]] std::optional<parsing::parse_target> pre_parse(
78  parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
79  const Parents&... parents) const
80 
81  {
82  return parent_type::pre_parse(pre_parse_data, *this, parents...);
83  }
84 
92  template <typename... Parents>
93  bool parse([[maybe_unused]] parsing::parse_target&& target,
94  [[maybe_unused]] const Parents&... parents) const noexcept
95  {
96  // Presence of the flag yields a constant true. Validation is done by the parent mode as it
97  // carries the final result
98  return true;
99  }
100 
101 private:
102  static_assert(!parent_type::template any_phases_v<value_type,
105  "Counting flag does not support policies with parse or routing phases "
106  "(e.g. custom_parser)");
107 
108  // Value will always be true
109  constexpr static void merge_impl(std::optional<value_type>& result, bool /*value*/) noexcept
110  {
111  if (!result) {
112  result = static_cast<value_type>(1);
113  return;
114  }
115 
116  *result = static_cast<value_type>(static_cast<std::size_t>(*result) + 1);
117  }
118 };
119 
143 template <typename T, typename... Policies>
144 [[nodiscard]] constexpr auto counting_flag(Policies... policies) noexcept
145 {
146  return std::apply(
147  [](auto... converted_policies) {
148  // Add the short-form expander if one of the policies implements the short name method,
149  // and if the short and long prefix are not the same
150  constexpr auto has_short_name =
151  boost::mp11::mp_any_of<std::tuple<std::decay_t<decltype(converted_policies)>...>,
153  if constexpr ((config::long_prefix != config::short_prefix) && has_short_name) {
154  return counting_flag_t<T,
156  std::decay_t<decltype(converted_policies)>...>{
158  std::move(converted_policies)...};
159  } else {
160  return counting_flag_t<T, std::decay_t<decltype(converted_policies)>...>{
161  std::move(converted_policies)...};
162  }
163  },
168  std::move(policies)...));
169 }
170 } // namespace arg_router
bool parse([[maybe_unused]] parsing::parse_target &&target, [[maybe_unused]] const Parents &... parents) const noexcept
typename parent_type::template default_leaf_help_data_type< Flatten > help_data_type
constexpr counting_flag_t(Policies... policies) noexcept
std::optional< parsing::parse_target > pre_parse(parsing::pre_parse_data< Validator, HasTarget > pre_parse_data, const Node &node, const Parents &... parents) const
Definition: tree_node.hpp:465
constexpr auto short_prefix
Definition: config.hpp:58
constexpr auto long_prefix
Definition: config.hpp:52
constexpr auto short_form_expander
constexpr auto is_all_policies_v
Definition: policy.hpp:53
std::integral_constant< decltype(Value), Value > integral_constant
Definition: traits.hpp:210
constexpr auto convert(Params &&... params) noexcept
constexpr auto counting_flag(Policies... policies) noexcept