summaryrefslogtreecommitdiff
path: root/socket/socket.hpp
blob: dd9b2a3d8827486789f0e3e992602b11cf57e4ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#pragma once

#include <functional>
#include <map>

namespace socket {
	/* Allows casting R(Args...) */
	template <typename T>
	class Socket;

	/* A class that represents a socket that can
	   be used to dispatch a function call to different
	   handlers. Handlers can be connected and disconnected
	   from the socket at runtime. */
	template <typename R, typename... Args>
	class Socket<R(Args...)> {
		/* The type of handler function or methods */
		using HandlerType = std::function<R(Args...)>;
		

		/* The next handler descriptor to be assigned
		   the descriptor can be used to disconnect
		   a descriptor */
		int descriptor;

		/* Map between descriptors and handlers */
		std::map<int, HandlerType> handlers;
	public:
		/* Connect a handler to the socket
		   handler: the handler to connect to
		   Returns the handler descriptor */
		int connect(HandlerType handler) {
			// Get the handler descriptor of next handler
			int hd = descriptor++;

			// Store the handler
			handlers[hd] = handler;

			return hd;
		}

		/* Connect a handler to the socket
		   and bind the call to an object, this
		   can be useful if the handler is a method */
		template <typename T, typename V>
		int connect(T *object, R (V::*handler)(Args...)) {
			auto f = [=](Args... args) {
				return std::invoke(handler, object, args...);
			};

			return connect(f);
		}

		/* Disconnect a handler from the socket
		   hd: the handle descriptor of the handler
		       to disconnect */
		void disconnect(int hd) {
			// Remove the handler from the map
			handlers.erase(hd);
		}

		/* Dispatch a call to all handlers */
		void operator()(Args... args) {
			for (auto &handler : handlers)
				handler.second(args...);
		}
	};
}