summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-08-12 17:00:37 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-08-12 17:00:37 +0200
commit0ed45348c428a950db589caa227efa86af499170 (patch)
treec24267d08b40726ccfb706da6fc88144565215ee
parent41c0a5169bfb6e87a48f90a2af57c03bba707470 (diff)
compat: add util header
The run_in_thread_{sync,async} functions inject a functional into a Qt event queue. The former also takes care to process void return values.
-rw-r--r--opentrack-compat/options.hpp6
-rw-r--r--opentrack-compat/util.hpp93
2 files changed, 94 insertions, 5 deletions
diff --git a/opentrack-compat/options.hpp b/opentrack-compat/options.hpp
index 78699f63..40aca2de 100644
--- a/opentrack-compat/options.hpp
+++ b/opentrack-compat/options.hpp
@@ -43,11 +43,7 @@
#include "export.hpp"
#include "slider.hpp"
-// just put them here for lack of util header
-#define progn(...) ([&]() { __VA_ARGS__ }())
-template<typename t> using mem = std::shared_ptr<t>;
-template<typename t> using ptr = std::unique_ptr<t>;
-#include "make-unique.hpp"
+#include "util.hpp"
#define OPENTRACK_CONFIG_FILENAME_KEY "settings-filename"
#define OPENTRACK_DEFAULT_CONFIG "default.ini"
diff --git a/opentrack-compat/util.hpp b/opentrack-compat/util.hpp
new file mode 100644
index 00000000..1217e654
--- /dev/null
+++ b/opentrack-compat/util.hpp
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "make-unique.hpp"
+
+#include <memory>
+#include <utility>
+#include <type_traits>
+#include <thread>
+#include <condition_variable>
+
+#include <QDebug>
+
+#define progn(...) ([&]() { __VA_ARGS__ }())
+template<typename t> using mem = std::shared_ptr<t>;
+template<typename t> using ptr = std::unique_ptr<t>;
+
+template<typename F>
+void run_in_thread_async(QObject* obj, F&& fun)
+{
+ QObject src;
+ src.moveToThread(obj->thread());
+ QObject::connect(&src, &QObject::destroyed, obj, std::move(fun), Qt::AutoConnection);
+}
+
+namespace detail {
+
+template<typename t>
+struct run_in_thread_traits
+{
+ using type = t;
+ using ret_type = t&&;
+ static inline void assign(t& lvalue, t&& rvalue) { lvalue = rvalue; }
+ static inline ret_type&& pass(ret_type&& val) { return std::move(val); }
+ template<typename F> static ret_type call(F& fun) { return std::move(fun()); }
+};
+
+template<>
+struct run_in_thread_traits<void>
+{
+ using type = unsigned char;
+ using ret_type = void;
+ static inline void assign(unsigned char&, unsigned char&&) {}
+ static inline void pass(type&&) {}
+ template<typename F> static type&& call(F& fun) { fun(); return std::move(type(0)); }
+};
+
+}
+
+template<typename F>
+auto run_in_thread_sync(QObject* obj, F&& fun)
+ -> typename detail::run_in_thread_traits<decltype(std::forward<F>(fun)())>::ret_type
+{
+ using lock_guard = std::unique_lock<std::mutex>;
+
+ std::mutex mtx;
+ lock_guard guard(mtx);
+ std::condition_variable cvar;
+
+ std::thread::id waiting_thread = std::this_thread::get_id();
+
+ using traits = detail::run_in_thread_traits<decltype(std::forward<F>(fun)())>;
+
+ typename traits::type ret;
+
+ bool skip_wait = false;
+
+ {
+ QObject src;
+ src.moveToThread(obj->thread());
+ QObject::connect(&src,
+ &QObject::destroyed,
+ obj,
+ [&]() {
+ std::thread::id calling_thread = std::this_thread::get_id();
+ if (waiting_thread == calling_thread)
+ {
+ skip_wait = true;
+ traits::assign(ret, traits::call(fun));
+ }
+ else
+ {
+ lock_guard guard(mtx);
+ traits::assign(ret, traits::call(fun));
+ cvar.notify_one();
+ }
+ },
+ Qt::AutoConnection);
+ }
+
+ if (!skip_wait)
+ cvar.wait(guard);
+ return traits::pass(std::move(ret));
+}