#pragma once #include #include #include namespace mbgl { // A movable type-erasing function wrapper. This allows to store arbitrary invokable // things (like std::function<>, or the result of a movable-only std::bind()) in the queue. // Source: http://stackoverflow.com/a/29642072/331379 class Message { public: virtual ~Message() = default; virtual void operator()() = 0; }; template class MessageImpl : public Message { public: MessageImpl(Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_) : object(object_), memberFn(memberFn_), argsTuple(std::move(argsTuple_)) { } void operator()() override { invoke(std::make_index_sequence::value>()); } template void invoke(std::index_sequence) { (object.*memberFn)(std::move(std::get(argsTuple))...); } Object& object; MemberFn memberFn; 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; }; 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 { ask(std::make_index_sequence::value>()); promise.set_value(); } template void ask(std::index_sequence) { (object.*memberFn)(std::move(std::get(argsTuple))...); } Object& object; MemberFn memberFn; ArgsTuple argsTuple; std::promise promise; }; namespace actor { template std::unique_ptr makeMessage(Object& object, MemberFn memberFn, Args&&... args) { auto tuple = std::make_tuple(std::forward(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