1 #pragma once
2 
3 #include "nodiscard.h"
4 
5 #include <algorithm>
6 #include <cassert>
7 #include <mutex>
8 #include <memory>
9 #include <vector>
10 #include <functional>
11 
12 namespace Framework
13 {
14 	template<typename> class CSignal;
15 	template<typename T, typename... Args>
16 	class CSignal<T (Args...)>
17 	{
18 	public:
19 		class CConnection;
20 
21 		typedef std::shared_ptr<CConnection> Connection;
22 		typedef std::weak_ptr<CConnection> WeakConnection;
23 		typedef std::function<T (Args...)> SlotFunction;
24 
25 		CSignal() = default;
26 
27 		FRAMEWORK_NODISCARD
28 		Connection Connect(const SlotFunction& func, bool oneShot = false)
29 		{
30 			assert(func);
31 
32 			std::unique_lock<std::mutex> lock(m_lock);
33 
34 			auto connection = std::make_shared<CConnection>(func, oneShot);
35 			m_connections.push_back(connection);
36 
37 			return connection;
38 		}
39 
40 		FRAMEWORK_NODISCARD
ConnectOnce(const SlotFunction & func)41 		Connection ConnectOnce(const SlotFunction& func)
42 		{
43 			return Connect(func, true);
44 		}
45 
Reset()46 		void Reset()
47 		{
48 			std::unique_lock<std::mutex> lock(m_lock);
49 
50 			m_connections.clear();
51 		}
52 
operator()53 		void operator()(Args... args)
54 		{
55 			std::unique_lock<std::mutex> lock(m_lock);
56 
57 			m_connections.erase(
58 				std::remove_if(
59 					m_connections.begin(),
60 					m_connections.end(),
61 					[&](WeakConnection& connection)
62 					{
63 						auto connectionPtr = connection.lock();
64 						if(connectionPtr)
65 						{
66 							(*connectionPtr)(args...);
67 						}
68 						return !connectionPtr || (*connectionPtr).IsOneShot();
69 					}
70 				),
71 				m_connections.end()
72 			);
73 		}
74 
75 		class CConnection
76 		{
77 			public:
CConnection(const SlotFunction slot,bool oneShot)78 				CConnection(const SlotFunction slot, bool oneShot)
79 				: m_slot(slot)
80 				, m_oneShot(oneShot)
81 				{
82 				}
83 
operator()84 				void operator()(Args... args)
85 				{
86 					(m_slot)(args...);
87 				}
88 
IsOneShot()89 				bool IsOneShot() const
90 				{
91 					return m_oneShot;
92 				}
93 
94 			private:
95 				SlotFunction m_slot;
96 				bool m_oneShot;
97 		};
98 	private:
99 		std::vector<WeakConnection> m_connections;
100 		std::mutex m_lock;
101 	};
102 }
103