BareGit
#include "agent_smith/detail/blocking_pool.hpp"

#include <algorithm>

namespace agent_smith::internal
{

BlockingPool::BlockingPool(std::size_t size)
{
    const std::size_t worker_count = std::max<std::size_t>(size, 1);
    workers_.reserve(worker_count);
    for(std::size_t index = 0; index < worker_count; ++index)
    {
        workers_.emplace_back([this](std::stop_token stop) { worker(stop); });
    }
}

BlockingPool::~BlockingPool()
{
    std::queue<WorkItem> pending;
    {
        std::lock_guard lock(mutex_);
        stopping_ = true;
        pending.swap(pending_);
    }

    while(!pending.empty())
    {
        pending.front().cancel();
        pending.pop();
    }

    condition_.notify_all();
}

bool BlockingPool::enqueue(WorkItem item)
{
    {
        std::lock_guard lock(mutex_);
        if(stopping_)
        {
            return false;
        }
        pending_.push(std::move(item));
    }

    condition_.notify_one();
    return true;
}

void BlockingPool::worker(std::stop_token stop)
{
    while(!stop.stop_requested())
    {
        WorkItem item;
        {
            std::unique_lock lock(mutex_);
            condition_.wait(lock,
                            [&]()
                            {
                                return stop.stop_requested() || stopping_ ||
                                       !pending_.empty();
                            });

            if(stop.stop_requested() || stopping_)
            {
                return;
            }

            item = std::move(pending_.front());
            pending_.pop();
        }

        item.run();
    }
}

} // namespace agent_smith::internal