arg_router  1.4.0
C++ command line argument parsing and routing
short_form_expander.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/parsing/parse_target.hpp"
8 #include "arg_router/parsing/parsing.hpp"
9 #include "arg_router/policy/policy.hpp"
10 #include "arg_router/traits.hpp"
11 #include "arg_router/utility/compile_time_optional.hpp"
12 #include "arg_router/utility/utf8.hpp"
13 
14 namespace arg_router::policy
15 {
23 template <typename = void> // This is needed due so it can be used in
24 class short_form_expander_t // template template parameters
25 {
26 public:
28  constexpr static auto priority = std::size_t{900};
29 
48  template <typename ProcessedTarget, typename... Parents>
51  [[maybe_unused]] utility::compile_time_optional<ProcessedTarget> processed_target,
52  [[maybe_unused]] parsing::parse_target& target,
53  [[maybe_unused]] const Parents&... parents) const
54  {
55  static_assert(sizeof...(Parents) > 0,
56  "Short-form expansion policy requires at least one parent");
57  using owner_type = boost::mp11::mp_first<std::tuple<Parents...>>;
58 
59  static_assert(traits::has_short_name_method_v<owner_type>,
60  "Short-form expansion support requires a short name policy");
61 
62  static_assert(utility::utf8::count(owner_type::short_name()) == 1,
63  "Short name must only be 1 character");
64 
65  // Parents is always greater than zero, but having it in this statement causes it to only be
66  // evaluated upon template instantiation - otherwise it would fail even if the class is
67  // never used
68  static_assert((sizeof...(Parents) > 0) && (config::short_prefix != config::long_prefix),
69  "Short and long prefixes cannot be the same");
70 
71  if (tokens.empty()) {
73  }
74 
75  auto first = tokens.begin();
76  auto first_token = *first;
77  if (first_token.prefix == parsing::prefix_type::none) {
78  // The token has _probably_ not been processed yet, so try to convert to short form
79  const auto& owner = algorithm::pack_element<0>(parents...);
80  const auto tt = parsing::get_token_type(owner, first_token.name);
81  if (tt.prefix != parsing::prefix_type::short_) {
83  }
84 
85  first_token = tt;
86  } else if (first_token.prefix == parsing::prefix_type::long_) {
88  }
89 
90  // Exit early if there's no expansion to be done
91  if (first_token.name.size() == owner_type::short_name().size()) {
93  }
94 
95  // Move the token to the processed container
96  tokens.transfer(first);
97 
98  // Insert the extra flags at the front of the unprocessed section, so they will be processed
99  // independently
100  tokens.unprocessed().reserve(tokens.unprocessed().size() + first_token.name.size() - 1);
101  auto it = tokens.unprocessed().begin();
102 
103  // Skip past the first grapheme cluster as we'll re-use the existing short form token for
104  // that
105  for (auto gc_it = ++utility::utf8::iterator{first_token.name};
106  gc_it != utility::utf8::iterator{};
107  ++gc_it, ++it) {
108  it = tokens.unprocessed().insert(it, {parsing::prefix_type::short_, *gc_it});
109  }
110 
111  // Shrink the first to a single grapheme cluster
112  first.set({parsing::prefix_type::short_, *utility::utf8::iterator{first_token.name}});
113 
115  }
116 };
117 
120 
121 template <>
122 struct is_policy<short_form_expander_t<>> : std::true_type {
123 };
124 } // namespace arg_router::policy
parsing::pre_parse_result pre_parse_phase(parsing::dynamic_token_adapter &tokens, [[maybe_unused]] utility::compile_time_optional< ProcessedTarget > processed_target, [[maybe_unused]] parsing::parse_target &target, [[maybe_unused]] const Parents &... parents) const
constexpr auto short_prefix
Definition: config.hpp:58
constexpr auto long_prefix
Definition: config.hpp:52
token_type get_token_type(std::string_view token)
Definition: token_type.hpp:103
constexpr auto short_form_expander
constexpr std::size_t count(std::string_view str) noexcept
Definition: utf8.hpp:278