From c8119a48a418adb468fb60dd671be5215763f405 Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Wed, 2 Aug 2017 16:34:51 -0500 Subject: [PATCH 1/3] Change Command to handle nullary actions. --- cmd/traffic_cache_tool/Command.cc | 63 +++++++++++++++++++++++-------- cmd/traffic_cache_tool/Command.h | 40 ++++++++++++++++---- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/cmd/traffic_cache_tool/Command.cc b/cmd/traffic_cache_tool/Command.cc index f4b64492ce4..4e1b1c54c5c 100644 --- a/cmd/traffic_cache_tool/Command.cc +++ b/cmd/traffic_cache_tool/Command.cc @@ -42,37 +42,65 @@ ERR_COMMAND_TAG_NOT_FOUND(char const *tag) return ts::Errata(s.str()); } -CommandTable::Command::Command() +CommandTable::Command::Command(std::string const &name, std::string const &help) : _name(name), _help(help) { } -CommandTable::Command::Command(std::string const &name, std::string const &help) : _name(name), _help(help) +CommandTable::Command::Command(std::string const &name, std::string const &help, Action const &f) + : _name(name), _help(help), _style(LEAF) { + _action._a = f; } -CommandTable::Command::Command(std::string const &name, std::string const &help, CommandFunction const &f) - : _name(name), _help(help), _func(f) +CommandTable::Command::Command(std::string const &name, std::string const &help, NullaryAction const &f) + : _name(name), _help(help), _style(NO_ARGS) { + _action._na = f; +} + +CommandTable::Command::Command(Command && that) : _name(std::move(that._name)), _help(std::move(that._help)), _style(that._style) { + switch (_style) { + case SUPER: break; + case NO_ARGS: _action._na = std::move(that._action._na); break; + case LEAF: _action._a = std::move(that._action._a); break; + } } +CommandTable::Command::~Command() { + switch (_style) { + case SUPER: break; + case NO_ARGS: _action._na.~NullaryAction(); break; + case LEAF: _action._a.~Action(); break; + } +} + +# if 0 auto CommandTable::Command::set(CommandFunction const &f) -> self & { _func = f; return *this; } +#endif + +CommandTable::Command & +CommandTable::Command::subCommand(std::string const &name, std::string const &help, Action const &f) +{ + _group.push_back(Command(name, help, f)); + return _group.back(); +} CommandTable::Command & -CommandTable::Command::subCommand(std::string const &name, std::string const &help, CommandFunction const &f) +CommandTable::Command::subCommand(std::string const &name, std::string const &help, NullaryAction const &f) { - _group.emplace_back(Command(name, help, f)); + _group.push_back(Command(name, help, f)); return _group.back(); } auto CommandTable::Command::subCommand(std::string const &name, std::string const &help) -> self & { - _group.emplace_back(Command(name, help)); + _group.push_back(Command(name, help)); return _group.back(); } @@ -81,10 +109,11 @@ CommandTable::Command::invoke(int argc, char *argv[]) { ts::Errata zret; - if (CommandTable::_opt_idx >= argc || argv[CommandTable::_opt_idx][0] == '-') { - // Tail of command keywords, try to invoke. - if (_func) { - zret = _func(argc - CommandTable::_opt_idx, argv + CommandTable::_opt_idx); + if (LEAF == _style) { + zret = _action._a(argc - CommandTable::_opt_idx, argv + CommandTable::_opt_idx); + } else if (CommandTable::_opt_idx >= argc || argv[CommandTable::_opt_idx][0] == '-') { + if (NO_ARGS == _style) { + zret = _action._na(); } else { std::ostringstream s; s << "Incomplete command, additional keyword required"; @@ -132,10 +161,6 @@ CommandTable::Command::helpMessage(int argc, char *argv[], std::ostream &out, st } } -CommandTable::Command::~Command() -{ -} - CommandTable::CommandTable() { } @@ -147,7 +172,13 @@ CommandTable::add(std::string const &name, std::string const &help) -> Command & } auto -CommandTable::add(std::string const &name, std::string const &help, CommandFunction const &f) -> Command & +CommandTable::add(std::string const &name, std::string const &help, Action const &f) -> Command & +{ + return _top.subCommand(name, help, f); +} + +auto +CommandTable::add(std::string const &name, std::string const &help, NullaryAction const &f) -> Command & { return _top.subCommand(name, help, f); } diff --git a/cmd/traffic_cache_tool/Command.h b/cmd/traffic_cache_tool/Command.h index bd9d08b17c9..1c52934796a 100644 --- a/cmd/traffic_cache_tool/Command.h +++ b/cmd/traffic_cache_tool/Command.h @@ -44,8 +44,10 @@ class CommandTable { typedef CommandTable self; ///< Self reference type. public: - /// Signature for actual command implementation. - typedef std::function CommandFunction; + /// Signature for a leaf command. + using Action = std::function; + /// Signature for a argumentless command. + using NullaryAction = std::function; CommandTable(); @@ -56,6 +58,7 @@ class CommandTable { typedef Command self; ///< Self reference type. public: + Command(Command && that); ~Command(); /** Add a subcommand to this command. @@ -65,11 +68,13 @@ class CommandTable /** Add a subcommand to this command. @return The new sub command instance. */ - Command &subCommand(std::string const &name, std::string const &help, CommandFunction const &f); + Command &subCommand(std::string const &name, std::string const &help, NullaryAction const &f); /** Add a leaf command. @return This new sub command instance. */ - Command &set(CommandFunction const &f); + Command &subCommand(std::string const &name, std::string const &help, Action const &f); + + // Command &set(CommandFunction const &f); /** Invoke a command. @return The return value of the executed command, or an error value if the command was not found. @@ -80,11 +85,23 @@ class CommandTable protected: typedef std::vector CommandGroup; + struct nil_t {}; std::string _name; ///< Command name. std::string _help; ///< Help message. - /// Command to execute if no more keywords. - CommandFunction _func; + enum { + SUPER, ///< Pure super command, not valid itself + LEAF, ///< Leaf command (always invoke) + NO_ARGS ///< Argumentless command, invoke if no more args. + } _style = SUPER; + /// Command to execute. + union ActionContainer{ + ActionContainer(){} + ~ActionContainer(){} + nil_t _nil; + Action _a; + NullaryAction _na; + } _action; /// Next command for current keyword. CommandGroup _group; @@ -93,7 +110,9 @@ class CommandTable /// Construct with a function for this command. Command(std::string const &name, std::string const &help); /// Construct with a function for this command. - Command(std::string const &name, std::string const &help, CommandFunction const &f); + Command(std::string const &name, std::string const &help, Action const &f); + /// Construct with a function for this command. + Command(std::string const &name, std::string const &help, NullaryAction const &f); friend class CommandTable; }; @@ -101,7 +120,12 @@ class CommandTable /** Add a direct command. @return The created @c Command instance. */ - Command &add(std::string const &name, std::string const &help, CommandFunction const &f); + Command &add(std::string const &name, std::string const &help, Action const &f); + + /** Add a direct command. + @return The created @c Command instance. + */ + Command &add(std::string const &name, std::string const &help, NullaryAction const &f); /** Add a parent command. @return The created @c Command instance. From 770ce79f5084eae864ee2b6fa65ca233ff6550ea Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Wed, 2 Aug 2017 16:39:11 -0500 Subject: [PATCH 2/3] Add nullary commands to Command. Use in CacheTool. --- cmd/traffic_cache_tool/CacheTool.cc | 6 +++--- cmd/traffic_cache_tool/Command.cc | 11 ++--------- cmd/traffic_cache_tool/Command.h | 2 -- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/cmd/traffic_cache_tool/CacheTool.cc b/cmd/traffic_cache_tool/CacheTool.cc index 332e019fb1e..11adc3be551 100644 --- a/cmd/traffic_cache_tool/CacheTool.cc +++ b/cmd/traffic_cache_tool/CacheTool.cc @@ -1151,7 +1151,7 @@ struct option Options[] = {{"help", 0, nullptr, 'h'}, } Errata -List_Stripes(Cache::SpanDumpDepth depth, int argc, char *argv[]) +List_Stripes(Cache::SpanDumpDepth depth) { Errata zret; Cache cache; @@ -1241,9 +1241,9 @@ main(int argc, char *argv[]) Commands .add("list", "List elements of the cache", - [](int argc, char *argv[]) { return List_Stripes(Cache::SpanDumpDepth::SPAN, argc, argv); }) + []() { return List_Stripes(Cache::SpanDumpDepth::SPAN); }) .subCommand(std::string("stripes"), std::string("List the stripes"), - [](int argc, char *argv[]) { return List_Stripes(Cache::SpanDumpDepth::STRIPE, argc, argv); }); + []() { return List_Stripes(Cache::SpanDumpDepth::STRIPE); }); Commands.add(std::string("clear"), std::string("Clear spans"), &Clear_Spans); Commands.add(std::string("volumes"), std::string("Volumes"), &Simulate_Span_Allocation); Commands.add(std::string("alloc"), std::string("Storage allocation")) diff --git a/cmd/traffic_cache_tool/Command.cc b/cmd/traffic_cache_tool/Command.cc index 4e1b1c54c5c..0f6d4834bd6 100644 --- a/cmd/traffic_cache_tool/Command.cc +++ b/cmd/traffic_cache_tool/Command.cc @@ -42,6 +42,8 @@ ERR_COMMAND_TAG_NOT_FOUND(char const *tag) return ts::Errata(s.str()); } +CommandTable::Command::Command() {} + CommandTable::Command::Command(std::string const &name, std::string const &help) : _name(name), _help(help) { } @@ -74,15 +76,6 @@ CommandTable::Command::~Command() { } } -# if 0 -auto -CommandTable::Command::set(CommandFunction const &f) -> self & -{ - _func = f; - return *this; -} -#endif - CommandTable::Command & CommandTable::Command::subCommand(std::string const &name, std::string const &help, Action const &f) { diff --git a/cmd/traffic_cache_tool/Command.h b/cmd/traffic_cache_tool/Command.h index 1c52934796a..8b2c7f5c105 100644 --- a/cmd/traffic_cache_tool/Command.h +++ b/cmd/traffic_cache_tool/Command.h @@ -74,8 +74,6 @@ class CommandTable */ Command &subCommand(std::string const &name, std::string const &help, Action const &f); - // Command &set(CommandFunction const &f); - /** Invoke a command. @return The return value of the executed command, or an error value if the command was not found. */ From 6849a976c53d6fc723513012d959897355e84935 Mon Sep 17 00:00:00 2001 From: "Alan M. Carroll" Date: Thu, 3 Aug 2017 12:46:27 -0500 Subject: [PATCH 3/3] Updated to handle leaf vs. nullary command functions. --- cmd/traffic_cache_tool/Command.cc | 35 ++++--------- cmd/traffic_cache_tool/Command.h | 87 ++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 42 deletions(-) diff --git a/cmd/traffic_cache_tool/Command.cc b/cmd/traffic_cache_tool/Command.cc index 0f6d4834bd6..c7a98d1310f 100644 --- a/cmd/traffic_cache_tool/Command.cc +++ b/cmd/traffic_cache_tool/Command.cc @@ -48,36 +48,23 @@ CommandTable::Command::Command(std::string const &name, std::string const &help) { } -CommandTable::Command::Command(std::string const &name, std::string const &help, Action const &f) - : _name(name), _help(help), _style(LEAF) +CommandTable::Command::Command(std::string const &name, std::string const &help, LeafAction const &f) + : _name(name), _help(help) { - _action._a = f; + _action = f; } CommandTable::Command::Command(std::string const &name, std::string const &help, NullaryAction const &f) - : _name(name), _help(help), _style(NO_ARGS) + : _name(name), _help(help) { - _action._na = f; -} - -CommandTable::Command::Command(Command && that) : _name(std::move(that._name)), _help(std::move(that._help)), _style(that._style) { - switch (_style) { - case SUPER: break; - case NO_ARGS: _action._na = std::move(that._action._na); break; - case LEAF: _action._a = std::move(that._action._a); break; - } + _action = f; } CommandTable::Command::~Command() { - switch (_style) { - case SUPER: break; - case NO_ARGS: _action._na.~NullaryAction(); break; - case LEAF: _action._a.~Action(); break; - } } CommandTable::Command & -CommandTable::Command::subCommand(std::string const &name, std::string const &help, Action const &f) +CommandTable::Command::subCommand(std::string const &name, std::string const &help, LeafAction const &f) { _group.push_back(Command(name, help, f)); return _group.back(); @@ -102,11 +89,11 @@ CommandTable::Command::invoke(int argc, char *argv[]) { ts::Errata zret; - if (LEAF == _style) { - zret = _action._a(argc - CommandTable::_opt_idx, argv + CommandTable::_opt_idx); + if (_action.is_leaf()) { + zret = _action.invoke(argc - CommandTable::_opt_idx, argv + CommandTable::_opt_idx); } else if (CommandTable::_opt_idx >= argc || argv[CommandTable::_opt_idx][0] == '-') { - if (NO_ARGS == _style) { - zret = _action._na(); + if (_action.is_nullary()) { + zret = _action.invoke(); } else { std::ostringstream s; s << "Incomplete command, additional keyword required"; @@ -165,7 +152,7 @@ CommandTable::add(std::string const &name, std::string const &help) -> Command & } auto -CommandTable::add(std::string const &name, std::string const &help, Action const &f) -> Command & +CommandTable::add(std::string const &name, std::string const &help, LeafAction const &f) -> Command & { return _top.subCommand(name, help, f); } diff --git a/cmd/traffic_cache_tool/Command.h b/cmd/traffic_cache_tool/Command.h index 8b2c7f5c105..582f46766e7 100644 --- a/cmd/traffic_cache_tool/Command.h +++ b/cmd/traffic_cache_tool/Command.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #if !defined(CACHE_TOOL_COMMAND_H) @@ -45,7 +46,7 @@ class CommandTable typedef CommandTable self; ///< Self reference type. public: /// Signature for a leaf command. - using Action = std::function; + using LeafAction = std::function; /// Signature for a argumentless command. using NullaryAction = std::function; @@ -58,7 +59,7 @@ class CommandTable { typedef Command self; ///< Self reference type. public: - Command(Command && that); + Command(Command && that) = default; ~Command(); /** Add a subcommand to this command. @@ -72,7 +73,7 @@ class CommandTable /** Add a leaf command. @return This new sub command instance. */ - Command &subCommand(std::string const &name, std::string const &help, Action const &f); + Command &subCommand(std::string const &name, std::string const &help, LeafAction const &f); /** Invoke a command. @return The return value of the executed command, or an error value if the command was not found. @@ -83,23 +84,73 @@ class CommandTable protected: typedef std::vector CommandGroup; - struct nil_t {}; std::string _name; ///< Command name. std::string _help; ///< Help message. - enum { - SUPER, ///< Pure super command, not valid itself - LEAF, ///< Leaf command (always invoke) - NO_ARGS ///< Argumentless command, invoke if no more args. - } _style = SUPER; - /// Command to execute. - union ActionContainer{ - ActionContainer(){} - ~ActionContainer(){} - nil_t _nil; - Action _a; - NullaryAction _na; + + /** Class to hold varying types of functions. + + @internal A bit ugly, I need to do better wrapping and type erasure. + */ + class Action { + public: + /// Type of the function stored. + enum Type { + NIL, ///< Nothing / empty + LEAF, ///< Leaf action (arguments) + NULLARY, ///< Nullary action. + }; + Action() { } + Action(Action && that) { + _type = that._type; + memcpy(_data, that._data, sizeof(_data)); + that._type = NIL; + } + ~Action() { this->clear(); } + + Action& operator = (LeafAction const& a) { + this->clear(); + _type = LEAF; + new (_data) LeafAction(a); + return *this; + } + + Action& operator = (NullaryAction const& a) { + this->clear(); + _type = NULLARY; + new (_data) NullaryAction(a); + return *this; + } + + Errata invoke(int argc, char *argv[]) { + assert(LEAF == _type); + return (*reinterpret_cast(_data))(argc, argv); + } + + Errata invoke() { + assert(NULLARY == _type); + return (*reinterpret_cast(_data))(); + } + + bool is_leaf() const { return LEAF == _type; } + bool is_nullary() const { return NULLARY == _type; } + + protected: + + void clear() { + switch (_type) { + case NIL: break; + case LEAF: reinterpret_cast(_data)->~LeafAction(); break; + case NULLARY: reinterpret_cast(_data)->~NullaryAction(); break; + } + _type = NIL; + } + + Type _type = NIL; ///< Type of function stored. + /// Raw storage for the function. + char _data[sizeof(NullaryAction) > sizeof(LeafAction) ? sizeof(NullaryAction) : sizeof(LeafAction)]; } _action; + /// Next command for current keyword. CommandGroup _group; @@ -108,7 +159,7 @@ class CommandTable /// Construct with a function for this command. Command(std::string const &name, std::string const &help); /// Construct with a function for this command. - Command(std::string const &name, std::string const &help, Action const &f); + Command(std::string const &name, std::string const &help, LeafAction const &f); /// Construct with a function for this command. Command(std::string const &name, std::string const &help, NullaryAction const &f); @@ -118,7 +169,7 @@ class CommandTable /** Add a direct command. @return The created @c Command instance. */ - Command &add(std::string const &name, std::string const &help, Action const &f); + Command &add(std::string const &name, std::string const &help, LeafAction const &f); /** Add a direct command. @return The created @c Command instance.