#pragma once /** * \file Commands.h * \brief File containing the definitions of the lockstep commands */ #include #include #include #include #include namespace sp { namespace protocol { class CommandVisitor; /** A Command id is 8 bits wide */ using CommandID = std::uint8_t; #define DeclareCommand(CommandName, ...) /** CommandName */ CommandName, /** * \enum CommandType * \brief Map a Command to an id */ enum class CommandType : CommandID { DeclareAllCommand() /** The number of Commands */ COMMAND_COUNT }; #undef DeclareCommand class Command : private NonCopyable { public: /** * \return The real type of the Command */ virtual CommandType GetType() const = 0; private: /** Use a CommandVisitor to make double-dispatch possible */ virtual void Accept(CommandVisitor& a_Visitor) const = 0; friend class CommandVisitor; }; namespace commands { /** * \class ConcreteCommand * \brief A Command associated with an id and holding data * \tparam PT The Command type * \tparam Data The structure holding the data of the Command (in sp::protocol::data namespace) */ template class ConcreteCommand : public Command { public: /** The type of the struct holding the data */ using CommandDataType = Data; /** The structure holding the actual data */ CommandDataType m_Data; /** Construct the Command with data of type CommandDataType */ ConcreteCommand(const CommandDataType& a_Data = {}); constexpr CommandType GetType() const override { return CT; }; private: void Accept(CommandVisitor& a_Visitor) const override; }; // define SP_INSTANCIATE_COMMANDS // before including this file // if you want to instantiate templates #ifdef SP_INSTANCIATE_COMMANDS #define DeclareCommand(CommandName, ...) \ using CommandName = ConcreteCommand; \ template class ConcreteCommand; #else #define DeclareCommand(CommandName, ...) /** Defines the CommandName Command */ \ using CommandName = ConcreteCommand; #endif DeclareAllCommand() #undef DeclareCommand } // namespace commands using LockStep = std::vector>; } // namespace protocol } // namespace sp