| 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 | |