clean-code/VectorFiller/atlas/collection/impl/MultiThreadedVectorFactory.h

57 lines
1.7 KiB
C++

#pragma once
#include "../../generator/generator.h"
#include "AbstractVectorFactory.h"
#include "fill_with.h"
#include <algorithm>
#include <functional>
#include <thread>
namespace atlas::collection {
namespace {
void join_thread(std::thread& t)
{
t.join();
}
}
template <typename T>
class MultiThreadedVectorFactory : public AbstractVectorFactory<T> {
public:
using Self = MultiThreadedVectorFactory<T>;
MultiThreadedVectorFactory(std::function<std::unique_ptr<generator::Generator<T>>()> generator_factory, size_t const nthreads)
: m_gen { std::move(generator_factory) }
, m_threads { nthreads }
{
}
MultiThreadedVectorFactory(MultiThreadedVectorFactory const&) = delete;
MultiThreadedVectorFactory(MultiThreadedVectorFactory&&) = delete;
MultiThreadedVectorFactory& operator=(MultiThreadedVectorFactory const&) = delete;
MultiThreadedVectorFactory& operator=(MultiThreadedVectorFactory&&) = delete;
auto fill(std::vector<T>& v) -> void override final
{
std::vector<std::thread> threads;
size_t const slice { v.size() / m_threads };
auto pos = v.begin();
for (size_t i = 0; i < m_threads; ++i, pos += slice) {
threads.emplace_back([this, from = pos, to = pos + slice] { this->worker(from, to); });
}
worker(pos, v.end());
std::for_each(threads.begin(), threads.end(), join_thread);
}
private:
void worker(std::vector<int>::iterator from, std::vector<int>::iterator to)
{
detail::fill_with(from, to, [g = m_gen()]() { return g->next(); });
}
std::function<std::unique_ptr<generator::Generator<T>>()> m_gen;
size_t m_threads;
};
}