libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
runner.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2025 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19// This file contains two classes Runner and Race for competitively running
20// different functions/member functions in different threads, and obtaining the
21// winner.
22
23#ifndef LIBSEMIGROUPS_RUNNER_HPP_
24#define LIBSEMIGROUPS_RUNNER_HPP_
25
26#include <algorithm> // for max
27#include <array> // for array
28#include <atomic> // for atomic
29#include <chrono> // for time_point, nanoseconds
30#include <cstddef> // for size_t
31#include <functional> // for function
32#include <memory> // for unique_ptr
33#include <mutex> // for mutex
34#include <string> // for basic_string, string
35#include <string_view> // for basic_string_view
36#include <thread> // for sleep_for, thread
37#include <tuple> // for apply
38#include <utility> // for move, forward
39#include <vector> // for vector
40
41#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
42
43#include "detail/function-ref.hpp" // for FunctionRef
44#include "detail/report.hpp" // for report_default
45#include "detail/string.hpp" // for unicode_string_length
46
47namespace libsemigroups {
48
59
68 // Not noexcept because std::chrono::duration_cast isn't
69 [[nodiscard]] static inline std::chrono::nanoseconds
70 delta(std::chrono::high_resolution_clock::time_point const& t) {
73 return duration_cast<std::chrono::nanoseconds>(high_resolution_clock::now()
74 - t);
75 }
76
85
97 class Reporter {
98 public:
100 using time_point = std::chrono::high_resolution_clock::time_point;
103
104 private:
105 std::string _divider;
106 std::string _prefix;
107 nanoseconds _report_time_interval;
108
109 mutable std::atomic<time_point> _last_report;
110 mutable time_point _start_time;
111
112 public:
120 // not noexcept because std::string constructor isn't
122
134
136 Reporter(Reporter const& that);
137
140
143
146
147 ~Reporter() = default;
148
166 // not noexcept because operator- for time_points can throw.
167 // TODO(later) remove? Used by Action
168 [[nodiscard]] bool report() const;
169
191 [[deprecated]] Reporter& report_every(nanoseconds val) noexcept {
193 _report_time_interval = val;
194 return *this;
195 }
196
217 template <typename Time>
218 [[deprecated]] Reporter& report_every(Time t) noexcept {
219#pragma GCC diagnostic push
220#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
221 return report_every(nanoseconds(t));
222#pragma GCC diagnostic pop
223 }
224
236 [[deprecated]] [[nodiscard]] nanoseconds report_every() const noexcept {
237 return _report_time_interval;
238 }
239
252 [[nodiscard]] time_point start_time() const noexcept {
253 return _start_time;
254 }
255
261 // Not sure if this is noexcept or not,
262 // std::chrono::high_resolution_clock::now is noexcept, but JDM couldn't
263 // find the noexcept spec of the copy assignment operator of a time_point.
264 Reporter const& reset_start_time() const {
266 _start_time = _last_report;
267 return *this;
268 }
269
283 [[nodiscard]] time_point last_report() const noexcept {
284 return _last_report;
285 }
286
297 // Not sure if this is noexcept or not,
298 // std::chrono::high_resolution_clock::now is noexcept, but JDM couldn't
299 // find the noexcept spec of the copy assignment operator of a time_point.
302 return *this;
303 }
304
316 // Not noexcept because std::string::operator= isn't
318 _prefix = val;
319 return *this;
320 }
321
334 [[nodiscard]] std::string const& report_prefix() const noexcept {
335 return _prefix;
336 }
337
348 // Not noexcept because std::string::operator= isn't
349 // TODO(1) deprecate
351 _divider = val;
352 return *this;
353 }
354
366 // TODO(1) deprecate
367 [[nodiscard]] std::string const& report_divider() const noexcept {
368 return _divider;
369 }
370
379 if (!_divider.empty()) {
380 report_no_prefix(_divider, "");
381 }
382 }
383 };
384
404 class Runner : public Reporter {
405 public:
433
434 private:
436 // Runner - data - private
438
440 mutable std::atomic<state> _state;
441 detail::FunctionRef<bool(void)> _stopper;
442
443 public:
445 // Runner - constructors + destructor - public
447
454 // not noexcept because Reporter() isn't
456
468
476 Runner(Runner const& other);
477
485 Runner(Runner&& other);
486
494 Runner& operator=(Runner const& other);
495
504
505 virtual ~Runner();
506
508 // Runner - non-virtual member functions - public
510
511 // The following mem fns don't return a reference to Runner to avoid the
512 // unexpected behaviour of e.g. Sims1.run_for() returning a reference to not
513 // a Sims1.
514
519 // At the end of this either finished, or dead.
520 void run();
521
531 // At the end of this either finished, dead, or timed_out.
533
545 template <typename Time>
546 void run_for(Time t) {
548 }
549
557 // not noexcept because operator-(time_point, time_point) isn't
558 [[nodiscard]] inline bool timed_out() const {
559 return (running_for() ? delta(start_time()) >= _run_for
561 }
562
568 // At the end of this either finished, dead, or stopped_by_predicate.
569 template <typename Func>
570 void run_until(Func&& func);
571
575 void run_until(bool (*func)()) {
576 run_until(detail::FunctionRef<bool(void)>(func));
577 }
578
584 // not noexcept because it calls timed_out which is not noexcept
586
587 // TODO(doc)
588 std::string string_why_we_stopped() const;
589
601 // Not noexcept because finished_impl isn't
602 [[nodiscard]] bool finished() const;
603
610 [[nodiscard]] virtual bool success() const {
611 return finished();
612 }
613
626 [[nodiscard]] bool started() const noexcept {
628 }
629
642 [[nodiscard]] bool running() const noexcept {
646 }
647
658 void kill() noexcept {
659 set_state(state::dead);
660 }
661
674 [[nodiscard]] bool dead() const noexcept {
675 return current_state() == state::dead;
676 }
677
687 // not noexcept because timed_out isn't
688 [[nodiscard]] bool stopped() const {
689 return (running() ? (timed_out() || stopped_by_predicate())
691 }
692
709 // noexcept should depend on whether _stopper can throw or not
710 [[nodiscard]] inline bool stopped_by_predicate() const {
711 if (running_until()) {
712 LIBSEMIGROUPS_ASSERT(_stopper.valid());
713 return _stopper();
714 } else {
716 }
717 }
718
734 [[nodiscard]] bool running_for() const noexcept {
735 return _state == state::running_for;
736 }
737
751 [[nodiscard]] std::chrono::nanoseconds
752 running_for_how_long() const noexcept {
753 return _run_for;
754 }
755
771 [[nodiscard]] bool running_until() const noexcept {
772 return _state == state::running_until;
773 }
774
787 [[nodiscard]] state current_state() const noexcept {
788 return _state;
789 }
790
791 private:
792 virtual void run_impl() = 0;
793 [[nodiscard]] virtual bool finished_impl() const = 0;
794
795 void set_state(state stt) const noexcept {
796 // We can set the state back to never_run if run_impl throws, and we are
797 // restoring the old state.
798 if (!dead()) {
799 // It can be that *this* becomes dead after this function has been
800 // called.
801 _state = stt;
802 }
803 }
804 }; // class Runner
805} // namespace libsemigroups
806
807#include "runner.tpp"
808#endif // LIBSEMIGROUPS_RUNNER_HPP_
Reporter(Reporter &&that)
Default move constructor.
time_point last_report() const noexcept
Get the time point of the last report.
Definition runner.hpp:283
std::string const & report_divider() const noexcept
Get the current divider string for reporting.
Definition runner.hpp:367
bool report() const
Check if it is time to report.
Reporter & operator=(Reporter &&that)
Default move assignment operator.
nanoseconds report_every() const noexcept
Get the minimum elapsed time between reports.
Definition runner.hpp:236
Reporter const & reset_start_time() const
Reset the start time (and last report) to now.
Definition runner.hpp:264
Reporter & report_every(Time t) noexcept
Set the minimum elapsed time between reports in a unit of time other than nanoseconds.
Definition runner.hpp:218
Reporter & init()
Initialize an existing Reporter object.
Reporter & operator=(Reporter const &that)
Default copy assignment operator.
Reporter const & reset_last_report() const
Set the last report time point to now.
Definition runner.hpp:300
std::chrono::high_resolution_clock::time_point time_point
Alias for std::chrono::high_resolution_clock::time_point.
Definition runner.hpp:100
std::string const & report_prefix() const noexcept
Get the current prefix string for reporting.
Definition runner.hpp:334
Reporter & report_prefix(std::string const &val)
Set the prefix string for reporting.
Definition runner.hpp:317
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
void emit_divider()
Emits the current divider string for reporting.
Definition runner.hpp:378
Reporter()
Default constructor.
Reporter(Reporter const &that)
Default copy constructor.
std::chrono::nanoseconds nanoseconds
Alias for std::chrono::nanoseconds.
Definition runner.hpp:102
Reporter & report_every(nanoseconds val) noexcept
Set the minimum elapsed time between reports in nanoseconds.
Definition runner.hpp:191
time_point start_time() const noexcept
Get the start time.
Definition runner.hpp:252
Reporter & report_divider(std::string const &val)
Set the divider string for reporting.
Definition runner.hpp:350
void run()
Run until finished.
bool started() const noexcept
Check if run has been called at least once before.
Definition runner.hpp:626
void run_until(Func &&func)
Run until a nullary predicate returns true or finished.
void run_until(bool(*func)())
Run until a nullary predicate returns true or finished.
Definition runner.hpp:575
Runner & operator=(Runner &&other)
Move assignment operator.
void report_why_we_stopped() const
Report why run stopped.
bool stopped() const
Check if the runner is stopped.
Definition runner.hpp:688
bool dead() const noexcept
Check if the runner is dead.
Definition runner.hpp:674
void run_for(Time t)
Run for a specified amount of time.
Definition runner.hpp:546
Runner()
Default constructor.
bool running_until() const noexcept
Check if the runner is currently running until a nullary predicate returns true.
Definition runner.hpp:771
Runner & operator=(Runner const &other)
Copy assignment operator.
virtual bool success() const
Check if run has been run to completion successfully.
Definition runner.hpp:610
Runner(Runner &&other)
Move constructor.
std::chrono::nanoseconds running_for_how_long() const noexcept
Return the last value passed to run_for.
Definition runner.hpp:752
Runner & init()
Initialize an existing Runner object.
bool running() const noexcept
Check if currently running.
Definition runner.hpp:642
bool timed_out() const
Check if the amount of time passed to run_for has elapsed.
Definition runner.hpp:558
void run_for(std::chrono::nanoseconds t)
Run for a specified amount of time.
state
Enum class for the state of the Runner.
Definition runner.hpp:407
@ running_for
Definition runner.hpp:416
@ not_running
Definition runner.hpp:429
@ timed_out
Definition runner.hpp:422
@ stopped_by_predicate
Definition runner.hpp:425
@ running_to_finish
Definition runner.hpp:413
@ never_run
Definition runner.hpp:410
@ running_until
Definition runner.hpp:419
@ dead
Indicates that the Runner was killed (by another thread).
Definition runner.hpp:431
state current_state() const noexcept
Return the current state.
Definition runner.hpp:787
bool running_for() const noexcept
Check if the runner is currently running for a particular length of time.
Definition runner.hpp:734
bool finished() const
Check if run has been run to completion or not.
bool stopped_by_predicate() const
Check if the runner was stopped, or should stop, because of the argument last passed to run_until.
Definition runner.hpp:710
void kill() noexcept
Stop run from running (thread-safe).
Definition runner.hpp:658
Runner(Runner const &other)
Copy constructor.
T duration_cast(T... args)
constexpr std::chrono::nanoseconds FOREVER
Value indicating forever (system dependent but possibly approx. 292 years).
Definition runner.hpp:84
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
void report_no_prefix(std::string_view sv, Args &&... args)
No doc.
Definition report.hpp:181