diff --git a/.clang-format b/.clang-format index 20865fd..c9ad570 100644 --- a/.clang-format +++ b/.clang-format @@ -1,12 +1,12 @@ --- -Language: Cpp -BasedOnStyle: LLVM -UseTab: Always -TabWidth: 4 -IndentWidth: 4 +Language: Cpp +BasedOnStyle: LLVM +UseTab: Always +TabWidth: 4 +IndentWidth: 4 NamespaceIndentation: All AccessModifierOffset: -4 BreakBeforeBraces: Attach -AllowShortFunctionsOnASingleLine: Empty -ColumnLimit: 120 +AllowShortFunctionsOnASingleLine: Empty +ColumnLimit: 180 ... diff --git a/src/headers/parser/argument_builder.hpp b/src/headers/parser/argument_builder.hpp index 6a6ccd7..79c1cf8 100644 --- a/src/headers/parser/argument_builder.hpp +++ b/src/headers/parser/argument_builder.hpp @@ -15,16 +15,7 @@ namespace argument_parser::builder { namespace builder_mask { using v2_flag = argument_parser::v2::add_argument_flags; using mask_type = std::uint64_t; - enum class value_mode { - unresolved, - store, - flag, - reference, - accumulate, - count, - action_no_param, - action_with_param - }; + enum class value_mode { unresolved, store, flag, reference, accumulate, count, action_no_param, action_with_param }; enum class extra_capability : unsigned { Store = static_cast(v2_flag::Reference) + 1, Flag }; @@ -45,15 +36,13 @@ namespace argument_parser::builder { constexpr mask_type required = bit(v2_flag::Required); constexpr mask_type reference = bit(v2_flag::Reference); constexpr mask_type accumulate = bit(v2_flag::Accumulate); - constexpr mask_type count = bit( - static_cast(static_cast(v2_flag::Accumulate) + (static_cast(extra_capability::Store) | - static_cast(extra_capability::Flag)))); + constexpr mask_type count = + bit(static_cast(static_cast(v2_flag::Accumulate) + (static_cast(extra_capability::Store) | static_cast(extra_capability::Flag)))); constexpr mask_type store = bit(extra_capability::Store); constexpr mask_type flag = bit(extra_capability::Flag); constexpr mask_type value_mode_group = action | reference | accumulate | count | store | flag; - constexpr mask_type initial = short_argument | long_argument | positional | help_text | action | required | - reference | accumulate | count | store | flag; + constexpr mask_type initial = short_argument | long_argument | positional | help_text | action | required | reference | accumulate | count | store | flag; constexpr mask_type storable_mode_group = (count | store | flag | accumulate | reference) >> 1; @@ -125,50 +114,34 @@ namespace argument_parser::builder { return {}; } - template = 0> + template = 0> auto short_argument(std::string short_name) const - -> argument { - using next_argument = - argument; + -> argument { + using next_argument = argument; next_argument next{*this}; next.m_short_argument = std::move(short_name); return next; } - template = 0> + template = 0> auto long_argument(std::string long_name) const - -> argument { - using next_argument = - argument; + -> argument { + using next_argument = argument; next_argument next{*this}; next.m_long_argument = std::move(long_name); return next; } - template = 0> + template = 0> auto positional(std::string positional_name) const - -> argument argument { using next_argument = argument; @@ -177,10 +150,8 @@ namespace argument_parser::builder { return next; } - template = 0> - auto position(int index) const - -> argument { + template = 0> + auto position(int index) const -> argument { using next_argument = argument; next_argument next{*this}; @@ -188,10 +159,8 @@ namespace argument_parser::builder { return next; } - template = 0> - auto help_text(std::string help) const - -> argument { + template = 0> + auto help_text(std::string help) const -> argument { using next_argument = argument; next_argument next{*this}; @@ -199,10 +168,8 @@ namespace argument_parser::builder { return next; } - template = 0> - auto required(bool value = true) const - -> argument { + template = 0> + auto required(bool value = true) const -> argument { using next_argument = argument; next_argument next{*this}; @@ -210,11 +177,9 @@ namespace argument_parser::builder { return next; } - template = 0> + template = 0> auto store() const -> argument { - static_assert(!std::is_same_v, - "store() is not supported. Use flag() for boolean-style arguments."); + static_assert(!std::is_same_v, "store() is not supported. Use flag() for boolean-style arguments."); using next_argument = argument; next_argument next{*this}; @@ -222,31 +187,21 @@ namespace argument_parser::builder { return next; } - template = 0> - auto accumulate() const -> argument> { + template = 0> + auto accumulate() const -> argument> { using vector_type = std::vector; - using next_argument = argument; + using next_argument = argument; next_argument next{*this}; next.m_value_mode = value_mode::accumulate; return next; } - template = 0, typename T> - auto accumulate(T &value) const -> argument< - builder_mask::replace(current_mask, builder_mask::value_mode_group, builder_mask::storable_mode_group), T> { - static_assert(argument_parser::v2::deducers::is_vector_v, - "accumulate(target) requires a std::vector target."); + template = 0, typename T> + auto accumulate(T &value) const -> argument { + static_assert(argument_parser::v2::deducers::is_vector_v, "accumulate(target) requires a std::vector target."); - using next_argument = argument; + using next_argument = argument; next_argument next{*this}; next.m_reference = std::addressof(value); @@ -254,29 +209,19 @@ namespace argument_parser::builder { return next; } - template = 0> - auto count() const -> argument { - using next_argument = argument; + template = 0> + auto count() const -> argument { + using next_argument = argument; next_argument next{*this}; next.m_value_mode = value_mode::count; return next; } - template = 0> - auto count(int &value) const -> argument { + template = 0> + auto count(int &value) const -> argument { - using next_argument = argument; + using next_argument = argument; next_argument next{*this}; next.m_reference = std::addressof(value); @@ -284,27 +229,18 @@ namespace argument_parser::builder { return next; } - template = 0> - auto flag() const -> argument { - using next_argument = argument; + template = 0> + auto flag() const -> argument { + using next_argument = argument; next_argument next{*this}; next.m_value_mode = value_mode::flag; return next; } - template = 0, typename T> - auto reference(T &value) const -> argument< - builder_mask::replace(current_mask, builder_mask::value_mode_group, builder_mask::storable_mode_group), T> { - using next_argument = argument; + template = 0, typename T> + auto reference(T &value) const -> argument { + using next_argument = argument; next_argument next{*this}; next.m_reference = std::addressof(value); @@ -312,34 +248,26 @@ namespace argument_parser::builder { return next; } - template = 0, typename Callable> - auto action(Callable &&handler) const -> std::enable_if_t< - std::is_invocable_r_v, - argument> { - using next_argument = - argument; + template = 0, typename Callable> + auto action(Callable &&handler) const + -> std::enable_if_t, argument> { + using next_argument = argument; next_argument next{*this}; - next.m_action = std::make_shared( - std::function(std::forward(handler))); + next.m_action = std::make_shared(std::function(std::forward(handler))); next.m_value_mode = value_mode::action_no_param; return next; } - template = 0, typename Callable> + template = 0, typename Callable> auto action(Callable &&handler) const - -> std::enable_if_t, - argument> { - static_assert(!std::is_same_v, - "action(...) is not supported. Use action([] { ... }) instead."); + -> std::enable_if_t, argument> { + static_assert(!std::is_same_v, "action(...) is not supported. Use action([] { ... }) instead."); using next_argument = argument; next_argument next{*this}; - next.m_action = std::make_shared>( - std::function(std::forward(handler))); + next.m_action = std::make_shared>(std::function(std::forward(handler))); next.m_value_mode = value_mode::action_with_param; return next; } @@ -392,8 +320,7 @@ namespace argument_parser::builder { throw std::logic_error("The builder reached build() without a supported terminal value mode."); } - template = 0> + template = 0> auto build_and_get(argument_parser::v2::base_parser &parser) const -> container { assert_has_identifier(); switch (m_value_mode) { @@ -428,9 +355,8 @@ namespace argument_parser::builder { template argument(argument const &other) - : m_short_argument(other.m_short_argument), m_long_argument(other.m_long_argument), - m_positional_name(other.m_positional_name), m_position(other.m_position), m_help_text(other.m_help_text), - m_required(other.m_required), m_action(other.m_action), m_reference(copy_reference(other.m_reference)), + : m_short_argument(other.m_short_argument), m_long_argument(other.m_long_argument), m_positional_name(other.m_positional_name), m_position(other.m_position), + m_help_text(other.m_help_text), m_required(other.m_required), m_action(other.m_action), m_reference(copy_reference(other.m_reference)), m_value_mode(other.m_value_mode) {} template using typed_map = std::unordered_map>; @@ -536,8 +462,7 @@ namespace argument_parser::builder { } auto build_action_with_param(argument_parser::v2::base_parser &parser) const -> void { - auto const *typed_action = - dynamic_cast const *>(m_action.get()); + auto const *typed_action = dynamic_cast const *>(m_action.get()); if (typed_action == nullptr) { throw std::logic_error("Stored action is not compatible with the requested parameter type."); } @@ -554,8 +479,7 @@ namespace argument_parser::builder { } if (is_positional()) { - auto wrapped_action = argument_parser::helpers::make_action( - [action = *nonparametered_action](std::string const &) { action.invoke(); }); + auto wrapped_action = argument_parser::helpers::make_action([action = *nonparametered_action](std::string const &) { action.invoke(); }); auto pairs = make_typed_pairs(); pairs[argument_parser::v2::flags::Action] = wrapped_action; parser.template add_argument(pairs); @@ -592,88 +516,6 @@ namespace argument_parser::builder { return argument<>::start(); } - namespace assertions { - struct noop_handler { - void operator()() const {} - }; - - template struct parameter_sink { - void operator()(T const &) const {} - }; - - template struct can_use_help_text : std::false_type {}; - - template - struct can_use_help_text().help_text(std::declval()))>> - : std::true_type {}; - - template struct can_use_position : std::false_type {}; - - template - struct can_use_position().position(0))>> : std::true_type {}; - - template struct can_use_nonparametered_action : std::false_type {}; - - template - struct can_use_nonparametered_action().action(noop_handler{}))>> - : std::true_type {}; - - template struct can_use_parametered_action : std::false_type {}; - - template - struct can_use_parametered_action< - T, U, std::void_t().template action(parameter_sink{}))>> : std::true_type {}; - - template struct can_use_store : std::false_type {}; - - template - struct can_use_store().template store())>> : std::true_type {}; - - template struct can_use_flag : std::false_type {}; - - template - struct can_use_flag().flag())>> : std::true_type {}; - - template struct can_use_reference : std::false_type {}; - - template - struct can_use_reference().reference(std::declval()))>> - : std::true_type {}; - - using after_help_text = decltype(argument<>::start().help_text("help")); - static_assert(!can_use_help_text::value, "help_text() should be single-use."); - - using after_positional = decltype(argument<>::start().positional("path")); - static_assert(can_use_position::value, "positional() should unlock position()."); - - using after_position = decltype(argument<>::start().positional("path").position(0)); - static_assert(!can_use_position::value, "position() should be single-use."); - - using after_positional_mode_selection = decltype(argument<>::start().positional("path").store<>()); - static_assert(!can_use_flag::value, - "flag() should not be available for positional arguments."); - - using after_nonparametered_action = - decltype(argument<>::start().short_argument("v").help_text("verbose").action(noop_handler{})); - static_assert(!can_use_nonparametered_action::value, - "action() should not remain callable after selecting a non-parametered action."); - static_assert(!can_use_parametered_action::value, - "typed action() should also be disabled after selecting a non-parametered action."); - static_assert(!can_use_store::value, - "store() should be mutually exclusive with action()."); - static_assert(!can_use_flag::value, - "flag() should be mutually exclusive with action()."); - static_assert(!can_use_reference::value, - "reference() should be mutually exclusive with action()."); - - using after_parametered_action = - decltype(argument<>::start().positional("count").position(0).action(parameter_sink{})); - static_assert(!can_use_nonparametered_action::value, - "non-parametered action() should be disabled after selecting a typed action."); - static_assert(!can_use_parametered_action::value, - "typed action() should be single-use regardless of the parameter type."); - - } // namespace assertions } // namespace argument_parser::builder #endif diff --git a/src/source/parser/argument_builder.cpp b/src/source/parser/argument_builder.cpp new file mode 100644 index 0000000..ef8af28 --- /dev/null +++ b/src/source/parser/argument_builder.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +namespace argument_parser::builder { + namespace assertions { + struct noop_handler { + void operator()() const {} + }; + + template struct parameter_sink { + void operator()(T const &) const {} + }; + + template struct can_use_help_text : std::false_type {}; + + template struct can_use_help_text().help_text(std::declval()))>> : std::true_type {}; + + template struct can_use_position : std::false_type {}; + + template struct can_use_position().position(0))>> : std::true_type {}; + + template struct can_use_nonparametered_action : std::false_type {}; + + template struct can_use_nonparametered_action().action(noop_handler{}))>> : std::true_type {}; + + template struct can_use_parametered_action : std::false_type {}; + + template + struct can_use_parametered_action().template action(parameter_sink{}))>> : std::true_type {}; + + template struct can_use_store : std::false_type {}; + + template struct can_use_store().template store())>> : std::true_type {}; + + template struct can_use_flag : std::false_type {}; + + template struct can_use_flag().flag())>> : std::true_type {}; + + template struct can_use_reference : std::false_type {}; + + template struct can_use_reference().reference(std::declval()))>> : std::true_type {}; + + using after_help_text = decltype(argument<>::start().help_text("help")); + static_assert(!can_use_help_text::value, "help_text() should be single-use."); + + using after_positional = decltype(argument<>::start().positional("path")); + static_assert(can_use_position::value, "positional() should unlock position()."); + + using after_position = decltype(argument<>::start().positional("path").position(0)); + static_assert(!can_use_position::value, "position() should be single-use."); + + using after_positional_mode_selection = decltype(argument<>::start().positional("path").store<>()); + static_assert(!can_use_flag::value, "flag() should not be available for positional arguments."); + + using after_nonparametered_action = decltype(argument<>::start().short_argument("v").help_text("verbose").action(noop_handler{})); + static_assert(!can_use_nonparametered_action::value, "action() should not remain callable after selecting a non-parametered action."); + static_assert(!can_use_parametered_action::value, "typed action() should also be disabled after selecting a non-parametered action."); + static_assert(!can_use_store::value, "store() should be mutually exclusive with action()."); + static_assert(!can_use_flag::value, "flag() should be mutually exclusive with action()."); + static_assert(!can_use_reference::value, "reference() should be mutually exclusive with action()."); + + using after_parametered_action = decltype(argument<>::start().positional("count").position(0).action(parameter_sink{})); + static_assert(!can_use_nonparametered_action::value, "non-parametered action() should be disabled after selecting a typed action."); + static_assert(!can_use_parametered_action::value, "typed action() should be single-use regardless of the parameter type."); + + } // namespace assertions +} // namespace argument_parser::builder