Created
August 10, 2023 14:05
-
-
Save mosolovsa/3380444b3cc46d12c076e59838809902 to your computer and use it in GitHub Desktop.
Virtual table for predefined set of custom protocol request handlers to make possible store request structures as POD and dispatching to handler via request type
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 <iostream> | |
#include <cassert> | |
using RequestHandler = void (*)(void); | |
struct RequestHandlers { | |
static constexpr size_t MAX_REQ_TYPE_CNT = 255; | |
enum EFlags { | |
IsExisting = 0x01, | |
}; | |
int flags; | |
RequestHandler setup; | |
RequestHandler handle; | |
RequestHandler teardown; | |
RequestHandlers() | |
: flags(0) | |
, setup(nullptr) | |
, handle(nullptr) | |
, teardown(nullptr) | |
{} | |
}; | |
class RequestHandlersRegistry { | |
public: | |
static RequestHandlersRegistry& getInstance() { | |
static RequestHandlersRegistry instance; | |
return instance; | |
} | |
RequestHandlers handlers[RequestHandlers::MAX_REQ_TYPE_CNT]; | |
private: | |
RequestHandlersRegistry() = default; | |
}; | |
void dummy(void) { | |
std::cout << "called dummy()" << std::endl; | |
} | |
template<typename DERIVED> | |
struct AutoRegister { | |
// static_assert(DERIVED::REQ_TYPE >= 0 && DERIVED::REQ_TYPE <= 254, "Request type must be in range 0...254"); | |
AutoRegister() { | |
registerHandlers(RequestHandlersRegistry::getInstance()); | |
} | |
void registerHandlers(RequestHandlersRegistry& registry) { | |
auto& this_req_handlers = registry.handlers[DERIVED::REQ_TYPE]; | |
// you've already got registered handlers for that type of request | |
// check that this request type is unique across request structures | |
assert((this_req_handlers.flags & RequestHandlers::EFlags::IsExisting) == 0); | |
this_req_handlers.setup = DERIVED::setup; | |
this_req_handlers.handle = DERIVED::handle; | |
this_req_handlers.teardown = DERIVED::teardown; | |
this_req_handlers.flags |= RequestHandlers::EFlags::IsExisting; | |
} | |
}; | |
#define BEGIN_REQUEST_DEFINITION(name, type_id) \ | |
class name { \ | |
static const struct Autoregistrer : public AutoRegister<name> {} __autoregister_handlers; \ | |
public: \ | |
static constexpr uint8_t REQ_TYPE = type_id;\ | |
private: | |
#define END_REQUEST_DEFINITION(name) \ | |
}; \ | |
const name::Autoregistrer name::__autoregister_handlers{}; | |
#define DEFINE_REQUEST_HANDLER_CLASS(name, type_id, members) \ | |
class name { \ | |
static const struct Autoregistrer : public AutoRegister<name> {} __autoregister_handlers; \ | |
public: \ | |
static constexpr uint8_t REQ_TYPE = type_id; \ | |
members \ | |
}; \ | |
const name::Autoregistrer name::__autoregister_handlers{}; | |
DEFINE_REQUEST_HANDLER_CLASS(RequsetType0, 0, | |
public: | |
static void setup(void) { | |
std::cout << "RequestType0 setup called" << std::endl; | |
} | |
static void handle(void) { | |
std::cout << "RequestType0 handle called" << std::endl; | |
} | |
static void teardown(void) { | |
std::cout << "RequestType0 teardown called" << std::endl; | |
} | |
) | |
DEFINE_REQUEST_HANDLER_CLASS(RequsetType1, 1, | |
public: | |
static void setup(void) { | |
std::cout << "RequestType1 setup called" << std::endl; | |
} | |
static void handle(void) { | |
std::cout << "RequestType1 handle called" << std::endl; | |
} | |
static void teardown(void) { | |
std::cout << "RequestType1 teardown called" << std::endl; | |
} | |
) | |
int main() { | |
const auto& handlerRegistry = RequestHandlersRegistry::getInstance(); | |
handlerRegistry.handlers[0].setup(); | |
handlerRegistry.handlers[1].teardown(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment