#pragma once
#include <condition_variable>
#include <cstddef>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <vector>
#include <mw/error.hpp>
/// Fixed worker pool that rejects tasks when all workers are reserved.
class ThreadPool
{
public:
/// Start workers, returning validation errors.
static mw::E<std::unique_ptr<ThreadPool>> create(std::size_t worker_count);
/// Finish accepted tasks and join workers. Must not run on a worker.
/// Callers must stop submitting before destroying the pool.
~ThreadPool();
/// Pools own their workers and cannot be copied.
ThreadPool(const ThreadPool&) = delete;
/// Pools cannot transfer ownership through copy assignment.
ThreadPool& operator=(const ThreadPool&) = delete;
/// Reserve a worker or return nullopt immediately if full.
/// The future reports completion. Task exceptions terminate the process.
/// Invalid tasks return errors.
mw::E<std::optional<std::future<void>>> trySubmit(
std::move_only_function<void()> task);
/// Wait until all accepted tasks finish. Must not run on a worker.
/// Concurrent submissions may extend the wait.
void waitIdle();
private:
explicit ThreadPool(std::size_t worker_count);
struct Worker
{
std::condition_variable work_ready;
std::packaged_task<void()> task;
bool busy = false;
std::thread thread;
};
void run(Worker& worker);
void stop();
std::mutex mutex;
std::condition_variable idle;
std::size_t outstanding = 0;
bool stopping = false;
std::vector<Worker> workers;
};