diff options
Diffstat (limited to 'compat')
| -rw-r--r-- | compat/run-in-thread.hpp | 85 | ||||
| -rw-r--r-- | compat/util.hpp | 87 | 
2 files changed, 86 insertions, 86 deletions
| diff --git a/compat/run-in-thread.hpp b/compat/run-in-thread.hpp new file mode 100644 index 00000000..d377f625 --- /dev/null +++ b/compat/run-in-thread.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include <QObject> + +#include <thread> +#include <condition_variable> +#include <utility> + +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)); +} + +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); +} diff --git a/compat/util.hpp b/compat/util.hpp index 528ae1a8..7a6858a3 100644 --- a/compat/util.hpp +++ b/compat/util.hpp @@ -1,16 +1,10 @@  #pragma once  #include "make-unique.hpp" +#include "run-in-thread.hpp"  #include <memory>  #include <cmath> -#include <utility> -#include <type_traits> -#include <thread> -#include <condition_variable> - -#include <QObject> -#include <QDebug>  #define progn(...) ([&]() { __VA_ARGS__ }())  template<typename t> using mem = std::shared_ptr<t>; @@ -47,82 +41,3 @@ inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val * mi  {      return ::detail::clamp_<decltype(val * min * max)>(val, min, max);  } - -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)); -} - -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); -} - | 
