7 #include "arg_router/algorithm.hpp"
9 #include "arg_router/list.hpp"
10 #include "arg_router/parsing/global_parser.hpp"
11 #include "arg_router/parsing/parsing.hpp"
12 #include "arg_router/parsing/pre_parse_data.hpp"
13 #include "arg_router/policy/min_max_count.hpp"
14 #include "arg_router/policy/policy.hpp"
16 #include "arg_router/utility/tuple_iterator.hpp"
24 template <
typename... Params>
27 boost::mp11::mp_filter<policy::is_policy, std::tuple<std::decay_t<Params>...>>>
29 template <
typename LHS,
typename RHS>
30 struct priority_order {
32 struct get_priority_or_default {
33 constexpr
static std::size_t value = []() {
34 if constexpr (policy::has_priority_v<T>) {
42 constexpr
static auto value =
43 get_priority_or_default<LHS>::value > get_priority_or_default<RHS>::value;
51 using policies_type = boost::mp11::mp_filter<policy::is_policy, parameters_type>;
59 std::decay_t<decltype(
list_expander(std::declval<std::decay_t<Params>>()...))>>;
62 (std::tuple_size_v<children_type> + std::tuple_size_v<policies_type>) ==
64 std::decay_t<decltype(
list_expander(std::declval<std::decay_t<Params>>()...))>>,
65 "tree_node constructor can only accept other tree_nodes and policies");
68 constexpr
static auto is_named = traits::has_short_name_method_v<tree_node> ||
69 traits::has_long_name_method_v<tree_node> ||
70 traits::has_none_name_method_v<tree_node>;
77 template <
template <
typename...>
typename PolicyChecker,
typename... Args>
79 using finder = boost::mp11::mp_bind<PolicyChecker, boost::mp11::_1, Args...>;
83 boost::mp11::mp_eval_if_c<boost::mp11::mp_find_if_q<policies_type, finder>::value ==
84 std::tuple_size_v<policies_type>,
88 boost::mp11::mp_find_if_q<policies_type, finder>>;
96 template <
template <
typename...>
typename PolicyChecker,
typename... Args>
110 template <
typename ValueType,
template <
typename...>
typename... PolicyCheckers>
113 template <
template <
typename...>
typename PolicyChecker>
115 constexpr
static bool value = []() {
117 if constexpr (std::tuple_size_v<policies_type> == 0) {
119 }
else if constexpr (boost::mp11::mp_valid<PolicyChecker,
120 boost::mp11::mp_first<policies_type>,
122 return !std::is_void_v<phase_finder_t<PolicyChecker, ValueType>>;
124 return !std::is_void_v<phase_finder_t<PolicyChecker>>;
130 constexpr
static bool value = boost::mp11::mp_any_of<std::tuple<checker<PolicyCheckers>...>,
131 boost::mp11::mp_to_bool>::value;
141 template <
typename ValueType,
template <
typename...>
typename... PolicyCheckers>
162 template <
bool Flatten>
165 template <
typename Child>
166 using child_help_getter =
typename Child::template help_data_type<Flatten>;
168 template <
typename Child>
169 using child_help = boost::mp11::
170 mp_eval_if_c<!traits::has_help_data_type_v<Child>, void, child_help_getter, Child>;
172 constexpr
static auto num_policies = std::tuple_size_v<policies_type>;
179 constexpr
auto has_min_value = traits::has_minimum_value_method_v<tree_node>;
180 constexpr
auto has_max_value = traits::has_maximum_value_method_v<tree_node>;
182 if constexpr (has_min_value || has_max_value) {
186 constexpr
auto min_value = [](
auto* type_ptr) {
187 using node_type = std::remove_pointer_t<decltype(type_ptr)>;
189 if constexpr (has_min_value) {
190 constexpr
auto value = node_type::minimum_value();
198 std::decay_t<decltype(node_type::maximum_value())>>;
199 if constexpr (std::is_unsigned_v<max_value_type>) {
200 return AR_STRING(
"0"){};
202 return AR_STRING(
"-N"){};
207 constexpr
auto max_value = [](
auto* type_ptr) {
208 using node_type = std::remove_pointer_t<decltype(type_ptr)>;
210 if constexpr (has_max_value) {
211 constexpr
auto value = node_type::maximum_value();
215 return AR_STRING(
"N"){};
219 return AR_STRING(
"<"){} + min_value + AR_STRING(
"-"){} + max_value +
222 return AR_STRING(
""){};
231 [[maybe_unused]] constexpr
bool fixed_count_of_one = []() {
232 if constexpr (traits::has_minimum_count_method_v<tree_node> &&
233 traits::has_maximum_count_method_v<tree_node>) {
234 return (tree_node::minimum_count() == tree_node::maximum_count()) &&
235 (tree_node::minimum_count() == 1);
241 [[maybe_unused]] constexpr
auto value_str = []() {
243 if constexpr (std::is_same_v<std::decay_t<decltype(min_max_str)>, AR_STRING(
"")>) {
244 return AR_STRING(
"<Value>"){};
250 [[maybe_unused]] constexpr
auto has_separator =
251 boost::mp11::mp_find_if<policies_type, traits::has_value_separator_method>::value !=
254 if constexpr (has_separator) {
255 return AR_STRING_SV(tree_node::value_separator()){} + value_str;
256 }
else if constexpr (fixed_count_of_one) {
257 return AR_STRING(
" "){} + value_str;
259 return AR_STRING(
""){};
268 [[maybe_unused]] constexpr
auto has_long_name =
269 boost::mp11::mp_find_if<policies_type, traits::has_long_name_method>::value !=
271 [[maybe_unused]] constexpr
auto has_short_name =
272 boost::mp11::mp_find_if<policies_type, traits::has_short_name_method>::value !=
274 [[maybe_unused]] constexpr
auto has_none_name =
275 boost::mp11::mp_find_if<policies_type, traits::has_none_name_method>::value !=
278 if constexpr (has_long_name && has_short_name) {
280 AR_STRING_SV(tree_node::long_name()){} + AR_STRING(
","){} +
283 }
else if constexpr (has_long_name) {
286 }
else if constexpr (has_short_name) {
289 }
else if constexpr (has_none_name) {
292 return AR_STRING(
""){};
300 [[maybe_unused]] constexpr
auto has_description =
301 boost::mp11::mp_find_if<policies_type, traits::has_description_method>::value !=
304 if constexpr (has_description) {
305 return AR_STRING_SV(tree_node::description()){};
307 return AR_STRING(
""){};
315 [[maybe_unused]] constexpr
bool fixed_count = []() {
316 if constexpr (traits::has_minimum_count_method_v<tree_node> &&
317 traits::has_maximum_count_method_v<tree_node>) {
318 return tree_node::minimum_count() == tree_node::maximum_count();
324 constexpr
auto prefix = AR_STRING(
"["){};
326 if constexpr (fixed_count) {
330 constexpr
auto min_count = []() {
331 if constexpr (traits::has_minimum_count_method_v<tree_node>) {
334 return AR_STRING(
"0"){};
338 constexpr
auto max_count = []() {
339 if constexpr (traits::has_maximum_count_method_v<tree_node>) {
340 if constexpr (tree_node::maximum_count() ==
341 decltype(policy::min_count<0>)::maximum_count()) {
342 return AR_STRING(
"N"){};
347 return AR_STRING(
"N"){};
351 return prefix + min_count + AR_STRING(
","){} + max_count + AR_STRING(
"]"){};
370 template <
typename OwnerNode,
typename FilterFn>
376 [&](
auto,
auto& child) {
377 using child_type = std::decay_t<decltype(child)>;
378 if constexpr (traits::has_help_data_type_v<child_type>) {
379 using child_help_data_type =
380 typename child_type::template help_data_type<Flatten>;
382 static_assert(child_help_data_type::description::get().find(
'\t') ==
383 std::string_view::npos,
384 "Help descriptions cannot contain tabs");
389 child_help_data_type>) {
390 child_result = child_help_data_type::runtime_children(child, f);
397 child_help_data_type::description::get(),
398 std::move(child_result)});
408 boost::mp11::mp_remove_if<boost::mp11::mp_transform<child_help, children_type>,
435 constexpr
explicit tree_node(Params... params) noexcept :
437 children_(common_filter_tuple<is_tree_node>(
list_expander(std::move(params)...)))
464 template <
typename Validator,
bool HasTarget,
typename Node,
typename... Parents>
465 [[nodiscard]] std::optional<parsing::parse_target>
pre_parse(
468 const Parents&... parents)
const
471 [&](
auto&&... ancestors) {
return pre_parse_impl(pre_parse_data, ancestors.get()...); },
487 template <
typename ValueType,
typename Node,
typename... Parents>
488 [[nodiscard]]
auto parse(std::string_view token,
490 const Parents&... parents)
const
493 [&](
auto&&... ancestors) {
return parse_impl<ValueType>(token, ancestors.get()...); },
498 static_assert((boost::mp11::mp_count_if_q<
500 typename phase_finder<policy::has_routing_phase_method>::finder>::value <=
502 "Only zero or one policies supporting a routing phase is supported");
504 template <
template <
typename...>
typename Fn,
typename... ExpandedParams>
505 [[nodiscard]] constexpr
static auto common_filter(ExpandedParams&... expanded_params) noexcept
508 using ref_tuple = std::tuple<std::reference_wrapper<ExpandedParams>...>;
512 boost::mp11::mp_bind<Fn, boost::mp11::mp_bind<traits::get_type, boost::mp11::_1>>;
516 auto ref_result = algorithm::tuple_filter_and_construct<ref_fn::template fn>(
517 ref_tuple{expanded_params...});
519 using ref_result_t = std::decay_t<decltype(ref_result)>;
520 using result_t = boost::mp11::mp_transform<traits::get_type, ref_result_t>;
523 return result_t{std::move(ref_result)};
526 template <
template <
typename...>
typename Fn,
typename Tuple>
527 [[nodiscard]] constexpr
static auto common_filter_tuple(Tuple&& tuple_params) noexcept
531 [](
auto&... args) {
return common_filter<Fn>(std::forward<decltype(args)>(args)...); },
535 template <
typename Val
idator,
bool HasTarget>
536 [[nodiscard]] constexpr
auto extract_parent_target(
537 [[maybe_unused]] parsing::pre_parse_data<Validator, HasTarget> pre_parse_data)
540 if constexpr (HasTarget) {
541 return utility::compile_time_optional{std::cref(pre_parse_data.target())};
543 return utility::compile_time_optional{};
547 template <
typename Validator,
bool HasTarget,
typename Node,
typename... Parents>
548 [[nodiscard]] std::optional<parsing::parse_target> pre_parse_impl(
549 parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
551 const Parents&... parents)
const
553 auto result = vector<parsing::token_type>{};
554 auto tmp_args = pre_parse_data.args();
555 auto adapter = parsing::dynamic_token_adapter{result, tmp_args};
558 auto target = parsing::parse_target{node, parents...};
561 utility::tuple_type_iterator<priority_ordered_policies_type>([&](
auto i) {
562 using policy_type = std::tuple_element_t<i, priority_ordered_policies_type>;
563 if constexpr (policy::has_pre_parse_phase_method_v<policy_type>) {
569 const auto use_subs =
571 match = this->policy_type::pre_parse_phase(adapter,
572 extract_parent_target(pre_parse_data),
594 if (result.empty()) {
595 if (tmp_args.empty()) {
598 result.push_back(tmp_args.front());
599 tmp_args.erase(tmp_args.begin());
603 auto& first_token = result.front();
609 if (!parsing::match<tree_node>(first_token)) {
616 if (!pre_parse_data.validator()(node, parents...)) {
621 match.throw_exception();
624 pre_parse_data.args() = tmp_args;
628 if (!result.empty()) {
629 result.erase(result.begin());
632 target.tokens(std::move(result));
637 template <
typename ValueType,
typename... Parents>
638 [[nodiscard]]
auto parse_impl(std::string_view token,
const Parents&... parents)
const
640 using finder_type = phase_finder<policy::has_parse_phase_method, ValueType>;
641 using policy_type =
typename finder_type::type;
643 #ifdef MSVC_1936_WORKAROUND
645 (boost::mp11::mp_count_if<policies_type, finder_type::finder::fn>::value <= 1),
646 "Only zero or one policies supporting a parse phase is supported");
648 (boost::mp11::mp_count_if<
650 phase_finder<policy::has_missing_phase_method, ValueType>::finder::fn>::value <=
652 "Only zero or one policies supporting a missing phase is "
656 (boost::mp11::mp_count_if_q<policies_type, typename finder_type::finder>::value <= 1),
657 "Only zero or one policies supporting a parse phase is supported");
660 typename phase_finder<policy::has_missing_phase_method,
661 ValueType>::finder>::value <= 1),
662 "Only zero or one policies supporting a missing phase is "
666 if constexpr (std::is_void_v<policy_type>) {
667 return parser<ValueType>::parse(token);
669 return this->policy_type::template parse_phase<ValueType>(token, parents...);
constexpr static auto label_generator() noexcept
constexpr static auto description_generator() noexcept
constexpr static auto count_suffix() noexcept
std::decay_t< decltype(description_generator())> description
static vector< runtime_help_data > runtime_children(const OwnerNode &owner, FilterFn &&f)
std::decay_t< decltype(label_generator())> label
boost::mp11::mp_remove_if< boost::mp11::mp_transform< child_help, children_type >, std::is_void > all_children_help
constexpr static auto value_suffix() noexcept
constexpr static auto value_separator_suffix()
constexpr static auto is_named
boost::mp11::mp_sort< policies_type, priority_order > priority_ordered_policies_type
constexpr static bool any_phases_v
std::tuple< std::decay_t< Params >... > parameters_type
typename phase_finder< PolicyChecker, Args... >::type phase_finder_t
constexpr tree_node(Params... params) noexcept
boost::mp11::mp_filter< is_tree_node, std::decay_t< decltype(list_expander(std::declval< std::decay_t< Params > >()...))> > children_type
constexpr const children_type & children() const noexcept
auto parse(std::string_view token, const Node &node, const Parents &... parents) const
boost::mp11::mp_filter< policy::is_policy, parameters_type > policies_type
children_type & children() noexcept
std::optional< parsing::parse_target > pre_parse(parsing::pre_parse_data< Validator, HasTarget > pre_parse_data, const Node &node, const Parents &... parents) const
constexpr auto short_prefix
constexpr auto long_prefix
@ skip_node_but_use_sub_targets
token_type get_token_type(std::string_view token)
utility::result< pre_parse_action, multi_lang_exception > pre_parse_result
constexpr bool match(token_type token) noexcept
constexpr auto clean_node_ancestry_list(const BaseNode &base_node, const DerivedAndParents &... derived_and_parents)
constexpr bool has_runtime_children_method_v
typename underlying_type< T >::type underlying_type_t
typename convert_integral_to_cts< Value >::type convert_integral_to_cts_t
constexpr std::enable_if_t< traits::is_tuple_like_v< std::decay_t< Tuple > > > tuple_iterator(F &&f, Tuple &&tuple)
std::vector< T, config::allocator< T > > vector
constexpr auto list_expander(Params... params) noexcept
boost::mp11::mp_eval_if_c< boost::mp11::mp_find_if_q< policies_type, finder >::value==std::tuple_size_v< policies_type >, void, boost::mp11::mp_at, policies_type, boost::mp11::mp_find_if_q< policies_type, finder > > type