diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-04-13 18:28:18 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-04-13 18:28:18 +0200 |
commit | 452d12e6e653d61c2182f4464d4365f0b96c9739 (patch) | |
tree | a96bcdba373ca23d832364d7bce6b5912864c1f5 /src/mbgl/util | |
parent | 16849a341b72c0633be1e3c89498c883d6efb000 (diff) | |
download | qtlocation-mapboxgl-452d12e6e653d61c2182f4464d4365f0b96c9739.tar.gz |
make implementation files private headers
Diffstat (limited to 'src/mbgl/util')
-rw-r--r-- | src/mbgl/util/run_loop.hpp | 56 | ||||
-rw-r--r-- | src/mbgl/util/thread.hpp | 87 |
2 files changed, 143 insertions, 0 deletions
diff --git a/src/mbgl/util/run_loop.hpp b/src/mbgl/util/run_loop.hpp new file mode 100644 index 0000000000..9bed417c38 --- /dev/null +++ b/src/mbgl/util/run_loop.hpp @@ -0,0 +1,56 @@ +#ifndef MBGL_UTIL_RUN_LOOP +#define MBGL_UTIL_RUN_LOOP + +#include <memory> +#include <mutex> +#include <functional> +#include <queue> + +namespace uv { +class async; +class loop; +} + +namespace mbgl { +namespace util { + +template <typename T> class Thread; + +class RunLoop { + friend Thread<RunLoop>; + +protected: + // These are called by the Thread<> wrapper. + RunLoop(); + ~RunLoop(); + + // Called by the Thread<> wrapper to start the loop. When you implement this + // method in a child class, you *must* call this function as the last action. + void start(); + +protected: + // Called by the Thread<> wrapper to terminate this loop. + void stop(); + + // Obtain the underlying loop object in case you want to attach additional listeners. + uv::loop& loop() { return *runloop; }; + +private: + // Invokes function in the run loop. + void process(); + +public: + // Schedules a function to be executed as part of this run loop. + void invoke(std::function<void()>&& fn); + +private: + const std::unique_ptr<uv::loop> runloop; + const std::unique_ptr<uv::async> runloopAsync; + std::mutex runloopMutex; + std::queue<std::function<void()>> runloopQueue; +}; + +} +} + +#endif diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp new file mode 100644 index 0000000000..7c9ba70e11 --- /dev/null +++ b/src/mbgl/util/thread.hpp @@ -0,0 +1,87 @@ +#ifndef MBGL_UTIL_THREAD +#define MBGL_UTIL_THREAD + +#include <future> +#include <thread> + +namespace { + +template <::std::size_t...> +struct index_sequence {}; + +template <::std::size_t N, ::std::size_t... I> +struct integer_sequence : integer_sequence<N - 1, N - 1, I...> {}; + +template <::std::size_t... I> +struct integer_sequence<0, I...> { + using type = index_sequence<I...>; +}; + +} + +namespace mbgl { +namespace util { + +// Manages a thread with Object. + +// Upon creation of this object, it launches a thread, creates an object of type Object in that +// thread, and then calls .start(); on that object. When the Thread<> object is destructed, the +// Object's .stop() function is called, and the destructor waits for thread termination. The +// Thread<> constructor blocks until the thread and the Object are fully created, so after the +// object creation, it's safe to obtain the Object stored in this thread. + +template <class Object> +class Thread { +public: + template <class... Args> + Thread(Args&&... args); + Thread(const Thread&) = delete; + Thread(Thread&&) = delete; + Thread& operator=(const Thread&) = delete; + Thread& operator=(Thread&&) = delete; + ~Thread(); + + inline Object* operator->() const { return &object; } + inline operator Object*() const { return &object; } + +private: + template <typename P, std::size_t... I> + void run(std::promise<Object&>& promise, P&& params, index_sequence<I...>) { + Object context(std::get<I>(std::forward<P>(params))...); + promise.set_value(context); + context.start(); + joinable.get_future().get(); + } + +private: + std::thread thread; + std::promise<void> joinable; + Object& object; +}; + +template <class Object> +template <class... Args> +Thread<Object>::Thread(Args&&... args) + : object([&](std::tuple<Args...>&& params) -> Object& { + // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug + // when expanding parameters packs captured in lambdas. + std::promise<Object&> promise; + constexpr auto seq = typename integer_sequence<sizeof...(Args)>::type(); + thread = std::thread([&] { + run(promise, std::move(params), seq); + }); + return promise.get_future().get(); + }(std::move(std::forward_as_tuple(::std::forward<Args>(args)...)))) { +} + +template <class Object> +Thread<Object>::~Thread() { + object.stop(); + joinable.set_value(); + thread.join(); +} + +} +} + +#endif |