Compare commits

..

3 Commits

5 changed files with 99 additions and 156 deletions

View File

@ -2,9 +2,71 @@
Simple utility lib to be interface of event system and simplify transform between different evet lib.
> deprecated, it seems impossible.
Current implementation require you to define(override) all the event specific dispatch function. If implement lack, you won't pass though compiler.
It seems dynamic reflection is necessary for implementation, but C++ have no this feature.
> The original goal of this project is ability to override all event behavior by 1 meta function.
>
> However, it seems dynamic reflection is necessary for implementation, but C++ have no this feature therefore impossible to achieve.
```cpp
#include <event_transformer.h>
#include <so_5/all.hpp>
struct AEvent
{
double speed; // parameter of event
};
struct BEvent
{};
/**
* @brief
* as an interface for fake module process
*/
class Fake_module_process_ev : virtual public EventList<AEvent, BEvent>
{}; // end of Fake_module_process_ev
/**
* @brief
* real implement
*/
// template<typename Functor>
class So5_fake_module_process_ev : virtual public Fake_module_process_ev
{
so_5::mbox_t target;
public:
So5_fake_module_process_ev(so_5::mbox_t target_) : target(target_)
{
}
void dispatch(const AEvent& evt) override
{
cout << "handling AEvent" << endl;
so_5::send<AEvent>(target, evt);
}
void dispatch(const BEvent& evt) override
{
cout << "handling BEvent" << endl;
so_5::send<BEvent>(target, evt);
}
};
void fake_module_process(Fake_module_process_ev* evt_li_ptr)
{
// ...
dispatch(evt_li_ptr, a_ev);
// ...
}
```
## build
```bash
conan build . --build=missing
```
## ref

View File

@ -32,10 +32,10 @@ class event_transformerRecipe(ConanFile):
# test
self.test_requires("gtest/[~1.13]")
self.test_requires("sobjectizer/[~5.8]")
self.test_requires("eventpp/[~0.1]")
self.test_requires("sigslot/[~1.2]")
self.test_requires("caf/[~0.19]")
self.test_requires("spdlog/[~1.13]")
# self.test_requires("eventpp/[~0.1]")
# self.test_requires("sigslot/[~1.2]")
# self.test_requires("caf/[~0.19]")
# self.test_requires("spdlog/[~1.13]")
def validate(self):
check_min_cppstd(self, "17")

View File

@ -155,4 +155,4 @@ std::any 也可以做到? [std any use case](https://zh-blog.logan.tw/2021/10/
> 另外沒有exception 也能用 -fno-exception
以上這些鬼方法implement 後,應該要藏在最底層的 base classuser 才能直接用叫user implement 根本要死。但是一放在底層又變ambiguous。要把pointer cast 回它的最底層,才能正確的呼叫使用 map 的 dispatch function。原lib 也有 ` static_cast<EventListener<Event>*>(listener)->onEvent(evt);`。這就顯示出了map based implement 方法和 inherit based 方法本來就不同,如何合併? 而且本來的inherit implement 就需要一個helper 去幫call。
可能的方法是,要有 helper class先在最底層的function找看看map 有沒有已經存值,沒有了話就 static cast 到對應的type並且calling。
可能的方法是,要有 helper class先在最底層的function找看看map 有沒有已經存值,沒有了話就 static cast 到對應的type並且calling。

View File

@ -1,90 +1,41 @@
#pragma once
#include <any>
#include <functional>
#include <map>
#include <typeindex>
#include <typeinfo>
using namespace std;
/**
* @details
* variadic template + template specialization
*/
template<class... EventTypes>
class EventList
{
// no function here will be expose to outer.
// void hello()
// {
// printf("hello");
// }
};
class EventList;
/**
* base of EventList
*/
template<>
class EventList<>
{
public:
template<typename EvntLists, typename EVT>
friend void dispatch(EvntLists* evnt_list_ptr, EVT evt);
/**
* @todo create templated setting functor meta function.
*/
template<typename EvntLists, template<typename Ty> class FunctorT, typename EVT>
friend void set_meta(EvntLists* evnt_list_ptr);
// protected:
// std::optional
std::map<std::type_index, std::any> fmap;
template<typename EvntLists, typename EVT>
friend void dispatch(EvntLists evnt_list, EVT evt);
};
// class Dispatcher
// {
// Dispatcher(Event)
// };
template<typename EvntLists, typename EVT>
void
dispatch(EvntLists* evnt_list_ptr, EVT evt)
{
auto base = static_cast<EventList<>*>(evnt_list_ptr); //->dispatch(evt);
auto any_func = base->fmap.at(std::type_index(typeid(EVT)));
if (any_func.has_value()) {
auto func = std::any_cast<std::function<void(EVT&)>>(any_func);
func(evt); // dispatch
return;
}
// else, call its own private dispatch function.
dynamic_cast<EventList<EVT>*>(evnt_list_ptr)->dispatch(evt); // error: 'EventList<>' is not polymorphic, so I need to
// create seperate func.
static_cast<EventList<EVT>*>(evnt_list_ptr)->dispatch(evt);
}
template<typename EvntLists, template<typename Ty> class FunctorT, typename EVT>
template<typename EvntLists, typename EVT>
void
set_meta(EvntLists* evnt_list_ptr)
dispatch(EvntLists evnt_list, EVT evt)
{
printf("set meta called\n");
auto base = static_cast<EventList<>*>(evnt_list_ptr);
base->fmap.at(std::type_index(typeid(EVT))) = FunctorT<EVT>();
static_cast<EventList<EVT>&>(evnt_list).dispatch(evt);
}
/**
* The second event list, connect between event and base
* @todo addition type but without trigger ambiguous error.
*/
template<class Event>
class EventList<Event> : public virtual EventList<>
{
public:
EventList<Event>()
{
printf("normal constructor called\n");
fmap.insert(std::pair<std::type_index, std::any>(std::type_index(typeid(Event)), std::any()));
// auto any_func = fmap.at(std::type_index(typeid(Event)));
// printf("any val:%d\n", any_func.has_value());
}
virtual void dispatch(const Event&){}; //=0
virtual void dispatch(const Event&) = 0;
// virtual void dispatch(Event&)
// {
// cout << "default cb\n";
@ -95,41 +46,9 @@ public:
// };
};
/**
* intermediate, and hierachy
*/
template<class Event, class... Others>
class EventList<Event, Others...>
: public EventList<Event>
, public EventList<Others...>
{
// EventList<Event, Others...>()
// {
// printf("intermediate constructor called\n");
// }
};
/************************************************/
template<template<typename Event> class FunctorT, class Event>
class EventList<FunctorT<Event>, Event> : public virtual EventList<>
{
public:
EventList<FunctorT<Event>, Event>()
{
printf("constructor with functor\n");
set_meta<EventList<FunctorT<Event>, Event>, FunctorT, Event>(this);
}
};
template<template<typename Ty> class FunctorT, class Event, class... Others>
class EventList<FunctorT<Event>, Event, Others...>
: public EventList<FunctorT<Event>, Event>
, public EventList<Others...>
{
public:
EventList<FunctorT<Event>, Event, Others...>()
{
printf("outer, constructor with functor\n");
}
};
{};

View File

@ -21,7 +21,6 @@ using namespace ::testing;
/**
* original required by `events` lib
* Primary template.
*/
class BaseEvent
{};
@ -58,9 +57,6 @@ class Foo_pp : public Foo
public:
// for c++ 17
/**
* if cast back to Foo, template function will disapear.
*/
template<typename EVT>
void dispatch(EVT evt)
{
@ -84,6 +80,7 @@ TEST_F(Evt_trans_test, create_test)
// static_cast<EventList<AEvent>>(foo).dispatch(a_ev);
// static_cast<Foo>(foo).dispatch(a_ev);
static_cast<EventList<AEvent>&>(foo).dispatch(a_ev);
dispatch(foo, a_ev);
static_cast<EventList<BEvent>&>(foo).dispatch(b_ev);
// foo.dispatch(a_ev);
foo.dispatch(std::ref(a_ev));
@ -101,50 +98,46 @@ TEST_F(Evt_trans_test, create_test)
#include <typeinfo>
/**
* @details
* I want this be interface only.
* @todo require a dynamic map to map from rtti typeinfo to coresponding function
* @brief
* as an interface for fake module process
*/
class Fake_module_process_ev : virtual public EventList<AEvent, BEvent>
{}; // Fake_module_process_ev
{}; // end of Fake_module_process_ev
/**
* friend `dispatch(foo, a_event);` `foo.dispatch(a_event);`
*/
/**
* I wan't this be implement.
*
* @brief
* real implement
*/
// template<typename Functor>
class So5_fake_module_process_ev : virtual public Fake_module_process_ev
{
using EventList<AEvent>::dispatch; // to disable warning
so_5::mbox_t target;
public:
So5_fake_module_process_ev(so_5::mbox_t target_)
: target(target_)
{
using namespace std;
// iterate over all the inherit class and generate function from functor.
//
std::function<void(AEvent&)> func = [this](AEvent& evt) -> void {
// so_5::send<AEvent>(target, evt.speed); //both work, but this isn't
so_5::send<AEvent>(target, evt);
};
fmap[type_index(typeid(AEvent))] = std::any(func);
// Functor<>;
}
void dispatch(const AEvent& evt) override
{
cout << "handling AEvent" << endl;
so_5::send<AEvent>(target, evt);
}
void dispatch(const BEvent& evt) override
{
std::cout << "So5_fake is handling BEvent" << endl;
cout << "handling BEvent" << endl;
so_5::send<BEvent>(target, evt);
}
};
/**
* simulate module process which require event interface but hide implement.
* simulate module process which require event interface
*/
void
fake_module_process(Fake_module_process_ev* evt_li_ptr)
@ -153,13 +146,9 @@ fake_module_process(Fake_module_process_ev* evt_li_ptr)
std::cout << "fake module called\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
const AEvent a_ev = AEvent{ .speed = 5.0 };
// static_cast<EventList<>*>(evt_li_ptr)->dispatch(a_ev);
// static_cast<EventList<>*>(evt_li_ptr)->dispatch(a_ev);
// evt_li_ptr->ev_dispatch(a_ev);
// static_cast<EventList<decltype(a_ev)>&>(*evt_li_ptr).dispatch(a_ev);
// evt_li_ptr->dispatch(std::ref(a_ev));
// static_cast<EventList<AEvent>&>(*evt_li_ptr).dispatch(a_ev);
dispatch(evt_li_ptr, a_ev);
const BEvent b_ev = BEvent();
dispatch(evt_li_ptr, b_ev);
std::cout << "fake module exist\n";
//
}
@ -169,7 +158,7 @@ class pinger final : public so_5::agent_t
void on_pong(mhood_t<AEvent> cmd)
{
std::cout << "actor pinger: received a A event, speed: " << cmd->speed << ".\n";
std::cout << "actor pinger: received a A event\n";
}
public:
@ -208,31 +197,4 @@ TEST_F(Evt_trans_test, so5_fake_module_test)
env.stop();
}); // end of so5 launch
}
/********************************************************************************************************/
template<typename Evt>
class Test
{
public:
void operator()(void)
{
cout << "empty test\n";
};
};
class Functor_fake_module_process_ev : virtual public Fake_module_process_ev
{
public:
Functor_fake_module_process_ev()
{
EventList<Test<AEvent>, AEvent, BEvent>(); //.fmap
};
};
TEST(testCase, functor_test)
{
auto t = Functor_fake_module_process_ev();
}
}