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/thread.hpp | |
parent | 16849a341b72c0633be1e3c89498c883d6efb000 (diff) | |
download | qtlocation-mapboxgl-452d12e6e653d61c2182f4464d4365f0b96c9739.tar.gz |
make implementation files private headers
Diffstat (limited to 'src/mbgl/util/thread.hpp')
-rw-r--r-- | src/mbgl/util/thread.hpp | 87 |
1 files changed, 87 insertions, 0 deletions
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 |