28#ifndef LIBSEMIGROUPS_DETAIL_RACE_HPP_
29#define LIBSEMIGROUPS_DETAIL_RACE_HPP_
38#include "libsemigroups/constants.hpp"
39#include "libsemigroups/debug.hpp"
40#include "libsemigroups/exception.hpp"
41#include "libsemigroups/runner.hpp"
49 class Race :
public Reporter {
52 std::vector<std::shared_ptr<Runner>> _runners;
53 std::shared_ptr<Runner> _winner;
71 Race(Race
const& other) : Race() {
73 _max_threads = other._max_threads;
75 _runners = other._runners;
76 _winner = other._winner;
77 _winner_index = other._winner_index;
82 : _max_threads(std::
move(other._max_threads)),
84 _runners(std::
move(other._runners)),
85 _winner(std::
move(other._winner)),
86 _winner_index(std::
move(other._winner_index)) {}
89 Race& operator=(Race
const& other) {
91 _max_threads = other._max_threads;
93 _runners = other._runners;
94 _winner = other._winner;
95 _winner_index = other._winner_index;
100 Race& operator=(Race&& other) {
102 _max_threads =
std::move(other._max_threads);
106 _winner_index =
std::move(other._winner_index);
113 Race& max_threads(
size_t val)
noexcept {
114 LIBSEMIGROUPS_ASSERT(val != 0);
119 [[nodiscard]]
size_t max_threads() const noexcept {
125 [[nodiscard]] std::shared_ptr<Runner> winner() {
130 [[nodiscard]]
size_t winner_index()
const {
131 return _winner_index;
134 [[nodiscard]]
size_t winner_index() {
136 return _winner_index;
139 [[nodiscard]]
bool finished() const noexcept {
140 return _winner !=
nullptr && _winner->finished();
144 void add_runner(std::shared_ptr<Runner>);
146 using const_iterator =
147 typename std::vector<std::shared_ptr<Runner>>::const_iterator;
149 [[nodiscard]] const_iterator begin() const noexcept {
150 return _runners.cbegin();
153 [[nodiscard]] const_iterator end() const noexcept {
154 return _runners.cend();
158 [[nodiscard]] const_iterator cbegin() const noexcept {
159 return _runners.cbegin();
163 [[nodiscard]] const_iterator cend() const noexcept {
164 return _runners.cend();
170 [[nodiscard]]
bool empty() const noexcept {
171 return _runners.empty();
175 [[nodiscard]]
size_t number_of_runners() const noexcept {
176 return _runners.size();
183 void run_for(std::chrono::nanoseconds);
191 template <
typename Func>
192 void run_until(Func&& func) {
194 std::is_same_v<std::invoke_result_t<Func>,
bool>,
195 "the result type of calling an object of type Func (the template "
196 "parameter) must be bool!");
206 report_default(
"{}: running until predicate returns true or finished\n",
208 run_func([&func](std::shared_ptr<Runner> r) ->
void {
213 template <
typename T>
215 return find_runner<T>() !=
nullptr;
218 template <
typename T>
219 [[nodiscard]] std::shared_ptr<T> find_runner()
const {
220 static_assert(std::is_base_of<Runner, T>::value,
221 "the template parameter must be derived from Runner");
226 [](std::shared_ptr<Runner>
const& m) {
227 auto& r = *(m.get());
228 return typeid(r) == typeid(T);
230 if (it != _runners.end()) {
237 void erase_runners(const_iterator pos) {
241 void erase_runners(const_iterator first, const_iterator last) {
242 _runners.erase(first, last);
246 void clear_runners_after_race() {
247 if (_winner !=
nullptr) {
248 for (
auto rnnr : _runners) {
249 if (rnnr != _winner) {
254 _runners.push_back(_winner);
259 template <
typename Func>
260 void run_func(Func&& func) {
262 std::is_same_v<std::invoke_result_t<Func, std::shared_ptr<Runner>>,
264 "the result type of calling an object of type Func (the template "
265 "parameter) must be void!");
266 using libsemigroups::detail::string_time;
267 LIBSEMIGROUPS_ASSERT(!empty());
269 if (_winner ==
nullptr) {
270 size_t nr_threads =
std::min(_runners.size(), _max_threads);
271 if (nr_threads == 1) {
273 func(_runners.at(0));
274 if (_runners.at(0)->success()) {
275 _winner = _runners.at(0);
277 clear_runners_after_race();
284 for (
size_t i = 0; i < _runners.size(); ++i) {
285 if (_runners[i]->success()) {
288 _winner = _runners[i];
294 clear_runners_after_race();
299 std::vector<std::thread::id> tids(_runners.size(),
307 LIBSEMIGROUPS_ASSERT(nr_threads != 0);
309 auto thread_func = [
this, &func, &tids](
size_t pos) {
312 func(_runners.at(pos));
313 }
catch (std::exception
const& e) {
314 size_t tid = thread_id(tids[pos]);
323 std::lock_guard<std::mutex> lg(_mtx);
324 if (_runners.at(pos)->success()) {
325 for (
auto it = _runners.begin(); it < _runners.begin() + pos;
329 for (
auto it = _runners.begin() + pos + 1; it < _runners.end();
338 std::vector<std::thread> t;
339 for (
size_t i = 0; i < nr_threads; ++i) {
340 t.
push_back(std::thread(thread_func, i));
342 for (
size_t i = 0; i < nr_threads; ++i) {
348 for (
auto method = _runners.begin(); method < _runners.end();
350 if ((*method)->success()) {
351 LIBSEMIGROUPS_ASSERT(_winner ==
nullptr);
353 _winner_index = method - _runners.begin();
354 size_t tid = thread_id(tids.at(method - _runners.begin()));
359 clear_runners_after_race();
Reporter const & reset_start_time() const
Reset the start time (and last report) to now.
Definition runner.hpp:250
std::string const & report_prefix() const noexcept
Get the current prefix string for reporting.
Definition runner.hpp:320
static std::chrono::nanoseconds delta(std::chrono::high_resolution_clock::time_point const &t)
The time between a given point and now.
Definition runner.hpp:65
time_point start_time() const noexcept
Get the start time.
Definition runner.hpp:238
Undefined const UNDEFINED
Value for something undefined.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:95
T hardware_concurrency(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
void report_default(std::string_view sv, Args &&... args)
No doc.
Definition report.hpp:157
T static_pointer_cast(T... args)