//////////////////////////////////////////////////////////////////////////// // // Copyright 2016 Realm Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////// #pragma once #include #include #include #include "util/event_loop_signal.hpp" // FIXME: remove once we switch to C++ 17 where we can use std::apply namespace _apply_polyfill { template constexpr auto apply_impl(Tuple t, F f, std::index_sequence) { return f(std::get(t)...); } template constexpr auto apply(Tuple t, F f) { return apply_impl(t, f, std::make_index_sequence{}>{}); } } namespace realm { template class EventLoopDispatcher; template class EventLoopDispatcher { using Tuple = std::tuple::type...>; private: struct State { public: State(std::function func) : m_func(func) { } const std::function m_func; std::queue m_invocations; std::mutex m_mutex; }; const std::shared_ptr m_state; struct Callback { std::shared_ptr m_state; public: void operator()() { std::unique_lock lock(m_state->m_mutex); while (!m_state->m_invocations.empty()) { auto& tuple = m_state->m_invocations.front(); ::_apply_polyfill::apply(tuple, m_state->m_func); m_state->m_invocations.pop(); } } }; const std::shared_ptr> m_signal; const std::thread::id m_thread = std::this_thread::get_id(); public: EventLoopDispatcher(std::function func) : m_state(std::make_shared(func)) , m_signal(std::make_shared>(Callback{m_state})) { } const std::function& func() const { return m_state->m_func; } void operator()(Args... args) { if (m_thread == std::this_thread::get_id()) { m_state->m_func(args...); return; } { std::unique_lock lock(m_state->m_mutex); m_state->m_invocations.push(std::make_tuple(args...)); } m_signal->notify(); } }; }