-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions.h
115 lines (100 loc) · 2.8 KB
/
functions.h
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#pragma once
#include <functional>
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <vector>
#include <cassert>
#include "message.h"
// [http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html]
template <typename Function>
struct function_traits
: public function_traits<decltype(&Function::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
typedef ReturnType (*pointer)(Args...);
typedef std::function<ReturnType(Args...)> function;
};
template <typename Function>
typename function_traits<Function>::pointer
to_function_pointer(Function& lambda)
{
return static_cast<typename function_traits<Function>::pointer>(lambda);
}
class Messenger
{
private:
typedef std::function<void(const Message&)> Receiver;
struct Subscriber
{
int code;
void* object;
Receiver call;
const std::type_index arg_type;
Subscriber(int code, void* object, Receiver recv, std::type_index arg_type)
: code(code),
object(object),
call(recv),
arg_type(arg_type)
{
}
};
// Variant for lambda (Arg)->void
template <typename Function>
struct SubscriberImpl
{
static Subscriber make(int code, Function func)
{
typedef typename function_traits<Function>::function FType;
typedef typename FType::argument_type Arg;
auto& arg_type = typeid(Arg);
typedef std::remove_reference<Arg>::type ArgNoRef;
static_assert(std::is_base_of<Message, ArgNoRef>::value,
"Argument type not derived from base Message");
auto pass = (void(*) (const Message&)) to_function_pointer(func);
return std::move(Subscriber(code, nullptr, pass, arg_type));
}
};
// Variant for std::function<void <T>>
template <typename Arg>
struct SubscriberImpl<std::function<void(const Arg&)>>
{
static Subscriber make(int code, std::function<void (const Arg&)> func)
{
static_assert(std::is_base_of<Message, Arg>::value, "Argument type not derived from base Message");
auto& arg_type = typeid(const Arg);
auto pass = *((std::function<void (const Message&)>*) &func); // Bdysh!
return std::move(Subscriber(code, nullptr, pass, arg_type));
}
};
public:
template <typename Function>
void subscribe(int code, Function func)
{
subscribers_.emplace_back(std::move(SubscriberImpl<Function>::make(code, func)));
}
template <class LikeMessage>
void send(const LikeMessage& msg)
{
assert((!is_sliced<Message, LikeMessage>(&msg)));
send_impl(msg);
}
private:
void send_impl(const Message& msg)
{
const std::type_index arg_type = typeid(msg);
for (auto& i: subscribers_)
{
if (i.code == msg.code)
{
if (arg_type != i.arg_type)
throw std::logic_error("Bad message cast");
i.call(msg);
}
}
}
private:
std::vector<Subscriber> subscribers_;
};