diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/collections.hpp | 27 | ||||
-rw-r--r-- | lib/gl_traits.hpp | 45 | ||||
-rw-r--r-- | lib/work.h | 12 | ||||
-rw-r--r-- | lib/worker.cpp | 39 | ||||
-rw-r--r-- | lib/worker.h | 132 |
5 files changed, 180 insertions, 75 deletions
diff --git a/lib/collections.hpp b/lib/collections.hpp index 59cec6f..8f5a43d 100644 --- a/lib/collections.hpp +++ b/lib/collections.hpp @@ -65,11 +65,36 @@ operator*=(IterableCollection auto & in, auto && f) } template<template<typename...> typename C, typename... T> + requires IterableCollection<C<T...>> [[nodiscard]] constexpr auto operator*(const C<T...> & in, auto && f) { - C<decltype(f(in[0]))> out; + C<decltype(f(*in.begin()))> out; + if constexpr (requires { out.reserve(in.size()); }) { + out.reserve(in.size()); + } + + std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f); + return out; +} + +template<typename T, std::size_t N> +[[nodiscard]] constexpr auto +operator*(const std::span<T, N> in, auto && f) +{ + std::array<decltype(f(std::declval<T>())), N> out; + + std::transform(in.begin(), in.end(), out.begin(), f); + return out; +} + +template<typename T> +[[nodiscard]] constexpr auto +operator*(const std::span<T, std::dynamic_extent> in, auto && f) +{ + std::vector<decltype(f(std::declval<T>()))> out; + out.reserve(in.size()); std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f); return out; } diff --git a/lib/gl_traits.hpp b/lib/gl_traits.hpp index d140de9..e2e689d 100644 --- a/lib/gl_traits.hpp +++ b/lib/gl_traits.hpp @@ -6,37 +6,50 @@ #include <glm/fwd.hpp> template<typename T> struct gl_traits; -template<> struct gl_traits<glm::f32> { - static constexpr GLenum type {GL_FLOAT}; +struct gl_traits_base { static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::f64> { +struct gl_traits_float : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribPointer(index, size, type, GL_FALSE, stride, pointer); + }}; +}; +struct gl_traits_longfloat : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribLPointer(index, size, type, stride, pointer); + }}; +}; +struct gl_traits_integer : public gl_traits_base { + static constexpr auto vertexAttribFunc { + [](GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer) { + glVertexAttribIPointer(index, size, type, stride, pointer); + }}; +}; +template<> struct gl_traits<glm::f32> : public gl_traits_float { + static constexpr GLenum type {GL_FLOAT}; +}; +template<> struct gl_traits<glm::f64> : public gl_traits_longfloat { static constexpr GLenum type {GL_DOUBLE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::int8> { +template<> struct gl_traits<glm::int8> : public gl_traits_integer { static constexpr GLenum type {GL_BYTE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::int16> { +template<> struct gl_traits<glm::int16> : public gl_traits_integer { static constexpr GLenum type {GL_SHORT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::int32> { +template<> struct gl_traits<glm::int32> : public gl_traits_integer { static constexpr GLenum type {GL_INT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::uint8> { +template<> struct gl_traits<glm::uint8> : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_BYTE}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::uint16> { +template<> struct gl_traits<glm::uint16> : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_SHORT}; - static constexpr GLint size {1}; }; -template<> struct gl_traits<glm::uint32> { +template<> struct gl_traits<glm::uint32> : public gl_traits_integer { static constexpr GLenum type {GL_UNSIGNED_INT}; - static constexpr GLint size {1}; }; template<typename T, std::size_t S> struct gl_traits<std::array<T, S>> : public gl_traits<T> { diff --git a/lib/work.h b/lib/work.h deleted file mode 100644 index c780e13..0000000 --- a/lib/work.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include <special_members.hpp> - -class Work { -public: - virtual ~Work() = default; - NO_COPY(Work); - NO_MOVE(Work); - - virtual void doWork() = 0; -}; diff --git a/lib/worker.cpp b/lib/worker.cpp index fd255c7..45fb6df 100644 --- a/lib/worker.cpp +++ b/lib/worker.cpp @@ -1,27 +1,24 @@ #include "worker.h" -#if __cpp_lib_semaphore -# include "work.h" -# include <algorithm> -# include <iterator> -# include <mutex> +#include <algorithm> +#include <iterator> +#include <mutex> + +Worker Worker::instance; Worker::Worker() : todoLen {0} { std::generate_n(std::back_inserter(threads), std::thread::hardware_concurrency(), [this]() { - return std::thread {&Worker::worker, this}; + return std::jthread {&Worker::worker, this}; }); } Worker::~Worker() { todoLen.release(std::thread::hardware_concurrency()); - std::for_each(threads.begin(), threads.end(), [](auto & th) { - th.join(); - }); } void -Worker::addWork(WorkPtr j) +Worker::addWorkPtr(WorkPtr j) { std::lock_guard<std::mutex> lck {todoMutex}; todoLen.release(); @@ -45,4 +42,24 @@ Worker::worker() j->doWork(); } } -#endif + +void +Worker::assist() +{ + auto job = [this]() { + using namespace std::chrono_literals; + if (todoLen.try_acquire_for(100us)) { + if (std::lock_guard<std::mutex> lck {todoMutex}; todo.size()) { + WorkPtr x = std::move(todo.front()); + if (x) { + todo.pop_front(); + } + return x; + } + } + return WorkPtr {}; + }; + if (auto j = job()) { + j->doWork(); + } +} diff --git a/lib/worker.h b/lib/worker.h index 7cd06f9..d9a5a6f 100644 --- a/lib/worker.h +++ b/lib/worker.h @@ -1,60 +1,122 @@ #pragma once +#include <deque> +#include <functional> +#include <future> +#include <memory> +#include <mutex> +#include <semaphore> +#include <special_members.hpp> +#include <thread> #include <utility> -class Work; - -#if __cpp_lib_semaphore -# include <deque> -# include <memory> -# include <mutex> -# include <semaphore> -# include <special_members.hpp> -# include <thread> -# include <vector> +#include <vector> class Worker { public: + class WorkItem { + protected: + WorkItem(Worker * worker) : worker {worker} { } + virtual ~WorkItem() = default; + NO_MOVE(WorkItem); + NO_COPY(WorkItem); + + void + assist() const + { + worker->assist(); + } + Worker * worker; + + public: + virtual void doWork() = 0; + }; + + template<typename T> class WorkItemT : public WorkItem { + public: + T + get() + { + using namespace std::chrono_literals; + while (future.wait_for(0s) == std::future_status::timeout) { + assist(); + } + return future.get(); + } + + protected: + WorkItemT(Worker * worker) : WorkItem {worker} { } + + std::promise<T> promise; + std::future<T> future {promise.get_future()}; + friend Worker; + }; + + template<typename... Params> + static auto + addWork(Params &&... params) + { + return instance.addWorkImpl(std::forward<Params>(params)...); + } + template<typename T> using WorkPtrT = std::shared_ptr<WorkItemT<T>>; + +private: + template<typename T, typename... Params> class WorkItemTImpl : public WorkItemT<T> { + public: + WorkItemTImpl(Worker * worker, Params &&... params) : + WorkItemT<T> {worker}, params {std::forward<Params>(params)...} + { + } + + private: + void + doWork() override + { + try { + if constexpr (std::is_void_v<T>) { + std::apply(std::invoke<Params &...>, params); + WorkItemT<T>::promise.set_value(); + } + else { + WorkItemT<T>::promise.set_value(std::apply(std::invoke<Params &...>, params)); + } + } + catch (...) { + WorkItemT<T>::promise.set_exception(std::current_exception()); + } + } + + std::tuple<Params...> params; + }; + Worker(); ~Worker(); NO_COPY(Worker); NO_MOVE(Worker); - using WorkPtr = std::unique_ptr<Work>; + using WorkPtr = std::shared_ptr<WorkItem>; - template<typename T, typename... Params> - void - addWork(Params &&... params) - requires std::is_base_of_v<Work, T> + template<typename... Params> + auto + addWorkImpl(Params &&... params) { - addWork(std::make_unique<T>(std::forward<Params>(params)...)); + using T = decltype(std::invoke(std::forward<Params>(params)...)); + auto work = std::make_shared<WorkItemTImpl<T, Params...>>(this, std::forward<Params>(params)...); + addWorkPtr(work); + return work; } - void addWork(WorkPtr w); - -private: + void addWorkPtr(WorkPtr w); void worker(); + void assist(); - using Threads = std::vector<std::thread>; + using Threads = std::vector<std::jthread>; using ToDo = std::deque<WorkPtr>; - Threads threads; ToDo todo; std::counting_semaphore<16> todoLen; std::mutex todoMutex; -}; - -#else + Threads threads; -class Worker { -public: - template<typename T, typename... Params> - void - addWork(Params &&... params) - requires std::is_base_of_v<Work, T> - { - T(std::forward<Params>(params)...).doWork(); - } + static Worker instance; }; - -#endif |