summaryrefslogtreecommitdiff
path: root/src/mbgl/util
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
parent16849a341b72c0633be1e3c89498c883d6efb000 (diff)
downloadqtlocation-mapboxgl-452d12e6e653d61c2182f4464d4365f0b96c9739.tar.gz
make implementation files private headers
Diffstat (limited to 'src/mbgl/util')
-rw-r--r--src/mbgl/util/run_loop.hpp56
-rw-r--r--src/mbgl/util/thread.hpp87
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