koutil
Loading...
Searching...
No Matches
subcommand.h
Go to the documentation of this file.
1#ifndef KOUTIL_ARGPARSER_SUBCOMMAND_H
2#define KOUTIL_ARGPARSER_SUBCOMMAND_H
3
5#include "koutil/type/types.h"
6#include <cassert>
7#include <concepts>
8#include <cstddef>
9#include <string_view>
10#include <tuple>
11#include <type_traits>
12
13namespace koutil::argparser {
14
15class CommandsBase;
16
21 std::string_view name;
22
23 constexpr SubcommandBase(std::string_view cmd_name)
24 : name(cmd_name) { }
25
26 constexpr virtual ~SubcommandBase() = default;
27
33 [[nodiscard]] constexpr virtual const ArgumentsBase& get_args() const = 0;
34
40 [[nodiscard]] constexpr virtual const CommandsBase& get_cmds() const = 0;
41
42 constexpr bool operator==(std::string_view n) const { return name == n; }
43};
44
50template <typename T>
51concept is_subcommand = requires(T t) {
52 std::is_base_of_v<SubcommandBase, T>;
53 requires std::same_as<std::decay_t<decltype(t.name)>, std::string_view>;
54};
55
61template <typename T>
62concept are_commands = std::is_base_of_v<CommandsBase, std::decay_t<T>>;
63
68public:
69 constexpr virtual ~CommandsBase() = default;
70
77 [[nodiscard]] constexpr virtual const SubcommandBase* find(std::string_view name) const = 0;
78
84 [[nodiscard]] constexpr virtual std::size_t size() const = 0;
85};
86
92template <is_subcommand... Cmd> class Commands : public CommandsBase {
93private:
94 static constexpr std::size_t count = sizeof...(Cmd);
96 = std::conditional_t<count != 1, std::tuple<Cmd...>, type::types_get_t<type::types<std::decay_t<Cmd>...>, 0>>;
97
98public:
99 constexpr Commands(const Cmd&... cmd)
100 requires(count != 1)
101 : m_cmds(std::tuple<Cmd...>(cmd...)) {
102 assert(!contains_duplicate());
103 }
104
110 [[nodiscard]] constexpr std::size_t size() const override { return count; }
111
118 [[nodiscard]] constexpr const SubcommandBase* find(std::string_view name) const override {
119
120 if constexpr (count == 1) {
121 return &m_cmds;
122 } else if constexpr (count == 0) {
123 return nullptr;
124 } else {
125 return find_impl<0>(name);
126 }
127 }
128
129private:
131
137 [[nodiscard]] constexpr bool contains_duplicate() const {
138 if constexpr (count <= 1) {
139 return false;
140 }
142 }
143
150 template <std::size_t I, std::size_t J>
151 requires(I < count && J < count)
152 [[nodiscard]] constexpr bool contains_duplicate_impl() const {
153 const auto& cmd = std::get<I>(m_cmds);
154 const auto& other = std::get<J>(m_cmds);
155
156 if (cmd.name == other.name) {
157 return true;
158 }
159
160 if constexpr (J + 1 >= count) {
162 } else {
164 }
165 }
166
167 template <std::size_t I, std::size_t J>
168 requires(I >= count || J >= count)
169 [[nodiscard]] constexpr bool contains_duplicate_impl() const {
170 return false;
171 }
172
180 template <std::size_t I> [[nodiscard]] constexpr const SubcommandBase* find_impl(std::string_view name) const {
181 if constexpr (I >= count) {
182 return nullptr;
183 } else {
184
185 const auto& cmd = std::get<I>(m_cmds);
186
187 if (cmd.name == name) {
188 return &cmd;
189 } else {
190 return find_impl<I + 1>(name);
191 }
192 }
193 }
194};
195
201template <is_subcommand Cmd> class Commands<Cmd> : public CommandsBase {
202public:
203 constexpr Commands(const Cmd& cmd)
204 : m_cmd(cmd) { }
205
206 [[nodiscard]] constexpr const SubcommandBase* find(std::string_view name) const override {
207 if (m_cmd.name == name) {
208 return &m_cmd;
209 } else {
210 return nullptr;
211 }
212 }
213
214 [[nodiscard]] constexpr std::size_t size() const override { return 1; }
215
216private:
217 Cmd m_cmd;
218};
219
226template <typename Args, typename Cmd> struct Subcommand;
227
234template <is_arg... Args, is_subcommand... Cmd>
235struct Subcommand<type::types<Args...>, type::types<Cmd...>> : public SubcommandBase {
236
237 Arguments<Args...> args;
238 Commands<Cmd...> cmds;
239
247 constexpr Subcommand(
248 std::string_view cmd_name, const Arguments<Args...>& arguments, const Commands<Cmd...>& commands
249 )
250 : SubcommandBase(cmd_name)
251 , args(arguments)
252 , cmds(commands) { }
253
259 [[nodiscard]] constexpr const ArgumentsBase& get_args() const override { return args; }
260
266 [[nodiscard]] constexpr const CommandsBase& get_cmds() const override { return cmds; }
267};
268
279template <is_arg... Args, is_subcommand... Cmds>
280constexpr auto make_subcommand(
281 std::string_view name,
282 const Arguments<Args...>& args = Arguments<> {},
283 const Commands<Cmds...>& cmds = Commands<> {}
284) {
285 return Subcommand<type::types<Args...>, type::types<Cmds...>>(name, args, cmds);
286}
287
288}
289
290#endif
Base class for argument collections.
Definition arg.h:135
Base class for commands.
Definition subcommand.h:67
virtual constexpr const SubcommandBase * find(std::string_view name) const =0
Finds a subcommand by name.
virtual constexpr std::size_t size() const =0
Gets the number of subcommands.
virtual constexpr ~CommandsBase()=default
Cmd m_cmd
Definition subcommand.h:217
constexpr Commands(const Cmd &cmd)
Definition subcommand.h:203
constexpr std::size_t size() const override
Gets the number of subcommands.
Definition subcommand.h:214
constexpr const SubcommandBase * find(std::string_view name) const override
Finds a subcommand by name.
Definition subcommand.h:206
Collection of subcommands.
Definition subcommand.h:92
constexpr const SubcommandBase * find_impl(std::string_view name) const
Finds a subcommand by name recursively.
Definition subcommand.h:179
std::conditional_t< count !=1, std::tuple< Cmd... >, type::types_get_t< type::types< std::decay_t< Cmd >... >, 0 > > storage_t
Definition subcommand.h:95
constexpr bool contains_duplicate_impl() const
Checks for duplicate subcommand names recursively.*.
Definition subcommand.h:151
constexpr bool contains_duplicate() const
Checks for duplicate subcommand names.
Definition subcommand.h:136
constexpr std::size_t size() const override
Gets the number of subcommands.
Definition subcommand.h:109
static constexpr std::size_t count
Definition subcommand.h:94
storage_t m_cmds
Definition subcommand.h:129
constexpr const SubcommandBase * find(std::string_view name) const override
Finds a subcommand by name.
Definition subcommand.h:117
constexpr Commands(const Cmd &... cmd)
Definition subcommand.h:98
Concept to check if a type satisfies the requirements of a collection of commands.
Definition subcommand.h:62
Checks if a type is Arg.
Definition arg.h:24
Concept to check if a type satisfies the requirements of a subcommand.
Definition subcommand.h:51
Definition arg.h:13
constexpr auto make_subcommand(std::string_view name, const Arguments< Args... > &args=Arguments<> {}, const Commands< Cmds... > &cmds=Commands<> {})
Helper function to create a subcommand.
Definition subcommand.h:280
detail::types_get_impl< Types, I >::type types_get_t
Alias for getting a type by index in a types list.
Definition types.h:381
Base class for subcommands.
Definition subcommand.h:20
virtual constexpr const ArgumentsBase & get_args() const =0
Gets the arguments of the subcommand.
constexpr SubcommandBase(std::string_view cmd_name)
Definition subcommand.h:23
virtual constexpr ~SubcommandBase()=default
virtual constexpr const CommandsBase & get_cmds() const =0
Gets the commands of the subcommand.
std::string_view name
Definition subcommand.h:21
constexpr bool operator==(std::string_view n) const
Definition subcommand.h:42
constexpr const CommandsBase & get_cmds() const override
Gets the commands of the subcommand.
Definition subcommand.h:266
constexpr Subcommand(std::string_view cmd_name, const Arguments< Args... > &arguments, const Commands< Cmd... > &commands)
Constructs a Subcommand object with the given name, arguments, and subcommands.
Definition subcommand.h:247
constexpr const ArgumentsBase & get_args() const override
Gets the arguments of the subcommand.
Definition subcommand.h:259
Subcommand template struct.
Definition subcommand.h:226
A structure representing a variadic list of types.
Definition types.h:20