7 #include "arg_router/arg.hpp"
8 #include "arg_router/counting_flag.hpp"
9 #include "arg_router/dependency/alias_group.hpp"
10 #include "arg_router/dependency/one_of.hpp"
11 #include "arg_router/flag.hpp"
12 #include "arg_router/forwarding_arg.hpp"
13 #include "arg_router/help.hpp"
14 #include "arg_router/mode.hpp"
15 #include "arg_router/multi_arg.hpp"
16 #include "arg_router/policy/alias.hpp"
17 #include "arg_router/policy/default_value.hpp"
18 #include "arg_router/policy/dependent.hpp"
19 #include "arg_router/policy/display_name.hpp"
20 #include "arg_router/policy/long_name.hpp"
21 #include "arg_router/policy/none_name.hpp"
22 #include "arg_router/policy/required.hpp"
23 #include "arg_router/policy/router.hpp"
24 #include "arg_router/policy/runtime_enable.hpp"
25 #include "arg_router/policy/short_form_expander.hpp"
26 #include "arg_router/policy/short_name.hpp"
27 #include "arg_router/positional_arg.hpp"
28 #include "arg_router/root.hpp"
29 #include "arg_router/utility/tree_recursor.hpp"
37 template <
typename... Rules>
41 template <
typename... Rules>
42 struct is_policy<validation::validator<Rules...>> : std::true_type {
73 template <
template <
typename...>
typename T,
typename... Conditions>
74 using rule = std::tuple<boost::mp11::mp_quote<T>, Conditions...>;
95 template <
typename T,
typename... Conditions>
96 using rule_q = std::tuple<T, Conditions...>;
105 template <
typename... Rules>
113 template <
typename Current>
115 template <
typename Rule>
117 constexpr
static bool value = boost::mp11::mp_first<Rule>::template fn<Current>::value;
122 template <
typename Current,
typename... Parents>
123 constexpr
static void fn() noexcept
126 #ifdef MSVC_1936_WORKAROUND
127 constexpr
auto rule_index = boost::mp11::mp_find_if<
129 rule_lookup<Current>::fn>::value;
131 constexpr
auto rule_index = boost::mp11::mp_find_if_q<
133 rule_lookup<Current>>::value;
135 static_assert(rule_index != std::tuple_size_v<rules_type>,
"No rule for Current");
139 boost::mp11::mp_drop_c<std::tuple_element_t<rule_index, rules_type>, 1>;
140 utility::tuple_type_iterator<conditions>([](
auto i) {
141 using condition = std::tuple_element_t<i, conditions>;
142 condition::template check<Current, Parents...>();
153 template <
typename Root>
156 utility::tree_type_recursor<validate_fn, Root>();
162 namespace common_rules
169 template <
template <
typename...>
typename... T>
171 static_assert((
sizeof...(T) > 0),
"Must be at least one despecialised type");
173 template <
typename Current>
175 constexpr
static bool value =
176 boost::mp11::mp_or<traits::is_specialisation_of<Current, T>...>::value;
184 template <
typename T,
typename... Parents>
185 constexpr
static void check() noexcept
187 if constexpr (
sizeof...(Parents) > 0) {
188 using Owner = boost::mp11::mp_first<std::tuple<Parents...>>;
191 static_assert(algorithm::count_despecialised_v<T, typename Owner::policies_type> == 1,
192 "Policy must be present and unique in owner");
202 template <
template <
typename...>
typename... ModeTypes>
204 static_assert(
sizeof...(ModeTypes),
"Must be at least one mode type");
206 template <
typename Policy,
typename PathToThis>
208 template <
typename Current,
typename... Parents>
209 constexpr
static void fn() noexcept
211 using path_type = std::tuple<Parents...>;
214 if constexpr (!std::is_same_v<PathToThis, path_type>) {
215 static_assert(!std::is_same_v<Policy, Current>,
216 "Policy must be unique in the parse tree up to "
217 "the nearest mode or root");
222 template <
typename T>
224 boost::mp11::mp_any_of<std::tuple<traits::is_specialisation_of<T, ModeTypes>...>,
225 boost::mp11::mp_to_bool>;
228 template <
typename StartType>
230 template <
typename Current,
typename...>
231 [[nodiscard]] constexpr
static bool fn() noexcept
234 if constexpr (std::is_same_v<StartType, Current>) {
237 return is_mode<Current>::value;
242 template <
typename T,
typename... Parents>
243 constexpr
static void check() noexcept
245 using ParentTuple = std::tuple<Parents...>;
246 constexpr
auto NumParents =
sizeof...(Parents);
249 if constexpr (NumParents > 1) {
252 constexpr
auto mode_index = boost::mp11::mp_find_if<ParentTuple, is_mode>::value;
255 boost::mp11::mp_take_c<ParentTuple, std::min(mode_index + 1, NumParents)>;
256 using start_type = boost::mp11::mp_back<path_type>;
260 utility::tree_type_recursor<checker<T, path_type>, skipper<start_type>, start_type>();
270 template <std::size_t Index,
template <
typename...>
typename ParentType>
273 constexpr
static std::size_t
index = Index;
279 template <
typename T>
290 template <
typename... ParentIndexTypes>
292 static_assert(
sizeof...(ParentIndexTypes) > 0,
"Must be at least one parent_index_pair_type");
294 template <std::
size_t MaxIndex>
295 struct index_filter {
296 template <
typename Pair>
297 using fn = boost::mp11::mp_bool<(Pair::index < MaxIndex)>;
300 template <
typename... Parents>
302 template <
typename Pair>
304 typename Pair::template fn<std::tuple_element_t<Pair::index, std::tuple<Parents...>>>;
307 template <
typename T,
typename... Parents>
308 constexpr
static void check() noexcept
311 using clamped_indices = boost::mp11::mp_filter_q<index_filter<
sizeof...(Parents)>,
312 std::tuple<ParentIndexTypes...>>;
315 using matches = boost::mp11::mp_transform_q<checker<Parents...>, clamped_indices>;
317 static_assert(boost::mp11::mp_any_of<matches, boost::mp11::mp_to_bool>::value,
318 "Parent must be one of a set of types");
326 template <
template <
typename...>
typename... Policies>
328 template <
typename T>
329 using checker = boost::mp11::mp_all_of<
330 std::tuple<algorithm::has_specialisation<Policies, typename T::policies_type>...>,
331 boost::mp11::mp_to_bool>;
333 template <
typename T,
typename...>
334 constexpr
static void check() noexcept
336 static_assert(checker<T>::value,
"T must have all these policies");
344 template <
template <
typename...>
typename... Policies>
346 template <
typename T>
347 using checker = boost::mp11::mp_none_of<
348 std::tuple<algorithm::has_specialisation<Policies, typename T::policies_type>...>,
349 boost::mp11::mp_to_bool>;
351 template <
typename T,
typename...>
352 constexpr
static void check() noexcept
354 static_assert(checker<T>::value,
"T must have none of these policies");
358 template <
template <
typename...>
typename Policy>
359 struct basic_child_must_have_policy {
360 template <
typename Child>
363 template <
typename T>
364 constexpr
static bool value =
365 boost::mp11::mp_all_of<typename T::children_type, child_checker>::value;
372 template <
template <
typename...>
typename Policy>
374 template <
typename T,
typename...>
375 constexpr
static void check() noexcept
377 static_assert(basic_child_must_have_policy<Policy>::template value<T>,
378 "All children of T must have this policy");
386 template <
template <
typename...>
typename Policy>
388 template <
typename T,
typename...>
389 constexpr
static void check() noexcept
391 if constexpr ((std::tuple_size_v<typename T::children_type>) > 0) {
392 static_assert(!basic_child_must_have_policy<Policy>::template value<T>,
393 "All children of T must not have this policy");
400 template <
template <
typename...>
typename Policy>
402 template <
typename T,
typename... Parents>
403 constexpr
static void check() noexcept
405 static_assert(policy::is_policy_v<T>,
"T must be a policy");
406 static_assert(
sizeof...(Parents) >= 1,
"Must be at least one parent");
408 using parent = boost::mp11::mp_first<std::tuple<Parents...>>;
409 static_assert(!algorithm::has_specialisation_v<Policy, typename parent::policies_type>,
410 "Parent must not have this policy");
419 template <
template <
typename...>
typename... ModeTypes>
421 static_assert(
sizeof...(ModeTypes),
"Must be at least one mode type");
423 template <
typename T>
425 boost::mp11::mp_any_of<std::tuple<traits::is_specialisation_of<T, ModeTypes>...>,
426 boost::mp11::mp_to_bool>;
428 template <
typename T>
429 struct is_anonymous_mode {
430 constexpr
static auto value = []() {
431 if constexpr (is_mode<T>::value) {
432 return T::is_anonymous;
438 template <
typename T,
typename...>
439 constexpr
static void check() noexcept
441 constexpr
auto num_anonymous = boost::mp11::mp_count_if<
442 typename T::children_type,
443 is_anonymous_mode>::value;
445 static_assert((num_anonymous <= 1),
"Only one child mode can be anonymous");
453 template <
template <
typename...>
typename... Policies>
455 static_assert(
sizeof...(Policies) >= 2,
"Condition requires at least two policies");
457 template <
typename T,
typename...>
458 constexpr
static void check() noexcept
461 (algorithm::count_specialisation_v<Policies, typename T::policies_type> + ...) >= 1,
462 "T must have at least one of the policies");
471 template <
template <
typename...>
typename... NodeTypes>
473 static_assert(
sizeof...(NodeTypes),
"Must be at least one node type");
475 template <
typename T>
476 using is_target_node =
477 boost::mp11::mp_any_of<std::tuple<traits::is_specialisation_of<T, NodeTypes>...>,
478 boost::mp11::mp_to_bool>;
480 template <
typename T,
typename...>
481 constexpr
static void check() noexcept
488 using children_type =
typename T::children_type;
489 using is_target_node_map = boost::mp11::mp_transform_q<
490 boost::mp11::mp_bind<boost::mp11::mp_to_bool,
491 boost::mp11::mp_bind<is_target_node, boost::mp11::_1>>,
495 constexpr
auto first_node_index =
496 boost::mp11::mp_find<is_target_node_map, boost::mp11::mp_true>::value;
497 if constexpr (first_node_index != std::tuple_size_v<is_target_node_map>) {
498 using drop_before_first = boost::mp11::mp_drop_c<is_target_node_map, first_node_index>;
499 static_assert(boost::mp11::mp_all_of<drop_before_first, boost::mp11::mp_to_bool>::value,
500 "Node types must all appear at the end of child list for a node");
510 template <
template <
typename...>
typename... ModeTypes>
512 static_assert(
sizeof...(ModeTypes),
"Must be at least one mode type");
514 template <
typename T>
516 boost::mp11::mp_any_of<std::tuple<traits::is_specialisation_of<T, ModeTypes>...>,
517 boost::mp11::mp_to_bool>;
519 template <
typename T>
520 struct is_anonymous_mode {
521 constexpr
static auto value = []() {
522 if constexpr (is_mode<T>::value) {
523 return T::is_anonymous;
529 template <
typename T,
typename...>
530 constexpr
static void check() noexcept
532 constexpr
auto has_anonymous_mode_child =
533 boost::mp11::mp_any_of<typename T::children_type, is_anonymous_mode>::value;
535 if constexpr (has_anonymous_mode_child) {
548 template <
typename T>
549 struct is_list_like_node {
550 static constexpr
bool value = []() {
551 if constexpr (traits::has_minimum_count_method_v<T> &&
552 traits::has_maximum_count_method_v<T>) {
553 return (T::minimum_count() != T::maximum_count()) &&
554 !policy::has_multi_stage_value_v<T> &&
555 !traits::has_token_end_marker_method_v<T>;
562 template <
typename T,
typename...>
563 constexpr
static void check() noexcept
565 using children_type =
typename T::children_type;
566 constexpr
auto count = boost::mp11::mp_count_if<children_type, is_list_like_node>::value;
567 static_assert(count <= 1,
"There can only be one variable length list-like child");
569 if constexpr (count == 1) {
570 constexpr
auto index = boost::mp11::mp_find_if<children_type, is_list_like_node>::value;
571 static_assert(index == (std::tuple_size_v<children_type> - 1),
572 "Variable length list-like child must be at end of children");
585 template <
typename T,
typename...>
586 constexpr
static void check() noexcept
588 if constexpr (policy::is_required_v<T> && traits::has_minimum_count_method_v<T>) {
590 T::minimum_count() >= 1,
591 "T must have a minimum count of at least 1 if required (it improves help output)");
598 template <
typename RuleTuple>
599 struct validator_from_tuple_impl {
600 static_assert(traits::always_false_v<RuleTuple>,
"RuleTuple must be a tuple-like type");
603 template <
template <
typename...>
typename Tuple,
typename... Rules>
604 struct validator_from_tuple_impl<Tuple<Rules...>> {
605 using type = validator<Rules...>;
613 template <
typename RuleTuple>
708 policy::runtime_enable_required,
728 policy::runtime_enable_required>,
constexpr static void validate() noexcept
std::tuple< Rules... > rules_type
constexpr auto default_validator
std::tuple< T, Conditions... > rule_q
typename detail::validator_from_tuple_impl< RuleTuple >::type validator_from_tuple
std::tuple< boost::mp11::mp_quote< T >, Conditions... > rule
constexpr static std::size_t index