1 | #pragma once |
2 | |
3 | #include <mbgl/actor/aspiring_actor.hpp> |
4 | #include <mbgl/actor/mailbox.hpp> |
5 | #include <mbgl/actor/message.hpp> |
6 | #include <mbgl/actor/actor_ref.hpp> |
7 | |
8 | #include <memory> |
9 | #include <future> |
10 | #include <type_traits> |
11 | #include <cassert> |
12 | |
13 | namespace mbgl { |
14 | |
15 | /* |
16 | An `EstablishedActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`), |
17 | the other half being `AspiringActor<O>`. It is responsible for managing the lifetime of the |
18 | target object `O` and the open/closed state of the parent's `mailbox`. |
19 | |
20 | The `O` object's lifetime is contained by that of its owning `EstablishedActor<O>`: the |
21 | `EstablishedActor` constructor executes the `O` constructor via "placement new", constructing |
22 | it at the address provided by the parent `AspiringActor`, and the `~EstablishedActor` destructor |
23 | similarly executes the `~O` destructor (after closing the mailbox). `EstablishedActor` should |
24 | therefore live entirely on the thread intended to own `O`. |
25 | */ |
26 | |
27 | template <class Object> |
28 | class EstablishedActor { |
29 | public: |
30 | // Construct the Object from a parameter pack `args` (i.e. `Object(args...)`) |
31 | template <typename U = Object, class... Args, typename std::enable_if< |
32 | std::is_constructible<U, Args...>::value || |
33 | std::is_constructible<U, ActorRef<U>, Args...>::value |
34 | >::type * = nullptr> |
35 | EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, Args&& ... args) |
36 | : parent(parent_) { |
37 | emplaceObject(std::forward<Args>(args)...); |
38 | parent.mailbox->open(scheduler); |
39 | } |
40 | |
41 | // Construct the `Object` from a tuple containing the constructor arguments (i.e. |
42 | // `Object(std::get<0>(args), std::get<1>(args), ...)`) |
43 | template <class ArgsTuple, std::size_t ArgCount = std::tuple_size<std::decay_t<ArgsTuple>>::value> |
44 | EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, ArgsTuple&& args) |
45 | : parent(parent_) { |
46 | emplaceObject(std::forward<ArgsTuple>(args), std::make_index_sequence<ArgCount>{}); |
47 | parent.mailbox->open(scheduler); |
48 | } |
49 | |
50 | EstablishedActor(const EstablishedActor&) = delete; |
51 | |
52 | ~EstablishedActor() { |
53 | parent.mailbox->close(); |
54 | parent.object().~Object(); |
55 | } |
56 | |
57 | private: |
58 | // Enabled for Objects with a constructor taking ActorRef<Object> as the first parameter |
59 | template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr> |
60 | void emplaceObject(Args&&... args_) { |
61 | new (&parent.objectStorage) Object(parent.self(), std::forward<Args>(args_)...); |
62 | } |
63 | |
64 | // Enabled for plain Objects |
65 | template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, Args...>::value>::type * = nullptr> |
66 | void emplaceObject(Args&&... args_) { |
67 | new (&parent.objectStorage) Object(std::forward<Args>(args_)...); |
68 | } |
69 | |
70 | // Used to expand a tuple holding the constructor arguments |
71 | template <class ArgsTuple, std::size_t... I> |
72 | void emplaceObject(ArgsTuple&& args, std::index_sequence<I...>) { |
73 | emplaceObject(std::move(std::get<I>(std::forward<ArgsTuple>(args)))...); |
74 | (void) args; // mark args as used: if it's empty tuple, it's not actually used above. |
75 | } |
76 | |
77 | AspiringActor<Object>& parent; |
78 | }; |
79 | |
80 | } // namespace mbgl |
81 | |