28#ifndef LIBSEMIGROUPS_DETAIL_RACE_HPP_
29#define LIBSEMIGROUPS_DETAIL_RACE_HPP_
43#include "libsemigroups/constants.hpp"
44#include "libsemigroups/debug.hpp"
45#include "libsemigroups/exception.hpp"
46#include "libsemigroups/runner.hpp"
53 class Race :
public Reporter {
56 std::vector<std::shared_ptr<Runner>> _runners;
57 std::shared_ptr<Runner> _winner;
75 Race(Race
const& other) : Race() {
77 _max_threads = other._max_threads;
79 _runners = other._runners;
80 _winner = other._winner;
81 _winner_index = other._winner_index;
86 : _max_threads(std::
move(other._max_threads)),
88 _runners(std::
move(other._runners)),
89 _winner(std::
move(other._winner)),
90 _winner_index(std::
move(other._winner_index)) {}
93 Race& operator=(Race
const& other) {
95 _max_threads = other._max_threads;
97 _runners = other._runners;
98 _winner = other._winner;
99 _winner_index = other._winner_index;
104 Race& operator=(Race&& other) {
106 _max_threads =
std::move(other._max_threads);
110 _winner_index =
std::move(other._winner_index);
117 Race& max_threads(
size_t val)
noexcept {
118 LIBSEMIGROUPS_ASSERT(val != 0);
123 [[nodiscard]]
size_t max_threads() const noexcept {
129 [[nodiscard]] std::shared_ptr<Runner> winner() {
134 [[nodiscard]]
size_t winner_index()
const {
135 return _winner_index;
138 [[nodiscard]]
size_t winner_index() {
140 return _winner_index;
143 [[nodiscard]]
bool finished() const noexcept {
144 return _winner !=
nullptr && _winner->finished();
148 void add_runner(std::shared_ptr<Runner>);
150 using const_iterator =
151 typename std::vector<std::shared_ptr<Runner>>::const_iterator;
153 [[nodiscard]] const_iterator begin() const noexcept {
154 return _runners.cbegin();
157 [[nodiscard]] const_iterator end() const noexcept {
158 return _runners.cend();
162 [[nodiscard]] const_iterator cbegin() const noexcept {
163 return _runners.cbegin();
167 [[nodiscard]] const_iterator cend() const noexcept {
168 return _runners.cend();
174 [[nodiscard]]
bool empty() const noexcept {
175 return _runners.empty();
179 [[nodiscard]]
size_t number_of_runners() const noexcept {
180 return _runners.size();
187 void run_for(std::chrono::nanoseconds);
195 template <
typename Func>
196 void run_until(Func&& func) {
198 std::is_same_v<std::invoke_result_t<Func>,
bool>,
199 "the result type of calling an object of type Func (the template "
200 "parameter) must be bool!");
210 report_default(
"{}: running until predicate returns true or finished\n",
212 run_func([&func](std::shared_ptr<Runner> r) ->
void {
217 template <
typename T>
219 return find_runner<T>() !=
nullptr;
222 template <
typename T>
223 [[nodiscard]] std::shared_ptr<T> find_runner()
const {
224 static_assert(std::is_base_of<Runner, T>::value,
225 "the template parameter must be derived from Runner");
230 [](std::shared_ptr<Runner>
const& m) {
231 auto& r = *(m.get());
232 return typeid(r) == typeid(T);
234 if (it != _runners.end()) {
241 void erase_runners(const_iterator pos) {
245 void erase_runners(const_iterator first, const_iterator last) {
246 _runners.erase(first, last);
250 void clear_runners_after_race() {
251 if (_winner !=
nullptr) {
252 for (
auto rnnr : _runners) {
253 if (rnnr != _winner) {
258 _runners.push_back(_winner);
263 template <
typename Func>
264 void run_func(Func&& func) {
266 std::is_same_v<std::invoke_result_t<Func, std::shared_ptr<Runner>>,
268 "the result type of calling an object of type Func (the template "
269 "parameter) must be void!");
270 using libsemigroups::detail::string_time;
271 LIBSEMIGROUPS_ASSERT(!empty());
273 if (_winner ==
nullptr) {
274 size_t nr_threads =
std::min(_runners.size(), _max_threads);
275 if (nr_threads == 1) {
277 func(_runners.at(0));
278 if (_runners.at(0)->success()) {
279 _winner = _runners.at(0);
281 clear_runners_after_race();
288 for (
size_t i = 0; i < _runners.size(); ++i) {
289 if (_runners[i]->success()) {
292 _winner = _runners[i];
298 clear_runners_after_race();
303 std::vector<std::thread::id> tids(_runners.size(),
311 LIBSEMIGROUPS_ASSERT(nr_threads != 0);
313 auto thread_func = [
this, &func, &tids](
size_t pos) {
316 func(_runners.at(pos));
317 }
catch (std::exception
const& e) {
318 size_t tid = thread_id(tids[pos]);
327 std::lock_guard<std::mutex> lg(_mtx);
328 if (_runners.at(pos)->success()) {
329 for (
auto it = _runners.begin(); it < _runners.begin() + pos;
333 for (
auto it = _runners.begin() + pos + 1; it < _runners.end();
342 std::vector<std::thread> t;
343 for (
size_t i = 0; i < nr_threads; ++i) {
344 t.
push_back(std::thread(thread_func, i));
346 for (
size_t i = 0; i < nr_threads; ++i) {
352 for (
auto method = _runners.begin(); method < _runners.end();
354 if ((*method)->success()) {
355 LIBSEMIGROUPS_ASSERT(_winner ==
nullptr);
357 _winner_index = method - _runners.begin();
358 size_t tid = thread_id(tids.at(method - _runners.begin()));
363 clear_runners_after_race();
Reporter const & reset_start_time() const
Reset the start time (and last report) to now.
Definition runner.hpp:255
std::string const & report_prefix() const noexcept
Get the current prefix string for reporting.
Definition runner.hpp:325
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:70
time_point start_time() const noexcept
Get the start time.
Definition runner.hpp:243
Undefined const UNDEFINED
Value for something undefined.
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:99
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:162
T static_pointer_cast(T... args)