diff options
| -rw-r--r-- | nihil/command_map.cc | 66 | ||||
| -rw-r--r-- | nihil/command_map.ccm | 50 | ||||
| -rw-r--r-- | nihil/tests/command_map.cc | 2 |
3 files changed, 48 insertions, 70 deletions
diff --git a/nihil/command_map.cc b/nihil/command_map.cc index 1cc5081..fc31c87 100644 --- a/nihil/command_map.cc +++ b/nihil/command_map.cc @@ -29,19 +29,19 @@ namespace nihil { * typically from argv. */ -template<typename T> -struct string_tree_node final { - string_tree_node() +struct command_tree_node final { + command_tree_node() : _this_word("") { } - string_tree_node(std::string_view this_word) + command_tree_node(std::string_view this_word) : _this_word(this_word) { } - string_tree_node(std::string_view this_word, T value) + command_tree_node(std::string_view this_word, + command value) : _this_word(this_word) , _value(std::move(value)) { @@ -50,9 +50,9 @@ struct string_tree_node final { /* * Return a child node, or NULL if the child doesn't exist. */ - auto get_child(this string_tree_node const &self, + auto get_child(this command_tree_node const &self, std::string_view child) - -> string_tree_node const * + -> command_tree_node const * { if (auto it = self.children.find(std::string(child)); it != self.children.end()) @@ -61,9 +61,9 @@ struct string_tree_node final { return nullptr; } - auto get_child(this string_tree_node &self, + auto get_child(this command_tree_node &self, std::string_view child) - -> string_tree_node * + -> command_tree_node * { if (auto it = self.children.find(std::string(child)); it != self.children.end()) @@ -75,23 +75,23 @@ struct string_tree_node final { /* * Return a child node if it exists, or insert a new empty node. */ - auto get_or_create_child(this string_tree_node &self, + auto get_or_create_child(this command_tree_node &self, std::string_view child) - -> string_tree_node * + -> command_tree_node * { if (auto ptr = self.get_child(child); ptr != nullptr) return ptr; auto [it, ok] = self.children.emplace( - child, string_tree_node(child)); + child, command_tree_node(child)); return &it->second; } /* * Return this node's value. */ - auto value(this string_tree_node const &self) - -> std::optional<T> const & + auto value(this command_tree_node const &self) + -> std::optional<command> const & { return self._value; } @@ -99,25 +99,24 @@ struct string_tree_node final { /* * Set this node's value. */ - auto value(this string_tree_node &self, T value) -> void + auto value(this command_tree_node &self, command value) -> void { self._value = std::move(value); } private: std::string _this_word; - std::optional<T> _value; - std::unordered_map<std::string, string_tree_node> children; + std::optional<command> _value; + std::unordered_map<std::string, command_tree_node> children; }; -template<typename T> -struct string_tree { +struct command_tree { /* * Add a node to the tree. Returns false if the node already exists. */ - auto insert(this string_tree &self, + auto insert(this command_tree &self, std::ranges::range auto &&path, - T value) + command value) -> bool { auto *this_node = &self._root_node; @@ -142,9 +141,9 @@ struct string_tree { * Find a node in the tree. Unlike insert(), iteration stops when * we find any node with a value. */ - auto find(this string_tree const &self, + auto find(this command_tree const &self, std::ranges::range auto &&path) - -> std::optional<T> + -> std::optional<command> { auto *this_node = &self._root_node; {} @@ -166,44 +165,35 @@ struct string_tree { } private: - string_tree_node<T> _root_node; + command_tree_node _root_node; }; /* * The global command map. */ -auto get_commands() -> string_tree<command_base *> & { - static auto commands = string_tree<command_base *>(); +auto get_commands() -> command_tree & { + static auto commands = command_tree(); return commands; } -auto register_command(std::string_view path, command_base *cmd) noexcept - -> void +auto register_command(std::string_view path, command *cmd) noexcept -> void try { -{ auto &commands = get_commands(); - if (commands.insert(path | std::views::split(' '), cmd) == false) { + if (commands.insert(path | std::views::split(' '), *cmd) == false) { std::printf("command registration failed\n"); std::abort(); } -} } catch (...) { std::printf("command registration failed\n"); std::abort(); } - auto dispatch_command(int argc, char **argv) -> int { - if (argc == 0) { - std::print("not enough arguments\n"); - return 1; - } - auto &commands = get_commands(); auto node = commands.find(std::span(argv, argv + argc)); if (node) - return (**node).invoke(argc, argv); + return node->invoke(argc, argv); std::print("unknown command\n"); return 1; diff --git a/nihil/command_map.ccm b/nihil/command_map.ccm index 4e55211..5c60639 100644 --- a/nihil/command_map.ccm +++ b/nihil/command_map.ccm @@ -24,50 +24,38 @@ import :usage_error; namespace nihil { -struct command_base { - command_base(std::string_view path) - : _path(path) +/* + * A command that can be invoked. Instantiating a command adds this command + * to the global command table. If an error occurs, the program will abort. + */ +export struct command { + command(std::string_view path, std::string_view usage, auto &&fn) + : m_path(path) + , m_usage(usage) + , m_handler(std::forward<decltype(fn)>(fn)) { } - [[nodiscard]] auto path(this command_base const &self) - -> std::string_view + [[nodiscard]] auto path(this command const &self) -> std::string_view { - return self._path; + return self.m_path; } - [[nodiscard]] virtual auto invoke(int argc, char **argv) -> int = 0; + auto invoke(this command const &self, int argc, char **argv) -> int + { + return std::invoke(self.m_handler, argc, argv); + } private: - std::string_view _path; + std::string_view m_path; + std::string_view m_usage; + std::function<int (int, char **)> m_handler; }; /* * Register a command; used by command<>::command(). */ -auto register_command(std::string_view path, command_base *) noexcept -> void; - -/* - * A command that can be invoked. Instantiating a command adds this command - * to the global command table. If an error occurs, the program will abort. - */ -export template<typename Fn> -struct command final : command_base { - command(std::string_view path, Fn func) noexcept - : command_base(path) - , _func(func) - { - register_command(path, this); - } - - [[nodiscard]] auto invoke(int argc, char **argv) -> int final - { - return std::invoke(_func, argc, argv); - } - -private: - Fn _func; -}; +auto register_command(std::string_view path, command *) noexcept -> void; // The public API. export [[nodiscard]] auto dispatch_command(int argc, char **argv) -> int; diff --git a/nihil/tests/command_map.cc b/nihil/tests/command_map.cc index 4490396..de78be5 100644 --- a/nihil/tests/command_map.cc +++ b/nihil/tests/command_map.cc @@ -11,7 +11,7 @@ import nihil; namespace { auto cmd_sub1_called = false; -auto cmd_sub1 = nihil::command("cmd sub1", [](int, char **) -> int +auto cmd_sub1 = nihil::command("cmd sub1", "", [](int, char **) -> int { cmd_sub1_called = true; return 0; |
