1 #pragma once
2
3 #include <mbgl/util/optional.hpp>
4
5 #include <future>
6 #include <utility>
7
8 namespace mbgl {
9
10 // A movable type-erasing function wrapper. This allows to store arbitrary invokable
11 // things (like std::function<>, or the result of a movable-only std::bind()) in the queue.
12 // Source: http://stackoverflow.com/a/29642072/331379
13 class Message {
14 public:
15 virtual ~Message() = default;
16 virtual void operator()() = 0;
17 };
18
19 template <class Object, class MemberFn, class ArgsTuple>
20 class MessageImpl : public Message {
21 public:
MessageImpl(Object & object_,MemberFn memberFn_,ArgsTuple argsTuple_)22 MessageImpl(Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
23 : object(object_),
24 memberFn(memberFn_),
25 argsTuple(std::move(argsTuple_)) {
26 }
27
operator ()()28 void operator()() override {
29 invoke(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>());
30 }
31
32 template <std::size_t... I>
invoke(std::index_sequence<I...>)33 void invoke(std::index_sequence<I...>) {
34 (object.*memberFn)(std::move(std::get<I>(argsTuple))...);
35 }
36
37 Object& object;
38 MemberFn memberFn;
39 ArgsTuple argsTuple;
40 };
41
42 template <class ResultType, class Object, class MemberFn, class ArgsTuple>
43 class AskMessageImpl : public Message {
44 public:
AskMessageImpl(std::promise<ResultType> promise_,Object & object_,MemberFn memberFn_,ArgsTuple argsTuple_)45 AskMessageImpl(std::promise<ResultType> promise_, Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
46 : object(object_),
47 memberFn(memberFn_),
48 argsTuple(std::move(argsTuple_)),
49 promise(std::move(promise_)) {
50 }
51
operator ()()52 void operator()() override {
53 promise.set_value(ask(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>()));
54 }
55
56 template <std::size_t... I>
ask(std::index_sequence<I...>)57 ResultType ask(std::index_sequence<I...>) {
58 return (object.*memberFn)(std::move(std::get<I>(argsTuple))...);
59 }
60
61 Object& object;
62 MemberFn memberFn;
63 ArgsTuple argsTuple;
64 std::promise<ResultType> promise;
65 };
66
67 template <class Object, class MemberFn, class ArgsTuple>
68 class AskMessageImpl<void, Object, MemberFn, ArgsTuple> : public Message {
69 public:
AskMessageImpl(std::promise<void> promise_,Object & object_,MemberFn memberFn_,ArgsTuple argsTuple_)70 AskMessageImpl(std::promise<void> promise_, Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
71 : object(object_),
72 memberFn(memberFn_),
73 argsTuple(std::move(argsTuple_)),
74 promise(std::move(promise_)) {
75 }
76
operator ()()77 void operator()() override {
78 ask(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>());
79 promise.set_value();
80 }
81
82 template <std::size_t... I>
ask(std::index_sequence<I...>)83 void ask(std::index_sequence<I...>) {
84 (object.*memberFn)(std::move(std::get<I>(argsTuple))...);
85 }
86
87 Object& object;
88 MemberFn memberFn;
89 ArgsTuple argsTuple;
90 std::promise<void> promise;
91 };
92
93 namespace actor {
94
95 template <class Object, class MemberFn, class... Args>
makeMessage(Object & object,MemberFn memberFn,Args &&...args)96 std::unique_ptr<Message> makeMessage(Object& object, MemberFn memberFn, Args&&... args) {
97 auto tuple = std::make_tuple(std::forward<Args>(args)...);
98 return std::make_unique<MessageImpl<Object, MemberFn, decltype(tuple)>>(object, memberFn, std::move(tuple));
99 }
100
101 template <class ResultType, class Object, class MemberFn, class... Args>
makeMessage(std::promise<ResultType> && promise,Object & object,MemberFn memberFn,Args &&...args)102 std::unique_ptr<Message> makeMessage(std::promise<ResultType>&& promise, Object& object, MemberFn memberFn, Args&&... args) {
103 auto tuple = std::make_tuple(std::forward<Args>(args)...);
104 return std::make_unique<AskMessageImpl<ResultType, Object, MemberFn, decltype(tuple)>>(std::move(promise), object, memberFn, std::move(tuple));
105 }
106
107 } // namespace actor
108 } // namespace mbgl
109