Skip to content

Instantly share code, notes, and snippets.

@janderudder
Last active March 16, 2020 15:04
Show Gist options
  • Save janderudder/c06db011e1f21a386fc106b515b1ee92 to your computer and use it in GitHub Desktop.
Save janderudder/c06db011e1f21a386fc106b515b1ee92 to your computer and use it in GitHub Desktop.
Simple command & command queue in C++17
#include <any>
#include <functional>
#include <iostream>
#include <map>
#include <string_view>
#include <tuple>
#include <queue>
int main()
{
// Something to turn strings into integers
using cmd_name_hasher_t = std::hash<std::string_view>;
cmd_name_hasher_t const command_name_hasher;
// The integer type of a hashed command name
using cmd_identifier_t
= std::invoke_result_t<cmd_name_hasher_t, std::string_view>;
// The actual type of a command object
using command_t = std::tuple<cmd_identifier_t, std::any>;
// Some functions to process different kinds of commands
auto const process_say_hello = [](std::any args)
{
std::cout << "We received a 'greetings' command.\n";
if (!args.has_value()) {
std::cout << "We were not given any argument this time.\n";
}
else {
std::cout << "We would like to say the following: ";
std::cout << std::any_cast<const char*>(args) << "\n";
}
std::cout << "\n";
};
auto const process_say_goodbye = [](std::any args)
{
std::cout << "We received a 'good bye' command.\n";
if (args.has_value()) {
std::cout << "Let me just add this before we leave: ";
std::cout << std::any_cast<const char*>(args) << "\n";
}
std::cout << "\n";
};
// This is the signature of those functions
using cmd_process_fn_t = std::function<void(std::any const&)>;
// Store them in a map with hashed command name as key
std::map<cmd_identifier_t, cmd_process_fn_t> command_function_map
{
{ command_name_hasher("say_hello_cmd"), process_say_hello },
{ command_name_hasher("say_goodbye_cmd"), process_say_goodbye }
};
// A little helper to create a command object
auto const make_command
= [command_name_hasher](std::string_view name, auto... args)
{
return command_t{command_name_hasher(name), std::any{std::move(args)...}};
};
// The command queue, central to this system: this is where the commands
// are put to await processing in a loop
std::queue<command_t> command_queue;
command_queue.push(make_command("say_hello_cmd"));
command_queue.push(make_command("say_hello_cmd", "hello, world!"));
command_queue.push(make_command("say_goodbye_cmd", "So long!"));
// A loop that polls the command queue and invokes the corresponding
// processing function. This should happen inside a main app loop.
while (!command_queue.empty())
{
auto const& [id, args] = command_queue.front();
std::invoke(command_function_map[id], args);
command_queue.pop();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment