summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/collections.hpp27
-rw-r--r--lib/gl_traits.hpp45
-rw-r--r--lib/work.h12
-rw-r--r--lib/worker.cpp39
-rw-r--r--lib/worker.h132
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