From a9ac314a5d28bec2a26cd6889364f81f811d4cd4 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 20 Jul 2017 19:17:49 +0300 Subject: [PATCH] [core] implement ask pattern in actor --- include/mbgl/actor/actor.hpp | 12 ++++++++++++ include/mbgl/actor/message.hpp | 34 ++++++++++++++++++++++++++++++++++ test/actor/actor.test.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/mbgl/actor/actor.hpp b/include/mbgl/actor/actor.hpp index 810114c51..00e1bb82f 100644 --- a/include/mbgl/actor/actor.hpp +++ b/include/mbgl/actor/actor.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace mbgl { @@ -61,6 +62,17 @@ public: mailbox->push(actor::makeMessage(object, fn, std::forward(args)...)); } + template + auto ask(Fn fn, Args&&... args) { + // Result type is deduced from the function's return type + using ResultType = typename std::result_of::type; + + std::promise promise; + auto future = promise.get_future(); + mailbox->push(actor::makeMessage(std::move(promise), object, fn, std::forward(args)...)); + return future; + } + ActorRef> self() { return ActorRef>(object, mailbox); } diff --git a/include/mbgl/actor/message.hpp b/include/mbgl/actor/message.hpp index cf071d493..406de425d 100644 --- a/include/mbgl/actor/message.hpp +++ b/include/mbgl/actor/message.hpp @@ -1,5 +1,8 @@ #pragma once +#include + +#include #include namespace mbgl { @@ -36,6 +39,31 @@ public: ArgsTuple argsTuple; }; +template +class AskMessageImpl : public Message { +public: + AskMessageImpl(std::promise promise_, Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_) + : object(object_), + memberFn(memberFn_), + argsTuple(std::move(argsTuple_)), + promise(std::move(promise_)) { + } + + void operator()() override { + promise.set_value(ask(std::make_index_sequence::value>())); + } + + template + ResultType ask(std::index_sequence) { + return (object.*memberFn)(std::move(std::get(argsTuple))...); + } + + Object& object; + MemberFn memberFn; + ArgsTuple argsTuple; + std::promise promise; +}; + namespace actor { template @@ -44,5 +72,11 @@ std::unique_ptr makeMessage(Object& object, MemberFn memberFn, Args&&.. return std::make_unique>(object, memberFn, std::move(tuple)); } +template +std::unique_ptr makeMessage(std::promise&& promise, Object& object, MemberFn memberFn, Args&&... args) { + auto tuple = std::make_tuple(std::forward(args)...); + return std::make_unique>(std::move(promise), object, memberFn, std::move(tuple)); +} + } // namespace actor } // namespace mbgl diff --git a/test/actor/actor.test.cpp b/test/actor/actor.test.cpp index 3d9746962..2b4c83f56 100644 --- a/test/actor/actor.test.cpp +++ b/test/actor/actor.test.cpp @@ -281,3 +281,27 @@ TEST(Actor, NonConcurrentMailbox) { test.invoke(&Test::end); endedFuture.wait(); } + +TEST(Actor, Ask) { + // Asking for a result + + struct Test { + + Test(ActorRef) {} + + int doubleIt(int i) { + return i * 2; + } + }; + + ThreadPool pool { 2 }; + Actor test(pool); + + auto result = test.ask(&Test::doubleIt, 1); + + ASSERT_TRUE(result.valid()); + + auto status = result.wait_for(std::chrono::seconds(1)); + ASSERT_EQ(std::future_status::ready, status); + ASSERT_EQ(2, result.get()); +}