|
|
@@ -0,0 +1,670 @@
|
|
|
+#include <iostream>
|
|
|
+#include <string>
|
|
|
+#include <map>
|
|
|
+#include <vector>
|
|
|
+#include <functional>
|
|
|
+#include <algorithm>
|
|
|
+#include <memory>
|
|
|
+#include <typeindex>
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <vector>
|
|
|
+#include <functional>
|
|
|
+#include <memory>
|
|
|
+#include <typeinfo>
|
|
|
+#include <typeindex>
|
|
|
+#include <tuple>
|
|
|
+#include <stdexcept>
|
|
|
+#include <algorithm>
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <functional>
|
|
|
+#include <unordered_map>
|
|
|
+#include <vector>
|
|
|
+#include <tuple>
|
|
|
+#include <typeindex>
|
|
|
+#include <string>
|
|
|
+#include <algorithm>
|
|
|
+#include <cassert>
|
|
|
+
|
|
|
+enum class EventType {
|
|
|
+ Click,
|
|
|
+ Hover,
|
|
|
+ Custom
|
|
|
+};
|
|
|
+
|
|
|
+using HandlerID = std::size_t;
|
|
|
+
|
|
|
+class EventDispatcher {
|
|
|
+public:
|
|
|
+ EventDispatcher() : nextHandlerID(1) {}
|
|
|
+
|
|
|
+ // Add a handler; returns an ID for removal
|
|
|
+ template<typename F>
|
|
|
+ HandlerID addHandler(EventType type, F&& f) {
|
|
|
+ using Traits = FunctionTraits<std::decay_t<F>>;
|
|
|
+ using R = typename Traits::ReturnType;
|
|
|
+ using Tuple = typename Traits::ArgsTuple;
|
|
|
+ return addHandlerImpl<R>(type, std::forward<F>(f), static_cast<Tuple*>(nullptr));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove a handler by its ID
|
|
|
+ void removeHandler(EventType type, HandlerID id) {
|
|
|
+ auto& vec = handlers[type];
|
|
|
+ vec.erase(std::remove_if(vec.begin(), vec.end(),
|
|
|
+ [id](const HandlerBasePtr& h) { return h->id == id; }),
|
|
|
+ vec.end());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Emit: returns vector of return values from all handlers of matching type/signature
|
|
|
+ template<typename R = void, typename... Args>
|
|
|
+ std::vector<R> emit(EventType type, Args&&... args) {
|
|
|
+ std::vector<R> results;
|
|
|
+ auto it = handlers.find(type);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ for (auto& handlerBase : it->second) {
|
|
|
+ auto handler = dynamic_cast<Handler<R, Args...>*>(handlerBase.get());
|
|
|
+ if (handler) {
|
|
|
+ if constexpr (std::is_void_v<R>) {
|
|
|
+ handler->func(std::forward<Args>(args)...);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ results.push_back(handler->func(std::forward<Args>(args)...));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ struct HandlerBase {
|
|
|
+ HandlerID id;
|
|
|
+ virtual ~HandlerBase() = default;
|
|
|
+ };
|
|
|
+ using HandlerBasePtr = std::unique_ptr<HandlerBase>;
|
|
|
+
|
|
|
+ template<typename R, typename... Args>
|
|
|
+ struct Handler : HandlerBase {
|
|
|
+ std::function<R(Args...)> func;
|
|
|
+ Handler(HandlerID id, std::function<R(Args...)> f)
|
|
|
+ : func(std::move(f)) {
|
|
|
+ this->id = id;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ std::unordered_map<EventType, std::vector<HandlerBasePtr>> handlers;
|
|
|
+ HandlerID nextHandlerID;
|
|
|
+
|
|
|
+ // FunctionTraits to deduce argument and return types
|
|
|
+ template<typename T>
|
|
|
+ struct FunctionTraits : public FunctionTraits<decltype(&T::operator())> {};
|
|
|
+
|
|
|
+ // For lambdas/functors (const call operator)
|
|
|
+ template<typename C, typename R, typename... Args>
|
|
|
+ struct FunctionTraits<R(C::*)(Args...) const> {
|
|
|
+ using ReturnType = R;
|
|
|
+ using ArgsTuple = std::tuple<Args...>;
|
|
|
+ };
|
|
|
+
|
|
|
+ // For non-const call operator
|
|
|
+ template<typename C, typename R, typename... Args>
|
|
|
+ struct FunctionTraits<R(C::*)(Args...)> {
|
|
|
+ using ReturnType = R;
|
|
|
+ using ArgsTuple = std::tuple<Args...>;
|
|
|
+ };
|
|
|
+
|
|
|
+ // For function pointers
|
|
|
+ template<typename R, typename... Args>
|
|
|
+ struct FunctionTraits<R(*)(Args...)> {
|
|
|
+ using ReturnType = R;
|
|
|
+ using ArgsTuple = std::tuple<Args...>;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Implementation: avoid constructing tuple-of-references!
|
|
|
+ template<typename R, typename F, typename... Args>
|
|
|
+ HandlerID addHandlerImpl(EventType type, F&& f, std::tuple<Args...>*) {
|
|
|
+ auto handler = std::make_unique<Handler<R, Args...>>(nextHandlerID, std::function<R(Args...)>(std::forward<F>(f)));
|
|
|
+ handlers[type].emplace_back(std::move(handler));
|
|
|
+ return nextHandlerID++;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+struct Widget {
|
|
|
+ void onClick(int x) {
|
|
|
+ std::cout << "Widget::onClick(" << x << ")\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ void onClick_1(int x) {
|
|
|
+ std::cout << "Widget::onClick_1(" << x << ")\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ void onClick_2(int x) {
|
|
|
+ std::cout << "Widget::onClick_2(" << x << ")\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ void onClick_3(int x) {
|
|
|
+ std::cout << "Widget::onClick_2(" << x << ")\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ bool onHover(const std::string& msg) {
|
|
|
+ std::cout << "Widget::onHover_3(" << msg << ")\n";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+bool globalHandler(int x) {
|
|
|
+ std::cout << "globalHandler(" << x << ")\n";
|
|
|
+ return x > 0;
|
|
|
+}
|
|
|
+
|
|
|
+int main() {
|
|
|
+ EventDispatcher dispatcher;
|
|
|
+ Widget w;
|
|
|
+
|
|
|
+ // Register handlers and keep their IDs for removal
|
|
|
+ auto id1 = dispatcher.addHandler(EventType::Click, globalHandler);
|
|
|
+
|
|
|
+ auto id2 = dispatcher.addHandler(EventType::Click, [](int x) {
|
|
|
+ std::cout << "lambda(" << x << ")\n";
|
|
|
+ return x % 2 == 0;
|
|
|
+ });
|
|
|
+ auto id3 = dispatcher.addHandler(EventType::Click, [&w](int x) { w.onClick(x); });
|
|
|
+ dispatcher.addHandler(EventType::Click, [&w](int x) { w.onClick_1(x); });
|
|
|
+ dispatcher.addHandler(EventType::Click, [&w](int x) { w.onClick_2(x); });
|
|
|
+ dispatcher.addHandler(EventType::Click, [&w](int x) { w.onClick_3(x); });
|
|
|
+
|
|
|
+ auto id4 = dispatcher.addHandler(EventType::Hover, [&w](const std::string& msg) { return w.onHover(msg); });
|
|
|
+
|
|
|
+ // Emit events; collect return values if any
|
|
|
+ auto clickResults = dispatcher.emit<bool>(EventType::Click, 42);
|
|
|
+ auto hoverResults = dispatcher.emit<bool>(EventType::Hover, std::string("hello"));
|
|
|
+
|
|
|
+ std::cout << "Click results: ";
|
|
|
+ for (bool b : clickResults) std::cout << b << " ";
|
|
|
+ std::cout << "\n";
|
|
|
+
|
|
|
+ std::cout << "Hover results: ";
|
|
|
+ for (bool b : hoverResults) std::cout << b << " ";
|
|
|
+ std::cout << "\n";
|
|
|
+
|
|
|
+ // Remove a handler and emit again
|
|
|
+ dispatcher.removeHandler(EventType::Click, id1);
|
|
|
+ clickResults = dispatcher.emit<bool>(EventType::Click, 7);
|
|
|
+ std::cout << "Click results after removal: ";
|
|
|
+ for (bool b : clickResults) std::cout << b << " ";
|
|
|
+ std::cout << "\n";
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// This code is a more complex version of the EventDispatcher, which allows for different types of events and handlers.
|
|
|
+#if 0
|
|
|
+/*
|
|
|
+Certainly!Here’s how you can improve the code by :
|
|
|
+
|
|
|
+1. * *Using an enum for event types** instead of string names.
|
|
|
+2. * *Using `Args...` for arguments** in `invokeAll`, `invokeById`, etc., so you don’t need to repeat the argument list everywhere.
|
|
|
+
|
|
|
+Below is a complete, working code example with these improvements :
|
|
|
+*/
|
|
|
+
|
|
|
+// 1. Define event types as enum
|
|
|
+enum class EventType {
|
|
|
+ ButtonClick,
|
|
|
+ Redraw,
|
|
|
+ Hover
|
|
|
+};
|
|
|
+
|
|
|
+// Helper for unique handler IDs
|
|
|
+class IdGen {
|
|
|
+ size_t current = 0;
|
|
|
+public:
|
|
|
+ size_t next() { return ++current; }
|
|
|
+};
|
|
|
+
|
|
|
+// Type-erased base for handler lists
|
|
|
+struct IEventHandlerList {
|
|
|
+ virtual ~IEventHandlerList() {}
|
|
|
+};
|
|
|
+
|
|
|
+// Templated handler list for a given signature
|
|
|
+template<typename Ret, typename... Args>
|
|
|
+class EventHandlerList : public IEventHandlerList {
|
|
|
+public:
|
|
|
+ using HandlerType = std::function<Ret(Args...)>;
|
|
|
+ struct HandlerEntry {
|
|
|
+ size_t id;
|
|
|
+ HandlerType handler;
|
|
|
+ };
|
|
|
+
|
|
|
+ size_t addHandler(const HandlerType& h) {
|
|
|
+ size_t id = idGen.next();
|
|
|
+ handlers.push_back({ id, h });
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+
|
|
|
+ void removeHandler(size_t id) {
|
|
|
+ handlers.erase(std::remove_if(handlers.begin(), handlers.end(),
|
|
|
+ [id](const HandlerEntry& e) { return e.id == id; }), handlers.end());
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<Ret> invokeAll(Args... args) {
|
|
|
+ std::vector<Ret> results;
|
|
|
+ for (auto& entry : handlers) {
|
|
|
+ results.push_back(entry.handler(args...));
|
|
|
+ }
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ret invokeById(size_t id, Args... args) {
|
|
|
+ for (auto& entry : handlers) {
|
|
|
+ if (entry.id == id)
|
|
|
+ return entry.handler(args...);
|
|
|
+ }
|
|
|
+ throw std::runtime_error("Handler ID not found");
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ std::vector<HandlerEntry> handlers;
|
|
|
+ IdGen idGen;
|
|
|
+};
|
|
|
+
|
|
|
+// The main dispatcher
|
|
|
+class EventDispatcher {
|
|
|
+public:
|
|
|
+ // Main template: add handler as std::function
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ size_t addHandler(EventType eventType, std::function<Ret(Args...)> handler) {
|
|
|
+ auto key = std::make_pair(eventType, std::type_index(typeid(EventHandlerList<Ret, Args...>)));
|
|
|
+ auto& ptr = handlers[key];
|
|
|
+ if (!ptr) {
|
|
|
+ ptr.reset(new EventHandlerList<Ret, Args...>());
|
|
|
+ }
|
|
|
+ auto* list = static_cast<EventHandlerList<Ret, Args...>*>(ptr.get());
|
|
|
+ return list->addHandler(handler);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for free functions
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ size_t addHandler(EventType eventType, Ret(*func)(Args...)) {
|
|
|
+ return addHandler<Ret, Args...>(eventType, std::function<Ret(Args...)>(func));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for non-const member functions
|
|
|
+ template<typename Ret, typename Class, typename... Args>
|
|
|
+ size_t addHandler(EventType eventType, Class* obj, Ret(Class::* memFn)(Args...)) {
|
|
|
+ auto wrapper = [obj, memFn](Args... args) -> Ret {
|
|
|
+ return (obj->*memFn)(args...);
|
|
|
+ };
|
|
|
+ return addHandler<Ret, Args...>(eventType, wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for const member functions
|
|
|
+ template<typename Ret, typename Class, typename... Args>
|
|
|
+ size_t addHandler(EventType eventType, Class* obj, Ret(Class::* memFn)(Args...) const) {
|
|
|
+ auto wrapper = [obj, memFn](Args... args) -> Ret {
|
|
|
+ return (obj->*memFn)(args...);
|
|
|
+ };
|
|
|
+ return addHandler<Ret, Args...>(eventType, wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove handler by ID
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ void removeHandler(EventType eventType, size_t id) {
|
|
|
+ auto key = std::make_pair(eventType, std::type_index(typeid(EventHandlerList<Ret, Args...>)));
|
|
|
+ auto it = handlers.find(key);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = static_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) list->removeHandler(id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Invoke all handlers for an event
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ std::vector<Ret> invokeAll(EventType eventType, Args&&... args) {
|
|
|
+ auto key = std::make_pair(eventType, std::type_index(typeid(EventHandlerList<Ret, Args...>)));
|
|
|
+ auto it = handlers.find(key);
|
|
|
+ // auto it = handlers.find(eventType);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = static_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) return list->invokeAll(std::forward<Args>(args)...);
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+
|
|
|
+ // Invoke a handler by ID
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ Ret invokeById(EventType eventType, size_t id, Args&&... args) {
|
|
|
+ auto key = std::make_pair(eventType, std::type_index(typeid(EventHandlerList<Ret, Args...>)));
|
|
|
+ auto it = handlers.find(key);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = static_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) return list->invokeById(id, std::forward<Args>(args)...);
|
|
|
+ }
|
|
|
+ throw std::runtime_error("Handler or event not found");
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ using HandlerKey = std::pair<EventType, std::type_index>;
|
|
|
+ std::map<HandlerKey, std::unique_ptr<IEventHandlerList>> handlers;
|
|
|
+};
|
|
|
+
|
|
|
+// Example class for reference parameter/return
|
|
|
+struct MyWidget {
|
|
|
+ int value = 42;
|
|
|
+ int memberFunc(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "MyWidget::memberFunc called: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return value + a;
|
|
|
+ }
|
|
|
+ bool onRedraw(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "Redraw: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ int constMember(int a, bool, const char*, MyWidget&) const {
|
|
|
+ std::cout << "constMember: " << a << std::endl;
|
|
|
+ return a + 100;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+bool freeHandler(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ ref.value = 32;
|
|
|
+ std::cout << "freeHandler: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return a > 0;
|
|
|
+}
|
|
|
+
|
|
|
+int main() {
|
|
|
+ EventDispatcher dispatcher;
|
|
|
+ MyWidget widget, refWidget;
|
|
|
+
|
|
|
+ // Lambda handler returning bool
|
|
|
+ auto id1 = dispatcher.addHandler<bool, int, bool, const char*, MyWidget&>(
|
|
|
+ EventType::ButtonClick,
|
|
|
+ [](int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "Lambda handler: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Free function handler
|
|
|
+ auto id2 = dispatcher.addHandler(EventType::ButtonClick, freeHandler);
|
|
|
+
|
|
|
+ // Member function handler (non-const)
|
|
|
+ auto id3 = dispatcher.addHandler(EventType::ButtonClick, &widget, &MyWidget::onRedraw);
|
|
|
+
|
|
|
+ // Member function handler (const)
|
|
|
+ auto id4 = dispatcher.addHandler(EventType::Hover, &widget, &MyWidget::constMember);
|
|
|
+
|
|
|
+ // Lambda handler returning int
|
|
|
+ auto id5 = dispatcher.addHandler<int, int, bool, const char*,
|
|
|
+ MyWidget&>(EventType::Hover, [](int a, bool, const char*, MyWidget&) {
|
|
|
+ std::cout << "Hover handler: " << a << std::endl;
|
|
|
+ return a + 10;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Member function handler returning int (non-const)
|
|
|
+ auto id6 = dispatcher.addHandler(EventType::Hover, &widget, &MyWidget::memberFunc);
|
|
|
+
|
|
|
+ // Lambda handler returning const char*
|
|
|
+ auto id7 = dispatcher.addHandler<const char*, int, bool, const char*, MyWidget&>(
|
|
|
+ EventType::Redraw,
|
|
|
+ [](int, bool, const char*, MyWidget&) {
|
|
|
+ return "Redraw done";
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Call all buttonClick handlers
|
|
|
+ std::cout << "\nInvoking all buttonClick with return bool and argument (int, bool, const char*) handlers:\n";
|
|
|
+ auto results = dispatcher.invokeAll<bool>(
|
|
|
+ EventType::ButtonClick, 5, true, "OK", refWidget);
|
|
|
+ for (auto r : results) std::cout << "Result: " << std::boolalpha << r << std::endl;
|
|
|
+
|
|
|
+ std::cout << "\nInvoking all with return int and argument (int bool const char*) handlers:\n";
|
|
|
+ auto hoverResults = dispatcher.invokeAll<int, int, bool, const char*, MyWidget&>(EventType::Hover, 7, true, "Hovering", refWidget);
|
|
|
+ for (auto r : hoverResults) std::cout << "Hover result: " << r << std::endl;
|
|
|
+
|
|
|
+
|
|
|
+ // Call a specific handler by ID
|
|
|
+ std::cout << "\nInvoke buttonClick by id3:\n";
|
|
|
+ bool res = dispatcher.invokeById<bool, int, bool, const char*, MyWidget&>(EventType::ButtonClick, id3, 2, false, "Cancel", refWidget);
|
|
|
+ std::cout << "Result: " << std::boolalpha << res << std::endl;
|
|
|
+
|
|
|
+
|
|
|
+ // Call redraw handler (returns const char*)
|
|
|
+ std::cout << "\nInvoking all redraw handlers:\n";
|
|
|
+ auto redrawResults = dispatcher.invokeAll<const char*, int, bool, const char*, MyWidget&>(EventType::Redraw, 1, false, "Redraw", refWidget);
|
|
|
+ for (auto r : redrawResults) std::cout << "Redraw result: " << r << std::endl;
|
|
|
+
|
|
|
+ // Remove a handler and show it's gone
|
|
|
+ dispatcher.removeHandler<bool, int, bool, const char*, MyWidget&>(EventType::ButtonClick, id1);
|
|
|
+ std::cout << "\nAfter removing lambda handler (id1):\n";
|
|
|
+ auto results2 = dispatcher.invokeAll<bool, int, bool, const char*, MyWidget&>(EventType::ButtonClick, 9, false, "Bye", refWidget);
|
|
|
+ for (auto r : results2) std::cout << "Result: " << std::boolalpha << r << std::endl;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+#if 0
|
|
|
+
|
|
|
+// Helper for unique handler IDs
|
|
|
+class IdGen {
|
|
|
+ size_t current = 0;
|
|
|
+public:
|
|
|
+ size_t next() { return ++current; }
|
|
|
+};
|
|
|
+
|
|
|
+// Type-erased base for handler lists
|
|
|
+struct IEventHandlerList {
|
|
|
+ virtual ~IEventHandlerList() {}
|
|
|
+};
|
|
|
+
|
|
|
+// Templated handler list for a given signature
|
|
|
+template<typename Ret, typename... Args>
|
|
|
+class EventHandlerList : public IEventHandlerList {
|
|
|
+public:
|
|
|
+ using HandlerType = std::function<Ret(Args...)>;
|
|
|
+ struct HandlerEntry {
|
|
|
+ size_t id;
|
|
|
+ HandlerType handler;
|
|
|
+ };
|
|
|
+
|
|
|
+ size_t addHandler(const HandlerType& h) {
|
|
|
+ size_t id = idGen.next();
|
|
|
+ handlers.push_back({ id, h });
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+
|
|
|
+ void removeHandler(size_t id) {
|
|
|
+ handlers.erase(std::remove_if(handlers.begin(), handlers.end(),
|
|
|
+ [id](const HandlerEntry& e) { return e.id == id; }), handlers.end());
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<Ret> invokeAll(Args... args) {
|
|
|
+ std::vector<Ret> results;
|
|
|
+ for (auto& entry : handlers) {
|
|
|
+ results.push_back(entry.handler(args...));
|
|
|
+ }
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ret invokeById(size_t id, Args... args) {
|
|
|
+ for (auto& entry : handlers) {
|
|
|
+ if (entry.id == id)
|
|
|
+ return entry.handler(args...);
|
|
|
+ }
|
|
|
+ throw std::runtime_error("Handler ID not found");
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ std::vector<HandlerEntry> handlers;
|
|
|
+ IdGen idGen;
|
|
|
+};
|
|
|
+
|
|
|
+// The main dispatcher
|
|
|
+class EventDispatcher {
|
|
|
+public:
|
|
|
+ // Main template: add handler as std::function
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ size_t addHandler(const std::string& eventName, std::function<Ret(Args...)> handler) {
|
|
|
+ auto& ptr = handlers[eventName];
|
|
|
+ if (!ptr) {
|
|
|
+ ptr.reset(new EventHandlerList<Ret, Args...>());
|
|
|
+ }
|
|
|
+ auto* list = dynamic_cast<EventHandlerList<Ret, Args...>*>(ptr.get());
|
|
|
+ if (!list) throw std::runtime_error("Event signature mismatch");
|
|
|
+ return list->addHandler(handler);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for free functions
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ size_t addHandler(const std::string& eventName, Ret(*func)(Args...)) {
|
|
|
+ return addHandler<Ret, Args...>(eventName, std::function<Ret(Args...)>(func));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for non-const member functions
|
|
|
+ template<typename Ret, typename Class, typename... Args>
|
|
|
+ size_t addHandler(const std::string& eventName, Class* obj, Ret(Class::* memFn)(Args...)) {
|
|
|
+ auto wrapper = [obj, memFn](Args... args) -> Ret {
|
|
|
+ return (obj->*memFn)(args...);
|
|
|
+ };
|
|
|
+ return addHandler<Ret, Args...>(eventName, wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Overload for const member functions
|
|
|
+ template<typename Ret, typename Class, typename... Args>
|
|
|
+ size_t addHandler(const std::string& eventName, Class* obj, Ret(Class::* memFn)(Args...) const) {
|
|
|
+ auto wrapper = [obj, memFn](Args... args) -> Ret {
|
|
|
+ return (obj->*memFn)(args...);
|
|
|
+ };
|
|
|
+ return addHandler<Ret, Args...>(eventName, wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove handler by ID
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ void removeHandler(const std::string& eventName, size_t id) {
|
|
|
+ auto it = handlers.find(eventName);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = dynamic_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) list->removeHandler(id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Invoke all handlers for an event
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ std::vector<Ret> invokeAll(const std::string& eventName, Args... args) {
|
|
|
+ auto it = handlers.find(eventName);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = dynamic_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) return list->invokeAll(args...);
|
|
|
+ }
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+
|
|
|
+ // Invoke a handler by ID
|
|
|
+ template<typename Ret, typename... Args>
|
|
|
+ Ret invokeById(const std::string& eventName, size_t id, Args... args) {
|
|
|
+ auto it = handlers.find(eventName);
|
|
|
+ if (it != handlers.end()) {
|
|
|
+ auto* list = dynamic_cast<EventHandlerList<Ret, Args...>*>(it->second.get());
|
|
|
+ if (list) return list->invokeById(id, args...);
|
|
|
+ }
|
|
|
+ throw std::runtime_error("Handler or event not found");
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ std::map<std::string, std::unique_ptr<IEventHandlerList>> handlers;
|
|
|
+};
|
|
|
+
|
|
|
+// Example class for reference parameter/return
|
|
|
+struct MyWidget {
|
|
|
+ int value = 42;
|
|
|
+ int memberFunc(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "MyWidget::memberFunc called: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return value + a;
|
|
|
+ }
|
|
|
+ bool onRedraw(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "Redraw: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ int constMember(int a, bool, const char*, MyWidget&) const {
|
|
|
+ std::cout << "constMember: " << a << std::endl;
|
|
|
+ return a + 100;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+bool freeHandler(int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "freeHandler: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return a > 0;
|
|
|
+}
|
|
|
+
|
|
|
+int main() {
|
|
|
+ EventDispatcher dispatcher;
|
|
|
+ MyWidget widget, refWidget;
|
|
|
+
|
|
|
+ // Lambda handler returning bool
|
|
|
+ auto id1 = dispatcher.addHandler<bool, int, bool, const char*, MyWidget&>(
|
|
|
+ "buttonClick",
|
|
|
+ [](int a, bool b, const char* s, MyWidget& ref) {
|
|
|
+ std::cout << "Lambda handler: " << a << ", " << b << ", " << s << ", ref.value=" << ref.value << std::endl;
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Free function handler
|
|
|
+ auto id2 = dispatcher.addHandler("buttonClick", freeHandler);
|
|
|
+
|
|
|
+ // Member function handler (non-const)
|
|
|
+ auto id3 = dispatcher.addHandler("buttonClick", &widget, &MyWidget::onRedraw);
|
|
|
+
|
|
|
+ // Member function handler (const)
|
|
|
+ auto id4 = dispatcher.addHandler("hover", &widget, &MyWidget::constMember);
|
|
|
+
|
|
|
+ // Lambda handler returning int
|
|
|
+ auto id5 = dispatcher.addHandler<int, int, bool, const char*, MyWidget&>(
|
|
|
+ "hover",
|
|
|
+ [](int a, bool, const char*, MyWidget&) {
|
|
|
+ std::cout << "Hover handler: " << a << std::endl;
|
|
|
+ return a + 10;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Member function handler returning int (non-const)
|
|
|
+ auto id6 = dispatcher.addHandler("hover", &widget, &MyWidget::memberFunc);
|
|
|
+
|
|
|
+ // Lambda handler returning const char*
|
|
|
+ auto id7 = dispatcher.addHandler<const char*, int, bool, const char*, MyWidget&>(
|
|
|
+ "redraw",
|
|
|
+ [](int, bool, const char*, MyWidget&) {
|
|
|
+ return "Redraw done";
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // Call all buttonClick handlers
|
|
|
+ std::cout << "\nInvoking all buttonClick handlers:\n";
|
|
|
+ auto results = dispatcher.invokeAll<bool, int, bool, const char*, MyWidget&>("buttonClick", 5, true, "OK", refWidget);
|
|
|
+ for (auto r : results) std::cout << "Result: " << std::boolalpha << r << std::endl;
|
|
|
+
|
|
|
+ // Call a specific handler by ID
|
|
|
+ std::cout << "\nInvoke buttonClick by id3:\n";
|
|
|
+ bool res = dispatcher.invokeById<bool, int, bool, const char*, MyWidget&>("buttonClick", id3, 2, false, "Cancel", refWidget);
|
|
|
+ std::cout << "Result: " << std::boolalpha << res << std::endl;
|
|
|
+
|
|
|
+ auto hoverResults = dispatcher.invokeAll<int, int, bool, const char*, MyWidget&>("hover", 7, true, "Hovering", refWidget);
|
|
|
+ for (auto r : hoverResults) std::cout << "Hover result: " << r << std::endl;
|
|
|
+
|
|
|
+ // Call redraw handler (returns const char*)
|
|
|
+ std::cout << "\nInvoking all redraw handlers:\n";
|
|
|
+ auto redrawResults = dispatcher.invokeAll<const char*, int, bool, const char*, MyWidget&>("redraw", 1, false, "Redraw", refWidget);
|
|
|
+ for (auto r : redrawResults) std::cout << "Redraw result: " << r << std::endl;
|
|
|
+
|
|
|
+ // Remove a handler and show it's gone
|
|
|
+ dispatcher.removeHandler<bool, int, bool, const char*, MyWidget&>("buttonClick", id1);
|
|
|
+ std::cout << "\nAfter removing lambda handler (id1):\n";
|
|
|
+ auto results2 = dispatcher.invokeAll<bool, int, bool, const char*, MyWidget&>("buttonClick", 9, false, "Bye", refWidget);
|
|
|
+ for (auto r : results2) std::cout << "Result: " << std::boolalpha << r << std::endl;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|