#pragma once #include #include #include #include #include #include #include #include #include #include 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 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 promise; std::future future {promise.get_future()}; friend Worker; }; template static auto addWork(Params &&... params) { return instance.addWorkImpl(std::forward(params)...); } template using WorkPtrT = std::shared_ptr>; private: template class WorkItemTImpl : public WorkItemT { public: WorkItemTImpl(Worker * worker, Params &&... params) : WorkItemT {worker}, params {std::forward(params)...} { } private: void doWork() override { try { if constexpr (std::is_void_v) { std::apply(std::invoke, params); WorkItemT::promise.set_value(); } else { WorkItemT::promise.set_value(std::apply(std::invoke, params)); } } catch (...) { WorkItemT::promise.set_exception(std::current_exception()); } } std::tuple params; }; Worker(); ~Worker(); NO_COPY(Worker); NO_MOVE(Worker); using WorkPtr = std::shared_ptr; template auto addWorkImpl(Params &&... params) { using T = decltype(std::invoke(std::forward(params)...)); auto work = std::make_shared>(this, std::forward(params)...); addWorkPtr(work); return work; } void addWorkPtr(WorkPtr w); void worker(); void assist(); using Threads = std::vector; using ToDo = std::deque; ToDo todo; std::counting_semaphore<16> todoLen; std::mutex todoMutex; Threads threads; static Worker instance; };