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