summaryrefslogtreecommitdiff
path: root/src/mbgl/util/thread.hpp
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-04-13 18:28:18 +0200
committerKonstantin Käfer <mail@kkaefer.com>2015-04-13 18:28:18 +0200
commit452d12e6e653d61c2182f4464d4365f0b96c9739 (patch)
treea96bcdba373ca23d832364d7bce6b5912864c1f5 /src/mbgl/util/thread.hpp
parent16849a341b72c0633be1e3c89498c883d6efb000 (diff)
downloadqtlocation-mapboxgl-452d12e6e653d61c2182f4464d4365f0b96c9739.tar.gz
make implementation files private headers
Diffstat (limited to 'src/mbgl/util/thread.hpp')
-rw-r--r--src/mbgl/util/thread.hpp87
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