Last active
March 16, 2020 15:04
-
-
Save janderudder/c06db011e1f21a386fc106b515b1ee92 to your computer and use it in GitHub Desktop.
Simple command & command queue in C++17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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