Codechange: Template the command callback function type to allow unpacked arguments.

This commit is contained in:
Michael Lutz
2021-11-28 17:37:04 +01:00
parent 13528bfcd0
commit d85348b1d1
7 changed files with 153 additions and 71 deletions

View File

@@ -78,6 +78,20 @@ private:
static int _counter;
};
#if defined(__GNUC__) && !defined(__clang__)
/*
* We cast specialized function pointers to a generic one, but don't use the
* converted value to call the function, which is safe, except that GCC
* helpfully thinks it is not.
*
* "Any pointer to function can be converted to a pointer to a different function type.
* Calling the function through a pointer to a different function type is undefined,
* but converting such pointer back to pointer to the original function type yields
* the pointer to the original function." */
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
# define SILENCE_GCC_FUNCTION_POINTER_CAST
#endif
template<Commands TCmd, typename T, bool THasTile> struct CommandHelper;
@@ -148,18 +162,19 @@ public:
* @param err_message Message prefix to show on error
* @param args Parameters for the command
*/
static inline bool Post(StringID err_message, Targs... args) { return Post(err_message, nullptr, std::forward<Targs>(args)...); }
static inline bool Post(StringID err_message, Targs... args) { return Post<CommandCallback>(err_message, nullptr, std::forward<Targs>(args)...); }
/**
* Shortcut for the long Post when not using an error message.
* @param callback A callback function to call after the command is finished
* @param args Parameters for the command
*/
static inline bool Post(CommandCallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward<Targs>(args)...); }
template <typename Tcallback>
static inline bool Post(Tcallback *callback, Targs... args) { return Post((StringID)0, callback, std::forward<Targs>(args)...); }
/**
* Shortcut for the long Post when not using a callback or an error message.
* @param args Parameters for the command
*/
static inline bool Post(Targs... args) { return Post((StringID)0, nullptr, std::forward<Targs>(args)...); }
static inline bool Post(Targs... args) { return Post<CommandCallback>((StringID)0, nullptr, std::forward<Targs>(args)...); }
/**
* Top-level network safe command execution for the current company.
@@ -171,7 +186,8 @@ public:
* @param args Parameters for the command
* @return \c true if the command succeeded, else \c false.
*/
static bool Post(StringID err_message, CommandCallback *callback, Targs... args)
template <typename Tcallback>
static bool Post(StringID err_message, Tcallback *callback, Targs... args)
{
return InternalPost(err_message, callback, true, false, std::forward_as_tuple(args...));
}
@@ -185,7 +201,8 @@ public:
* @param args Parameters for the command
* @return \c true if the command succeeded, else \c false.
*/
static bool PostFromNet(StringID err_message, CommandCallback *callback, bool my_cmd, TileIndex location, std::tuple<Targs...> args)
template <typename Tcallback>
static bool PostFromNet(StringID err_message, Tcallback *callback, bool my_cmd, TileIndex location, std::tuple<Targs...> args)
{
return InternalPost(err_message, callback, my_cmd, true, location, std::move(args));
}
@@ -194,11 +211,10 @@ public:
* Prepare a command to be send over the network
* @param cmd The command to execute (a CMD_* value)
* @param err_message Message prefix to show on error
* @param callback A callback function to call after the command is finished
* @param company The company that wants to send the command
* @param args Parameters for the command
*/
static void SendNet(StringID err_message, CommandCallback *callback, CompanyID company, Targs... args)
static void SendNet(StringID err_message, CompanyID company, Targs... args)
{
auto args_tuple = std::forward_as_tuple(args...);
@@ -207,7 +223,7 @@ public:
tile = std::get<0>(args_tuple);
}
::NetworkSendCommand(Tcmd, err_message, callback, _current_company, tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
::NetworkSendCommand(Tcmd, err_message, nullptr, _current_company, tile, EndianBufferWriter<CommandDataBuffer>::FromValue(args_tuple));
}
/**
@@ -220,9 +236,10 @@ public:
* @param args Parameters for the command
* @return the command cost of this function.
*/
static CommandCost Unsafe(StringID err_message, CommandCallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple<Targs...> args)
template <typename Tcallback>
static CommandCost Unsafe(StringID err_message, Tcallback *callback, bool my_cmd, bool estimate_only, TileIndex location, std::tuple<Targs...> args)
{
return Execute(err_message, callback, my_cmd, estimate_only, false, location, std::move(args));
return Execute(err_message, reinterpret_cast<CommandCallback *>(callback), my_cmd, estimate_only, false, location, std::move(args));
}
protected:
@@ -242,7 +259,8 @@ protected:
((SetClientIdHelper(std::get<Tindices>(values))), ...);
}
static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
template <typename Tcallback>
static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, std::tuple<Targs...> args)
{
/* Where to show the message? */
TileIndex tile{};
@@ -253,7 +271,8 @@ protected:
return InternalPost(err_message, callback, my_cmd, network_command, tile, std::move(args));
}
static bool InternalPost(StringID err_message, CommandCallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple<Targs...> args)
template <typename Tcallback>
static bool InternalPost(StringID err_message, Tcallback *callback, bool my_cmd, bool network_command, TileIndex tile, std::tuple<Targs...> args)
{
auto [err, estimate_only, only_sending] = InternalPostBefore(Tcmd, GetCommandFlags<Tcmd>(), tile, err_message, network_command);
if (err) return false;
@@ -261,7 +280,7 @@ protected:
/* Only set client IDs when the command does not come from the network. */
if (!network_command && GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) SetClientIds(args, std::index_sequence_for<Targs...>{});
CommandCost res = Execute(err_message, callback, my_cmd, estimate_only, network_command, tile, args);
CommandCost res = Execute(err_message, reinterpret_cast<CommandCallback *>(callback), my_cmd, estimate_only, network_command, tile, args);
InternalPostResult(res, tile, estimate_only, only_sending, err_message, my_cmd);
if (!estimate_only && !only_sending && callback != nullptr) {
@@ -360,20 +379,21 @@ struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), false> : Com
* @param location Tile location for user feedback.
* @param args Parameters for the command
*/
static inline bool Post(StringID err_message, TileIndex location, Targs... args) { return Post(err_message, nullptr, location, std::forward<Targs>(args)...); }
static inline bool Post(StringID err_message, TileIndex location, Targs... args) { return Post<CommandCallback>(err_message, nullptr, location, std::forward<Targs>(args)...); }
/**
* Shortcut for Post when not using a callback.
* @param callback A callback function to call after the command is finished
* @param location Tile location for user feedback.
* @param args Parameters for the command
*/
static inline bool Post(CommandCallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward<Targs>(args)...); }
template <typename Tcallback>
static inline bool Post(Tcallback *callback, TileIndex location, Targs... args) { return Post((StringID)0, callback, location, std::forward<Targs>(args)...); }
/**
* Shortcut for Post when not using a callback or an error message.
* @param location Tile location for user feedback.
* @param args Parameters for the command*
*/
static inline bool Post(TileIndex location, Targs... args) { return Post((StringID)0, nullptr, location, std::forward<Targs>(args)...); }
static inline bool Post(TileIndex location, Targs... args) { return Post<CommandCallback>((StringID)0, nullptr, location, std::forward<Targs>(args)...); }
/**
* Post variant that takes a TileIndex (for error window location and text effects) for
@@ -384,12 +404,16 @@ struct CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), false> : Com
* @param args Parameters for the command
* @return \c true if the command succeeded, else \c false.
*/
static inline bool Post(StringID err_message, CommandCallback *callback, TileIndex location, Targs... args)
template <typename Tcallback>
static inline bool Post(StringID err_message, Tcallback *callback, TileIndex location, Targs... args)
{
return CommandHelper<Tcmd, CommandCost(*)(DoCommandFlag, Targs...), true>::InternalPost(err_message, callback, true, false, location, std::forward_as_tuple(args...));
}
};
#ifdef SILENCE_GCC_FUNCTION_POINTER_CAST
# pragma GCC diagnostic pop
#endif
template <Commands Tcmd>
using Command = CommandHelper<Tcmd, typename CommandTraits<Tcmd>::ProcType, std::is_same_v<TileIndex, std::tuple_element_t<0, typename CommandTraits<Tcmd>::Args>>>;