forked from bkinnightskytw/event_transformer
Compare commits
2 Commits
feat/type_
...
main
Author | SHA1 | Date |
---|---|---|
|
d5dc22a0de | |
|
637ada816f |
66
README.md
66
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -155,4 +155,4 @@ std::any 也可以做到? [std any use case](https://zh-blog.logan.tw/2021/10/
|
|||
> 另外沒有exception 也能用 -fno-exception
|
||||
|
||||
以上這些鬼方法,implement 後,應該要藏在最底層的 base class,user 才能直接用,叫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。
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
{};
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue