Coder Social home page Coder Social logo

wqking / eventpp Goto Github PK

View Code? Open in Web Editor NEW
1.2K 54.0 207.0 869 KB

Event Dispatcher and callback list for C++

License: Other

C++ 99.03% CMake 0.47% Makefile 0.43% C 0.07%
header-only event-dispatcher callback signal slot observer-pattern publish-subscribe thread-safe nested-events cpp11

eventpp's People

Contributors

cnnblike avatar devbharat avatar marscatxdu avatar mpiccolino-tealblue avatar olivierldff avatar rotolof avatar sr-tream avatar wqking avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eventpp's Issues

EventQueue是异步的吗?/Is EventQueue asynchronous?

我在我的代码中使用了eventpp的EventQueue接收来自其他线程的一系列事件:
我的理解是当调用EventQueue的enqueue方法以后,其他线程就可以继续添加新的事件了
但是从现象来看,一旦某一个任务没有处理完成,线程似乎就会阻塞
请问是我的用法有问题吗?

I'm using eventpp's EventQueue in my code to receive a series of events from other threads:
My understanding is that after calling the enqueue method of EventQueue, other threads can continue to add new events
But from the phenomenon, once a certain task is not processed, the thread seems to be blocked
Is there a problem with my usage?

Problems with object slicing

I roughly have the following setup with names changed:

// a.h

enum class UpdateType { MeasurementUpdate, HealthUpdate };

// wrapper for listener with argument adapter
template <typename Params>
  eventpp::EventQueue<UpdateType, void(const Update&)>::Handle
  RegisterEventListener(const UpdateType& event_type,
                        std::function<Params>& callback) {
    return unified_event_queue_.appendListener(
        event_type, eventpp::argumentAdapter<Params>(callback));
  }

class Update {
  public:
    Update() {
    }

    virtual ~Update() {
    }
};

class Status : public Update {
 public:
  explicit Status(const A a, const B b, const C c)
      : a {a},
        b {b},
        c {c} {}

  A GetA() const {
    return a;
  }

  B GetB() const {
    return b;
  }

  C GetC() const {
    return c;
  }
 private:
  A a;
  B b;
  C c;
}

eventpp::EventQueue<UpdateType, void(const Update&)> unified_event_queue_;

I'm enqueueing with

// a.cc
A a {/* data I know about */};
B b {/* data I know about */};
C c {/* data I know about */};
unified_event_queue_.enqueue(
        UpdateType::MeasurementUpdate,
        Status(a, b, c));

and i've registered listeners with

// b.cc in a method of a class
std::function<void(const Status&)> status_f {
        [this](const auto& e) {
          this->CheckABC(e);
        }};
RegisterEventListener(UpdateType::MeasurementUpdate,
                                   status_f);

void CheckABC(const Status& status) {
  const auto a {status.GetA()};
  const auto b {status.GetB()};
  ...
}

when I check the attributes of status, I think that status has been sliced because the data I knew about is now no longer there when I call GetA() etc. My question is, where might this be happening? I've tried not to accidentally use anything but a reference, and I imagine that a dynamic cast is going on under the hood. I'm using unified_event_queue_.process() to dispatch. Would prefer not to use a pointer if I don't have to

maybe a typo in argumentadapter.md document

each event type has its own event class, such as a mouseDown event has MouseDown event class.

I think the word should be:

each event type has its own event class, such as a mouseDown event type has MouseDown event class.

Am I correct?

Thanks.

Run unittest failed

Runtime environment

ubuntu 22.04
gcc 11.3
Catch v2.13.9

Building process

cd xxx/eventpp/tests/build
cmake ..
make linux
cd unittest
make
./unittest

Result

image

After I commented out all test_callbacklist_multithread.cpp, the unittest passed.

EventDispatcher - detect no listeners

I'd like to be able to handle the scenario where there are no listeners for an event. In my specific case, I want to provide a default handler if there is not one. Is there already a mechanism to determine if dispatch() did nothing?

Perhaps dispatch() could return the listener count?

Typo readme.md

Hi, maybe I am missing something here, but should't there be queue instead of dispatcher?


dispatcher.appendListener(3, [](const std::string s, bool b) {
	std::cout << std::boolalpha << "Got event 3, s is " << s << " b is " << b << std::endl;
});
dispatcher.appendListener(5, [](const std::string s, bool b) {
	std::cout << std::boolalpha << "Got event 5, s is " << s << " b is " << b << std::endl;
});

// The listeners are not triggered during enqueue.
queue.enqueue(3, "Hello", true);
queue.enqueue(5, "World", false);

// Process the event queue, dispatch all queued events.
queue.process();

CallbackList move assignement operator create memory leak

The operator CallbackListBase & operator = (CallbackListBase && other) only release head and tail.

  • If there is one callback, then the node is destroyed.
  • If there is more, then they keep reference between each other and never get destroyed.

I fixed the problem on my fork in a branch move-assignement-fix

Fix in callbacklist.h

	CallbackListBase & operator = (CallbackListBase && other) noexcept {
		if(this != &other) {
			while(head) {
				// Create copy because doFreeNode reset temp->counter
				// after head reassignment.
				auto temp = head;
				doFreeNode(temp);
			}
			head = std::move(other.head);
			tail = std::move(other.tail);
			currentCounter = other.currentCounter.load();
		}
	}

And the unit test demonstrating the problem:

TEST_CASE("CallbackList, move assignement")
{
	using CL = eventpp::CallbackList<void()>;
	CL callbackList;
	const auto h1 = callbackList.append([]() {});
	const auto h2 = callbackList.append([]() {});
	callbackList = {};

	// Make sure nodes were destroyed
	REQUIRE(h1.expired());
	REQUIRE(h2.expired());
}

Would you consider a PR for this?

warning C4100: '<args_0>': unreferenced formal parameter

Hi, I just testing your great-looking library for events but receiving some warnings during compilation.

When I try to compile this minimal test-case:

	eventpp::EventDispatcher<int, void(const std::string &, const bool)> dispatcher;
 	dispatcher.dispatch(3, "Hello", true);
 	dispatcher.dispatch(5, "World", false);

Visual Studio 2017 is reporting the following issues:

1>eventDispatcher.test.cpp
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp\internal/eventpolicies_i.h(163): warning C4100: '<args_2>': unreferenced formal parameter
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp/eventdispatcher.h(225): note: see reference to function template instantiation 'bool eventpp::internal_::ForEachMixins<eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>,eventpp::MixinList<>,eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>::DoMixinBeforeDispatch>::forEach<const eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>*const ,const std::string&,_Ty&>(const eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void> *const &&,const std::string &,_Ty &)' being compiled
1>        with
1>        [
1>            Event_=int,
1>            Prototype_=void (const std::string &,bool),
1>            Policies_=eventpp::DefaultPolicies,
1>            _Ty=bool
1>        ]
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp/eventdispatcher.h(224): note: see reference to function template instantiation 'bool eventpp::internal_::ForEachMixins<eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>,eventpp::MixinList<>,eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>::DoMixinBeforeDispatch>::forEach<const eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>*const ,const std::string&,_Ty&>(const eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void> *const &&,const std::string &,_Ty &)' being compiled
1>        with
1>        [
1>            Event_=int,
1>            Prototype_=void (const std::string &,bool),
1>            Policies_=eventpp::DefaultPolicies,
1>            _Ty=bool
1>        ]
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp/eventdispatcher.h(223): note: while compiling class template member function 'void eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>::doDispatch(const int &,const std::string &,bool) const'
1>        with
1>        [
1>            Event_=int,
1>            Prototype_=void (const std::string &,bool),
1>            Policies_=eventpp::DefaultPolicies
1>        ]
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp/eventdispatcher.h(215): note: see reference to function template instantiation 'void eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>::doDispatch(const int &,const std::string &,bool) const' being compiled
1>        with
1>        [
1>            Event_=int,
1>            Prototype_=void (const std::string &,bool),
1>            Policies_=eventpp::DefaultPolicies
1>        ]
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp/eventdispatcher.h(295): note: see reference to class template instantiation 'eventpp::internal_::EventDispatcherBase<Event_,Prototype_,Policies_,void>' being compiled
1>        with
1>        [
1>            Event_=int,
1>            Prototype_=void (const std::string &,bool),
1>            Policies_=eventpp::DefaultPolicies
1>        ]
1>axEvents\eventDispatcher.test.cpp(37): note: see reference to class template instantiation 'eventpp::EventDispatcher<int,void (const std::string &,bool),eventpp::DefaultPolicies>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(54): note: see reference to class template instantiation 'boost::arg<9>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(53): note: see reference to class template instantiation 'boost::arg<8>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(52): note: see reference to class template instantiation 'boost::arg<7>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(51): note: see reference to class template instantiation 'boost::arg<6>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(50): note: see reference to class template instantiation 'boost::arg<5>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(49): note: see reference to class template instantiation 'boost::arg<4>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(48): note: see reference to class template instantiation 'boost::arg<3>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(47): note: see reference to class template instantiation 'boost::arg<2>' being compiled
1>Q:\SharedLibraries2015\boost32\include\boost/bind/placeholders.hpp(46): note: see reference to class template instantiation 'boost::arg<1>' being compiled
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp\internal/eventpolicies_i.h(163): warning C4100: '<args_1>': unreferenced formal parameter
1>q:\applications\atomixdevelopment\atomixdevelopment\axcore\axevents\eventpp\internal/eventpolicies_i.h(163): warning C4100: '<args_0>': unreferenced formal parameter

Also I'm not sure why complaining about boost::args<> when there is no boost used in the compiled code.

Is there any way how to remove these warnings?

Thanks

Using derived classes in listener prototype causes compile-time error

Steps to reproduce:
compile this code

class Event {
    public: 
        int type;
};

class DerivedEvent : public Event {
    public: 
        int data;
};

struct EventPolicies
{
	static int getEvent(const Event& e) {
		return e.type;
	}
};

void app_main() {
    eventpp::EventDispatcher<int, void (const Event&), EventPolicies> dispatcher;
    dispatcher.appendListener(3, [](const DerivedEvent& e) {
	    std::cout
		    << std::boolalpha
		    << "Event::type is " << e.type << std::endl
	    ;
    });

    DerivedEvent event;
    event.type = 3;
    event.data = 5;
    dispatcher.dispatch(event);
}

Expected behaviour:
Code to be compiled

Actual behaviour:
Got an error

src/main.cpp: In function 'void app_main()':
src/main.cpp:94:6: error: no matching function for call to 'eventpp::EventDispatcher<int, void(const Event&), EventPolicies>::appendListener(int, app_main()::<lambda(const DerivedEvent&)>)'

When I changed in the listener callback prototype [](const DerivedEvent& e) to [](const Event& e) it compiles perfectly. I could create instances of EventDispatcher for each event type, but not sure if it's a good idea.
Is there a possibility to use derived classes in prototype?

assignment operator of eventdispatcher is wrong

Check this at eventdispatcher.h:121

EventDispatcherBase & operator = (const EventDispatcherBase & other)
	{
		eventCallbackListMap = other;
	}

	EventDispatcherBase & operator = (EventDispatcherBase && other) noexcept
	{
		eventCallbackListMap = std::move(other);
	}

and hetereventdispatcher have same error

Inheritance from EventDispatcher doesn't compile

struct MyClass: Class1, EventDispatcher<int, void()> {
etc....
}

generates compilation error

1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2988: unrecognizable template declaration/definition (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(282): note: see reference to class template instantiation 'eventpp::internal_::EventDispatcherBase<EventType,ReturnType(Args...),PoliciesType,MixinRoot_>' being compiled (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2143: syntax error: missing ')' before 'this' (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2143: syntax error: missing ';' before 'this' (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2238: unexpected token(s) preceding ';' (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2059: syntax error: 'this' (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2059: syntax error: ')' (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(262): error C2334: unexpected token(s) preceding ':'; skipping apparent function body (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(30): fatal error C1075: the left brace '{' was unmatched at the end of the file (compiling source file sources\MonaTiny.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2988: unrecognizable template declaration/definition (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(282): note: see reference to class template instantiation 'eventpp::internal_::EventDispatcherBase<EventType,ReturnType(Args...),PoliciesType,MixinRoot_>' being compiled (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2143: syntax error: missing ')' before 'this' (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2143: syntax error: missing ';' before 'this' (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2238: unexpected token(s) preceding ';' (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2059: syntax error: 'this' (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(248): error C2059: syntax error: ')' (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(262): error C2334: unexpected token(s) preceding ':'; skipping apparent function body (compiling source file sources\main.cpp)
1>g:\programming\c++\monaserver2\eventdispatcher\eventpp\include\eventpp\eventdispatcher.h(30): fatal error C1075: the left brace '{' was unmatched at the end of the file (compiling source file sources\main.cpp)

eventpolicies SingleThreading的bug

  1. include/eventpp/callbacklist.h 158行用到了Atomic::exchange method
  2. include/eventpp/eventpolicies.h SingleThreading中的Atomic template未定义此方法

Adding Ci with github actions

I'm adding ci with GH actions with lots of my small project because it's so easy to do.
I tried to add it to eventpp on a branch on my repo. https://github.com/OlivierLDff/eventpp/actions
As you can see tests are not compiling on macOs.

Would you be interested in such a PR? I can also fix compilation error on mac when i will have time.
I think it can be cool to have at least CI for windows/ubuntu in Release

callback can't use std::function?

A event queue type like eventpp::EventQueue<int, std::function<void()>>, can't compile success.

In file included ...
eventpp/include/eventpp/eventqueue.h: In instantiation of ‘class eventpp::EventQueue<int, std::function<void()> >’:
pipeline.cpp:24:53:   required from here
eventpp/include/eventpp/eventqueue.h:482:7: error: invalid use of incomplete type ‘using Type = class eventpp::internal_::EventQueueBase<int, std::function<void()>, eventpp::DefaultPolicies> {aka class eventpp::internal_::EventQueueBase<int, std::function<void()>, eventpp::DefaultPolicies>}’
 class EventQueue : public internal_::InheritMixins<
       ^~~~~~~~~~
In file included ...
eventpp/include/eventpp/eventqueue.h:36:7: note: declaration of ‘using Type = class eventpp::internal_::EventQueueBase<int, std::function<void()>, eventpp::DefaultPolicies> {aka class eventpp::internal_::EventQueueBase<int, std::function<void()>, eventpp::DefaultPolicies>}’
 class EventQueueBase;
       ^~~~~~~~~~~~~~
In file included ...
eventpp/include/eventpp/eventqueue.h:494:15: error: type ‘eventpp::EventQueue<int, std::function<void()> >::super {aka eventpp::internal_::EventQueueBase<int, std::function<void()>, eventpp::DefaultPolicies>}’ is not a base type for type ‘eventpp::EventQueue<int, std::function<void()> >’
  using super::super;

Not compatible with C++11 compiler version?

Dear eventpp developers,
I really love this library, and have used it before in a PC project. Lately I started to work on embedded ARM Linux project where the gcc cross-compiler is set to C++11 standard. No way to upgrade to C++17. To my disappointment, when using eventpp, I am facing compilation problems. I believe they are due to use of fold expressions that only appear in C++17. They do resemble parameter packs (C++11) but not quite the same. Could you please confirm that the problem I am seeing is due to my compiler not supporting C++17? If yes, could you please provide some advice on how I can rewrite the expressions to fit the C++11 standard.
My compiler: arm-none-linux-gnueabi-g++ (Sourcery CodeBench Lite 2014.05-29) 4.8.3 20140320 (prerelease)

My compile errors:

host/bin/arm-none-linux-gnueabi-g++ -g -DDEBUG=1 -O0 -std=c++11 -D__cplusplus=201103L -fmessage-length=0 -DISO_DATE=date -u +'"%Y-%m-%dT%H:%M:%S"' -DGIT_BRANCH="git name-rev --name-only HEAD" -DGIT_REV="git log -1 --pretty=%h" -I../CommandHandlers/src -I../DataLinkCommunicators/src -I../ElvisDataModel/sr
c -I../DriverCommunicators/src -I../ScpiServerCmdsCommunicator/src -I../ClientBaseServerCmdsCommunicators/src -I../../Common/src -I../BAL/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder
/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/CommandHandlers/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achille
s2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/DataLinkCommunicators/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/
ControlLink/ScpiServer/ElvisDataModel/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/DriverCommunicators/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/ScpiServerCmdsCommunicator/src -I/home/maxim
/workspace/elvis/3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/ClientBaseServerCmdsCommunicators/src -I/home/maxim/workspace/elvis/
3.Implementation/Software/FirmwareBuilder/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/../Common/src -I/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder
/build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/BAL/src -I../../IdqCppSdk/logger/src -I../../IdqCppSdk/Util/src -I../../../IdqCppSdk/logger/src -I../../../IdqCppSdk/Util/src
-I../../../IdqCppSdk/eventpp/include -c src/EvtQueue.cpp -o Debug/EvtQueue.o
In file included from ../../../IdqCppSdk/eventpp/include/eventpp/eventdispatcher.h:17:0,
from ../../../IdqCppSdk/eventpp/include/eventpp/eventqueue.h:17,
from src/EvtQueue.h:20,
from src/EvtQueue.cpp:1:
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h: In member function 'void eventpp::internal
::CallbackListBase<ReturnType(Args ...), PoliciesType>::operator()(Args ...) const':
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:260:19: error: expected ',' before '...' token
forEachIf([&args...](Callback & callback) -> bool {
^
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:260:19: error: expected identifier before '...' token
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:260:22: error: parameter packs not expanded with '...':
forEachIf([&args...](Callback & callback) -> bool {
^
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:260:22: note: 'args'
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h: In lambda function:
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:261:17: error: expansion pattern 'args' contains no argument packs
callback(args...);
^
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:262:56: error: expansion pattern 'args' contains no argument packs
return CanContinueInvoking::canContinueInvoking(args...);
^
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h: In instantiation of 'struct eventpp::internal
::CallbackListBase<ReturnType(Args ...), PoliciesType>::operator()(Args ...) const [with PoliciesType = even
tpp::DefaultPolicies; ReturnType = void; Args = {bal::EventType, const std::basic_string<char, std::char_traits, std::allocator >&, std::shared_ptrbal::GeneralArgs}]::lambda2':
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:263:4: required from 'void eventpp::internal
::CallbackListBase<ReturnType(Args ...), PoliciesType>::operator()(Args ...) const [with PoliciesType = even
tpp::DefaultPolicies; ReturnType = void; Args = {bal::EventType, const std::basic_string<char, std::char_traits, std::allocator >&, std::shared_ptrbal::GeneralArgs}]'
../../../IdqCppSdk/eventpp/include/eventpp/eventdispatcher.h:228:47: required from 'void eventpp::internal
::EventDispatcherBase<EventType
, ReturnType(Args ...), Policies
, MixinRoot
>::directDispatch(const Eve
nt&, Args ...) const [with EventType
= bal::EventType; Policies
= eventpp::DefaultPolicies; MixinRoot
= eventpp::internal_::EventQueueBase<bal::EventType, void(bal::EventType, const std::basic_string&, st
d::shared_ptrbal::GeneralArgs), eventpp::DefaultPolicies>; ReturnType = void; Args = {bal::EventType, const std::basic_string<char, std::char_traits, std::allocator >&, std::shared_ptr<bal::GeneralAr
gs>}; eventpp::internal_::EventDispatcherBase<EventType_, ReturnType(Args ...), Policies_, MixinRoot_>::Event = bal::EventType]'
../../../IdqCppSdk/eventpp/include/eventpp/eventqueue.h:411:3: required from 'void eventpp::internal_::EventQueueBase<EventType_, ReturnType(Args ...), Policies_>::doDispatchQueuedEvent(T&&, eventpp::internal_::
IndexSequence<Indexes ...>) [with T = eventpp::internal_::EventQueueBase<bal::EventType, void(bal::EventType, const std::basic_string&, std::shared_ptrbal::GeneralArgs), eventpp::DefaultPolicies>::QueuedEv
ent_&; unsigned int ...Indexes = {0u, 1u, 2u}; EventType_ = bal::EventType; Policies_ = eventpp::DefaultPolicies; ReturnType = void; Args = {bal::EventType, const std::basic_string<char, std::char_traits, st
d::allocator >&, std::shared_ptrbal::GeneralArgs}]'
../../../IdqCppSdk/eventpp/include/eventpp/eventqueue.h:259:5: required from 'bool eventpp::internal_::EventQueueBase<EventType_, ReturnType(Args ...), Policies_>::processOne() [with EventType_ = bal::EventType;
Policies_ = eventpp::DefaultPolicies; ReturnType = void; Args = {bal::EventType, const std::basic_string<char, std::char_traits, std::allocator >&, std::shared_ptrbal::GeneralArgs}]'
src/EvtQueue.cpp:54:27: required from here
../../../IdqCppSdk/eventpp/include/eventpp/callbacklist.h:260:15: error: using invalid field 'eventpp::internal_::CallbackListBase<ReturnType(Args ...), PoliciesType>::operator()(Args ...) const::__lambda2::__args
'
forEachIf([&args...](Callback & callback) -> bool {
^
make[3]: *** [/home/maxim/workspace/elvis/3.Implementation/Software/FirmwareBuilder/_build/buildroot-2019.02.3/achilles2-dev/build/scpi-server-0.1/ControlLink/ScpiServer/../mk/common.mk:104: Debug/EvtQueue.o] Erro
r 1
make[2]: *** [Makefile:9: all] Error 2

New version release (vcpkg)

Hi!

Any plans for a new release soon? It seems like there has been significant development (fixes etc) since version 0.1.2 (June 2022).

We manage our dependencies via vcpkg so cloning the master branch is not a preferred alternative.

Thank you!

Question regarding using handle to remove callback from list

I had two questions regarding use of handles to remove a callback from the callbacklist type.

  1. Is there a simple way to remove the callback from the callbacklist when a certain condition arises within the callback itself? Currently I do it by capturing the handle into the lambda when adding it to the callbacklist, but I was wondering if there was a simpler way for a callback to get its own handle or auto-remove itself. (I know I can use counterRemover but was curious about more complicated logic to remove than just counting call count).
    int l = 0;
    eventpp::CallbackList<void()>::Handle two_shot_handle;
    two_shot_handle = CB_list.append(
        [&l, &two_shot_handle, &CB_list]() {
            static int ctr = 0;
            EXPECT_LT(ctr, 2);  // should not run more than twice
            ctr++;
            l++;

            if (ctr == 2) {
                // unsubscribe with your own handle when a certain condition is met
                // Is there a way to do this without CB_list, or atleast without capturing
                // the handle? like CB_list.remove_self()
                CB_list.remove(two_shot_handle);
            }
        });
  1. Is there an operation that can be done on the handle itself that removes the associated callback from the callbacklist without access to the callbacklist? Something like
int i;
auto handle = CB_list.append([&i](){++i;})

// remove the handle's callback
handle.self_destruct()

Thanks!

eventqueue process_all (or similar)

This is not an actual issue, more of a feature request.

I'm wondering if it would be possible to support an additional process call on the eventqueue similar to boost SPSC: size_type pop(T * ret, size_type size)

The idea would be that for queue:

eventpp::EventQueue<
          EventType,
          void(Event&),
          EventPolicies> {};

your listener could handle:

queue.appendListener(event_type, [](Event* data, size_t count) {
...
});

Producers would still be able to enqueue one at a time.

Dispatch would look something like:

queue.process_all(max_size) where max_size is the largest number of elements possible supplied to the listener callback.

Can you add an extra sample code for the Tutorials of EventDispatcher document

Hi, the document:

eventpp/tutorial_eventdispatcher.md at master · wqking/eventpp

Looks good!

But at the last statement:

Remarks A common situation is an Event class is defined as the base class, all other events derive from Event, and the actual event type is a data member of Event (think QEvent in Qt). To let EventDispatcher knows how to get the event type from class Event, policies (the third template parameter) is used.

So my suggestion is that can you add another example about using the policies?

I see a similar example in this page: eventpp/argumentadapter.md at master · wqking/eventpp

But argument adapter is the second argument of the function appendListener(), while the policy is the third argument.

Thanks.

BTW: I'm not sure, I see your library is the only library which support such policy feature. I mean that for many applications, when signal(event) can have different types, and we have different kinds of callback functions, such as:

void callback1(EventA &e);
void callback2(EventB &e);

The need here is both the above two functions can be added to the single signal/slot dispatcher object, and once a EventA signal happens, the callback1 function will be called, and not callback2. Once a EventB signal happens ,the callback2 function will be called, but not callbak1 function.

Generally, people don't need to use two different dispatcher objects for different event/signal classes, which make the library more flexible!

Cannot append callback

Hello,
I'm sure it is a super simple question, but I cannot handle the syntax. Could you please point out how to pass the instance of member function into it so it just work?

class MySettings
{
public:
...
eventpp::CallbackList<void(void)> AnySettingsUpdated;
}

class cMain : public wxFrame
{
protected:
	void OnAnySeetingsUpdate();

}

MySettings.AnySettingsUpdated.append(&cMain::OnAnySeetingsUpdate);

Which leaves me error:

1>c:\dev_pcn\ocr\code\ocrviaopencvwgui\ocrviaopencvwgui\cmain.cpp(52): error C2664: 'eventpp::internal_::CallbackListBase<Prototype_,Policies_>::Handle_ eventpp::internal_::CallbackListBase<Prototype_,Policies_>::append(const std::function<ReturnType (void)> &)': cannot convert argument 1 from 'void (cdecl cMain::* )(void)' to 'const std::function<ReturnType (void)> &'
1> with
1> [
1> Prototype
=void (void),
1> Policies
=eventpp::DefaultPolicies,
1> ReturnType=void
1> ]
1> and
1> [
1> ReturnType=void
1> ]
1>c:\dev_pcn\ocr\code\ocrviaopencvwgui\ocrviaopencvwgui\cmain.cpp(52): note: Reason: cannot convert from 'void (__cdecl cMain::* )(void)' to 'const std::function<ReturnType (void)>'
1> with
1> [
1> ReturnType=void
1> ]
1>c:\dev_pcn\ocr\code\ocrviaopencvwgui\ocrviaopencvwgui\cmain.cpp(52): note: No constructor could take the source type, or constructor overload resolution was ambiguous

CallbackList tutorial 4, for each couldn't compile

I tried to compile the following code in the tutorial but failed.
`using CL = eventpp::CallbackList<void ()>;
CL callbackList;

// Add some callbacks.
callbackList.append( {
std::cout << "Got callback 1." << std::endl;
});
callbackList.append( {
std::cout << "Got callback 2." << std::endl;
});
callbackList.append( {
std::cout << "Got callback 3." << std::endl;
});

// Now call forEach to remove the second callback
// The forEach callback prototype is void(const CallbackList::Handle & handle, const CallbackList::Callback & callback)
int index = 0;
callbackList.forEach([&callbackList, &index](const CL::Handle & handle, const CL::Callback & callback) {
std::cout << "forEach(Handle, Callback), invoked " << index << std::endl;
if(index == 1) {
callbackList.remove(handle);
std::cout << "forEach(Handle, Callback), removed second callback" << std::endl;
}
++index;
});

// The forEach callback prototype can also be void(const CallbackList::Handle & handle)
callbackList.forEach([&callbackList, &index](const CL::Handle & handle) {
std::cout << "forEach(Handle), invoked" << std::endl;
});

// The forEach callback prototype can also be void(const CallbackList::Callback & callback)
callbackList.forEach([&callbackList, &index](const CL::Callback & callback) {
std::cout << "forEach(Callback), invoked" << std::endl;
});

// Invoke the callback list
// The "Got callback 2" callback should not be triggered.
callbackList();
Errors may happen at // The forEach callback prototype can also be void(const CallbackList::Handle & handle)
callbackList.forEach([&callbackList, &index](const CL::Handle & handle) {
std::cout << "forEach(Handle), invoked" << std::endl;
});`

Got linker error on 32bit target.

At first, I would like to say you Thank you 🙏 because it's a convenient, stable yet lightweight library that's very helpful.
I use the library for an application written for ESP32 platform, it has 32 bit architecture and the linker produces an error, because there is a Node Counter declared and it's typed as uint_64t. After changing its type to uint_32t the linker works fine.
Is there a possibility to choose the type of Node Counter depends on architecture? May be with flags?
Thank you.

Confusion about the parameters of the `eventpp::EventQueue.enqueue`

In the following code:

template <typename T, typename ...A>
auto enqueue(T && first, A ...args) -> typename std::enable_if<sizeof...(A) == sizeof...(Args), void>::type
{
static_assert(super::ArgumentPassingMode::canExcludeEventType, "Enqueuing arguments count doesn't match required (Event type should NOT be included).");
using GetEvent = typename SelectGetEvent<Policies_, EventType_, HasFunctionGetEvent<Policies_, T &&, A...>::value>::Type;
doEnqueue(QueuedEvent{
GetEvent::getEvent(std::forward<T>(first), args...),
QueuedEventArgumentsType(std::forward<A>(args)...)
});
if(doCanProcess()) {
queueListConditionVariable.notify_one();
}
}

Where

auto enqueue(T && first, A ...args)

Why does A... not add universal references, likes A&&....

In my tests, there is extra move and destruct overhead (local variables) if the universal reference is not added. Is there any particular reason for this?

unused parameter 'args'

Hello,

One question, is it appropriate to replace the first line with the second one as shown below?
static auto forEach(const Self * /self/, A && ...args)
//static auto forEach(const Self * /self/, A && ...)
It's line 271 of “eventpp/eventdispatcher.h”.

Seems that, this removes a warning “unused parameter 'args'“ emitted from clang if -Wunused-parameter is on.

Thank you.

Function in CallbackList for removing all callbacks

Hey!

Thank you for this library.

I have a suggestion for a small improvement. In my use case it is quite common to want to remove all callbacks from the CallbackList. I know this can be acheived with the forEach function, but since I see this as a common and simple operation I think it makes sense to provide it as a simple function.

语法问题

大佬 研究你的代码 但是在

template
struct HasTypeCallback {
template
static std::true_type test(typename C::Callback*);

            template<typename C>
            static std::false_type test(...);

            enum {
                value = !!decltype(test<T>(0))()
            };
        };

块看不懂了 尤其是 value = !!decltype(test(0))() 真的很迷

Clang compile error

As below:
eventpp/include/eventpp/eventqueue.h:85:15: error: dependent using declaration resolved to type without 'typename'
[build] using super::Handle;
[build] ^
eventpp/include/eventpp/eventqueue.h:86:15: error: dependent using declaration resolved to type without 'typename'
[build] using super::Callback;
[build] ^

clang version 6.0.0

about the Dispatcher is allocated in a Class

If the Dispatcher is a member of a Class, and the callback function is a member function, and how should I use the appendListener? thanks.

The code below shows this class

Declaration:

class sysEvent_C
{
    private:
        // Define an Event to hold all parameters.
        struct _sysEventStruct{
            int type;
            std::string message;
            int param;
        };

        // Define policies to let the dispatcher knows how to
        // extract the event type.
        struct _sysEventPolicies{
            static int getEvent(const _sysEventStruct & e, bool /*b*/) {
                return e.type;
            }
        };

        eventpp::EventDispatcher< int,
            void (const _sysEventStruct& e, bool b),
            _sysEventPolicies > Dispatcher;

    private:
        void _LED_cbHandler(const _sysEventStruct& e, bool b);
        void _speaker_cbHandler(const _sysEventStruct& e, bool b);

  public:
          void init();
        
};

Definition:

void sysEvent_C::init()
{   
    /// led 
    Dispatcher.appendListener(EventType::LED, _LED_cbHandler);
    /// speaker
    Dispatcher.appendListener(EventType::Speaker, _speaker_cbHandler);
}

the IDE will report

error: invalid use of non-static member function ‘void sysEvent_C::_LED_cbHandler(const sysEvent_C::_sysEventStruct&, bool)’

How can it be improved??

Dispatcher模板类型限定,如何适配任意的事件

看了下参考例子,有点不太理解,

eventpp::EventDispatcher<int, void ()> dispatcher;

就限定死了回调参数类型,那如果回调参数类型是int (int), 是不是还得声明
eventpp::EventDispatcher<int, int(int)> dispatcher;

Thread safety ?

Hi, I stumbled across this library while researching for my own signal/slots implementation.
Unless I missread something the callbacklist class is supposed to support concurrent removal and iteration both from multiple threads and recursively (i.e. the callback removes itself). I might be wrong, but I don't think the current implementation actually does.

The issue I see is actually (kinda) documented in doFreeNode, where it says:

// don't modify node->previous or node->next
// because node may be still used in a loop.

right after modifying the previous/next value of the node before/after the removed one. So while keeping the values in the removed node works in practice I am fairly sure this is a data race if another node is removed concurrently. Consider the following flow of events:

Thread A starts iterating the list
Thread A starts reading nodeX->next and gets interupted after getting part of nodeX->next
Thread B removes the node after nodeX (which in turn updates nodeX->next)
Thread A is resumed and continues reading the rest of nodeX->next which now contains different data.

The result is that ThreadA now has a invalid pointer that might or might not lead to a crash. The root of the problem is that assigning/reading a shared_ptr is neither atomic nor threadsafe (thats why the free standing overloads of std::atomic_load for shared_ptr exist).

Please correct me if I am missing something, but I don't think the algorithm in the current form is actually thread safe (even if it might not manifest in practice).

Issues with Clang (-Wextra)

The project I'm working on currently uses flags -Wall -Wextra -Werror -Wpedantic for compiling. I get unused parameters errors like so:
/home/lemagicien/Development/winter/pawlib/pawlib-source/../../libdeps/libs/include/eventpp/eventpolicies.h:95:43: error: unused parameter 'order' [-Werror,-Wunused-parameter] void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept ^

/home/lemagicien/Development/winter/pawlib/pawlib-source/../../libdeps/libs/include/eventpp/eventpolicies.h:125:43: error: unused parameter 'lock' [-Werror,-Wunused-parameter] void wait(std::unique_lock<std::mutex>& lock, Predicate pred)

Are these intentional or an issue with eventpp? Compiling with Clang 7.0

Crash in winxp

image
image
image
My system is winxp sp3
It looks like there's some problem with std:mutex in winxp?

Heter Dispatchers - why aren't they default?

Hi, firstly let me say that I really like your project 🫠!

I was looking for some event-dispatcher library for C++ and I found this. What I needed though was to be able to subscribe for different types of events and also dispatch different types of events. Your primary API provides only one event type per dispatcher. Of course I can use polymorphism and do the casting in every lambda I pass to the dispatcher but that's a little bit too much work for me 😅

So I was wondering... what was stopping you from making this library... well... more generic?
I made a short code sample that showcases the core functionality of your library but written in a more generic way:

#include <iostream>
#include <functional>
#include <list>
#include <typeindex>
#include <map>

struct Dispatcher
{
    using Listeners = std::list<std::function<void(const void*)>>;
    std::map<std::type_index, Listeners> listenersByType;

    template<typename T>
    void appendListener(const std::function<void(const T&)>& listener)
    {
        listenersByType[std::type_index(typeid(T))].push_back([listener](const auto& msg) {
            const T* concreteMessage = static_cast<const T*>(msg);
            listener(*concreteMessage);
        });
    }

    template<typename T>
    void dispatch(const T& msg)
    {
        const auto& listeners = listenersByType.find(std::type_index(typeid(T)));
        if (listeners != listenersByType.end()) {
            for (auto &listener: listeners->second) {
                listener(&msg);
            }
        }
    }
};

And here is the usage:

struct Message {};

struct MousePressedMsg
{
    int x, y;
};

struct Chicken {};

int main() {

    Dispatcher dispatcher;
    dispatcher.appendListener<MousePressedMsg>([](const auto& msg) {
        std::cout << "Mouse pressed: (" << msg.x << ", " << msg.y << ")" << std::endl;
    });

    dispatcher.appendListener<Message>([](const auto& msg) {
        std::cout << "Some message" << std::endl;
    });

    dispatcher.dispatch(Message{}); // prints "Some message"
    dispatcher.dispatch(MousePressedMsg{10, 20}); // prints "Mouse pressed: (10, 20)"
    dispatcher.dispatch(Chicken{}); // no listener for this type, but no problem

    return 0;
}

And as you can see, I don't need any strange EventPolicies. EventType is just a C++ type. It is a compile-time unique identifier. What's the benefit of having a long enum-list with event types separately?

Also, I can add listener for literally every type and dispatch every type of message.

You said yourself that you are a big fan of observer pattern. And as an author of this library you definitely have much greater knowledge than me in this matter. I am creating this issue to ask a simple, and maybe stupid question (sorry 😟): why isn't your library more generic, like in the example that I provided? Are there some limitations that I have not yet reached in my solution?

run EventQueue tutorial 3, ordered queue failed

PC: win10 64bit

我 clone 了仓库后,编译了 tutorial.exe,执行时提示产生了断言 ,dtor 是空指针

将 EventQueue tutorial 3, ordered queue 测试代码注释后,能跑完剩下的 16 个测试

image

如何实现不定参数调用?

eventpp如何能实现不定参数的回调
类似伪代码

Listen(1, [](int a, const std::string& b){...});
Listen(2, [](int a, int b){...});

Invoke(1, 3, "abc");
Invoke(2, 3, 4);

Compilation error when calling processOne() in ordered Queue sample

Replacing process() with processOne() in the sample code that you provided for OrderedQueueList, will cause a compilation error.

The code:


#include <iostream>
#include "eventpp/eventqueue.h"
#include "eventpp/utilities/orderedqueuelist.h"
struct MyEvent
{
	int e;
	int priority;
};

// The comparison function object used by eventpp::OrderedQueueList.
// The function compares the event by priority.
struct MyCompare
{
	template <typename T>
	bool operator() (const T & a, const T & b) const {
		return std::get<0>(a.arguments).priority > std::get<0>(b.arguments).priority;
	}
};

// Define the EventQueue policy
struct MyPolicy
{
	template <typename Item>
	using QueueList = eventpp::OrderedQueueList<Item, MyCompare >;

	static int getEvent(const MyEvent & event) {
		return event.e;
	}
};

int main()
{
	using EQ = eventpp::EventQueue<int, void(const MyEvent &), MyPolicy>;
	EQ queue;

	queue.appendListener(3, [](const MyEvent & event) {
		std::cout << "Get event " << event.e << "(should be 3)." << " priority: " << event.priority << std::endl;
	});
	queue.appendListener(5, [](const MyEvent & event) {
		std::cout << "Get event " << event.e << "(should be 5)." << " priority: " << event.priority << std::endl;
	});
	queue.appendListener(7, [](const MyEvent & event) {
		std::cout << "Get event " << event.e << "(should be 7)." << " priority: " << event.priority << std::endl;
	});

	// Add an event, the first number 5 is the event type, the second number 100 is the priority.
	// After the queue processes, the events will be processed from higher priority to lower priority.
	queue.enqueue(MyEvent{ 5, 100 });
	queue.enqueue(MyEvent{ 5, 200 });
	queue.enqueue(MyEvent{ 7, 300 });
	queue.enqueue(MyEvent{ 7, 400 });
	queue.enqueue(MyEvent{ 3, 500 });
	queue.enqueue(MyEvent{ 3, 600 });

	queue.processOne();
}

Error message:

image

Compilation flags:

"-std=c++11 -O0"

Usinig a member function (method) as callback

I have some problems with using a method (class function) as a callback. I don't know which kind of signature is necessary when using std::bind, which I assume I have to use for this use case. Could you provide a little example?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.