2929#include < fmt/format.h>
3030// IWYU pragma: no_include <ext/alloc_traits.h>
3131#include < stdlib.h>
32+ #include < algorithm>
3233#include < chrono>
3334#include < limits>
3435#include < sstream> // IWYU pragma: keep
3536#include < thread>
37+ #include < type_traits>
3638#include < unordered_set>
3739#include < utility>
3840
41+ #include " gutil/map_util.h"
42+
3943namespace dsn {
4044
4145std::unique_ptr<command_deregister>
@@ -44,19 +48,19 @@ command_manager::register_command(const std::vector<std::string> &commands,
4448 const std::string &args,
4549 command_handler handler)
4650{
47- auto *c = new command_instance ();
48- c ->commands = commands;
49- c ->help = help;
50- c ->args = args;
51- c ->handler = std::move (handler);
51+ auto ch = std::make_shared<commands_handler> ();
52+ ch ->commands = commands;
53+ ch ->help = help;
54+ ch ->args = args;
55+ ch ->handler = std::move (handler);
5256
5357 utils::auto_write_lock l (_lock);
5458 for (const auto &cmd : commands) {
5559 CHECK (!cmd.empty (), " should not register empty command" );
56- CHECK (_handlers. emplace (cmd, c). second , " command '{}' already registered " , cmd );
60+ gutil::InsertOrDie (&_handler_by_cmd, cmd, ch );
5761 }
5862
59- return std::make_unique<command_deregister>(reinterpret_cast <uintptr_t >(c ));
63+ return std::make_unique<command_deregister>(reinterpret_cast <uintptr_t >(ch. get () ));
6064}
6165
6266std::unique_ptr<command_deregister> command_manager::register_bool_command (
@@ -94,35 +98,39 @@ command_manager::register_multiple_commands(const std::vector<std::string> &comm
9498 handler);
9599}
96100
97- void command_manager::deregister_command (uintptr_t handle )
101+ void command_manager::deregister_command (uintptr_t cmd_id )
98102{
99- auto c = reinterpret_cast <command_instance *>(handle );
100- CHECK_NOTNULL (c , " cannot deregister a null handle " );
103+ const auto ch = reinterpret_cast <commands_handler *>(cmd_id );
104+ CHECK_NOTNULL (ch , " cannot deregister a null command id " );
101105 utils::auto_write_lock l (_lock);
102- for (const std::string &cmd : c ->commands ) {
103- _handlers .erase (cmd);
106+ for (const auto &cmd : ch ->commands ) {
107+ _handler_by_cmd .erase (cmd);
104108 }
105109}
106110
111+ void command_manager::add_global_cmd (std::unique_ptr<command_deregister> cmd)
112+ {
113+ utils::auto_write_lock l (_lock);
114+ _cmds.push_back (std::move (cmd));
115+ }
116+
107117bool command_manager::run_command (const std::string &cmd,
108118 const std::vector<std::string> &args,
109119 /* out*/ std::string &output)
110120{
111- command_instance *h = nullptr ;
121+ std::shared_ptr<commands_handler> ch ;
112122 {
113123 utils::auto_read_lock l (_lock);
114- auto it = _handlers.find (cmd);
115- if (it != _handlers.end ())
116- h = it->second ;
124+ ch = gutil::FindPtrOrNull (_handler_by_cmd, cmd);
117125 }
118126
119- if (h == nullptr ) {
120- output = std::string (" unknown command '" ) + cmd + " ' " ;
127+ if (!ch ) {
128+ output = fmt::format (" unknown command '{}' " , cmd) ;
121129 return false ;
122- } else {
123- output = h->handler (args);
124- return true ;
125130 }
131+
132+ output = ch->handler (args);
133+ return true ;
126134}
127135
128136std::string command_manager::set_bool (bool &value,
@@ -159,36 +167,34 @@ std::string command_manager::set_bool(bool &value,
159167
160168command_manager::command_manager ()
161169{
162- _cmds.emplace_back (
163- register_multiple_commands ({" help" , " h" , " H" , " Help" },
164- " Display help information" ,
165- " [command]" ,
166- [this ](const std::vector<std::string> &args) {
167- std::stringstream ss;
168- if (args.empty ()) {
169- std::unordered_set<command_instance *> cmds;
170- utils::auto_read_lock l (_lock);
171- for (const auto &c : this ->_handlers ) {
172- // Multiple commands with the same handler are print
173- // only once.
174- if (cmds.insert (c.second .get ()).second ) {
175- ss << c.second ->help << std::endl;
176- }
177- }
178- } else {
179- utils::auto_read_lock l (_lock);
180- auto it = _handlers.find (args[0 ]);
181- if (it == _handlers.end ()) {
182- ss << " cannot find command '" << args[0 ] << " '" ;
183- } else {
184- ss.width (6 );
185- ss << std::left << it->second ->help << std::endl
186- << it->second ->args << std::endl;
187- }
188- }
189-
190- return ss.str ();
191- }));
170+ _cmds.emplace_back (register_multiple_commands (
171+ {" help" , " h" , " H" , " Help" },
172+ " Display help information" ,
173+ " [command]" ,
174+ [this ](const std::vector<std::string> &args) {
175+ std::stringstream ss;
176+ if (args.empty ()) {
177+ std::unordered_set<commands_handler *> chs;
178+ utils::auto_read_lock l (_lock);
179+ for (const auto &[_, ch] : _handler_by_cmd) {
180+ // Multiple commands with the same handler are print only once.
181+ if (gutil::InsertIfNotPresent (&chs, ch.get ())) {
182+ ss << ch->help << std::endl;
183+ }
184+ }
185+ } else {
186+ utils::auto_read_lock l (_lock);
187+ const auto ch = gutil::FindPtrOrNull (_handler_by_cmd, args[0 ]);
188+ if (!ch) {
189+ ss << " cannot find command '" << args[0 ] << " '" ;
190+ } else {
191+ ss.width (6 );
192+ ss << std::left << ch->help << std::endl << ch->args << std::endl;
193+ }
194+ }
195+
196+ return ss.str ();
197+ }));
192198
193199 _cmds.emplace_back (register_multiple_commands (
194200 {" repeat" , " r" , " R" , " Repeat" },
@@ -241,10 +247,10 @@ command_manager::command_manager()
241247command_manager::~command_manager ()
242248{
243249 _cmds.clear ();
244- CHECK (_handlers .empty (),
250+ CHECK (_handler_by_cmd .empty (),
245251 " All commands must be deregistered before command_manager is destroyed, however '{}' is "
246252 " still registered" ,
247- _handlers .begin ()->first );
253+ _handler_by_cmd .begin ()->first );
248254}
249255
250256} // namespace dsn
0 commit comments