libsemigroups  v3.5.3
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-2026 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 <atomic> // for atomic
27#include <chrono> // for nanoseconds, high_resolution_clock
28#include <memory> // for addressof
29#include <mutex> // for mutex
30#include <string> // for basic_string, string, char_traits
31#include <string_view> // for basic_string_view
32#include <type_traits> // for invoke_result_t, is_same_v
33#include <utility> // for forward
34
35#include "debug.hpp" // for LIBSEMIGROUPS_ASSERT
36
37#include "detail/fmt.hpp" // for print, format
38#include "detail/function-ref.hpp" // for FunctionRef
39#include "detail/report.hpp" // for report_default
40
41namespace libsemigroups {
42
53
62 // Not noexcept because std::chrono::duration_cast isn't
63 [[nodiscard]] static inline std::chrono::nanoseconds
64 delta(std::chrono::high_resolution_clock::time_point const& t) {
67 return duration_cast<std::chrono::nanoseconds>(high_resolution_clock::now()
68 - t);
69 }
70
79
91 class Reporter {
92 public:
94 using time_point = std::chrono::high_resolution_clock::time_point;
97
98 private:
99 std::string _divider;
100 std::string _prefix;
101 nanoseconds _report_time_interval;
102
103 mutable std::atomic<time_point> _last_report;
104 mutable time_point _start_time;
105
106 public:
114 // not noexcept because std::string constructor isn't
116
128
130 Reporter(Reporter const& that);
131
134
137
140
141 ~Reporter() = default;
142
160 // not noexcept because operator- for time_points can throw.
161 // TODO(later) remove? Used by Action
162 [[nodiscard]] bool report() const;
163
185 [[deprecated]] Reporter& report_every(nanoseconds val) noexcept {
187 _report_time_interval = val;
188 return *this;
189 }
190
211 template <typename Time>
212 [[deprecated]] Reporter& report_every(Time t) noexcept {
213#pragma GCC diagnostic push
214#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
215 return report_every(nanoseconds(t));
216#pragma GCC diagnostic pop
217 }
218
230 [[deprecated]] [[nodiscard]] nanoseconds report_every() const noexcept {
231 return _report_time_interval;
232 }
233
246 [[nodiscard]] time_point start_time() const noexcept {
247 return _start_time;
248 }
249
255 // Not sure if this is noexcept or not,
256 // std::chrono::high_resolution_clock::now is noexcept, but JDM couldn't
257 // find the noexcept spec of the copy assignment operator of a time_point.
258 Reporter const& reset_start_time() const {
260 _start_time = _last_report;
261 return *this;
262 }
263
277 [[nodiscard]] time_point last_report() const noexcept {
278 return _last_report;
279 }
280
291 // Not sure if this is noexcept or not,
292 // std::chrono::high_resolution_clock::now is noexcept, but JDM couldn't
293 // find the noexcept spec of the copy assignment operator of a time_point.
296 return *this;
297 }
298
310 // Not noexcept because std::string::operator= isn't
312 _prefix = val;
313 return *this;
314 }
315
328 [[nodiscard]] std::string const& report_prefix() const noexcept {
329 return _prefix;
330 }
331
342 // Not noexcept because std::string::operator= isn't
343 // TODO(1) deprecate
345 _divider = val;
346 return *this;
347 }
348
360 // TODO(1) deprecate
361 [[nodiscard]] std::string const& report_divider() const noexcept {
362 return _divider;
363 }
364
373 if (!_divider.empty()) {
374 report_no_prefix(_divider, "");
375 }
376 }
377 };
378
398 class Runner : public Reporter {
399 public:
427
428 private:
430 // Runner - data - private
432
433 mutable std::mutex _mtx;
435 mutable std::atomic<state> _state;
436 detail::FunctionRef<bool(void)> _stopper;
437
438 public:
440 // Runner - constructors + destructor - public
442
449 // not noexcept because Reporter() isn't
451
463
471 Runner(Runner const& other);
472
480 Runner(Runner&& other);
481
489 Runner& operator=(Runner const& other);
490
499
500 virtual ~Runner();
501
503 // Runner - non-virtual member functions - public
505
506 // The following mem fns don't return a reference to Runner to avoid the
507 // unexpected behaviour of e.g. Sims1.run_for() returning a reference to not
508 // a Sims1.
509
514 // At the end of this either finished, or dead.
515 void run();
516
526 // At the end of this either finished, dead, or timed_out.
528
540 template <typename Time>
541 void run_for(Time t) {
543 }
544
552 // not noexcept because operator-(time_point, time_point) isn't
553 [[nodiscard]] inline bool timed_out() const {
554 return (running_for() ? delta(start_time()) >= _run_for
556 }
557
563 // At the end of this either finished, dead, or stopped_by_predicate.
564 template <typename Func>
565 void run_until(Func&& func);
566
570 void run_until(bool (*func)()) {
571 run_until(detail::FunctionRef<bool(void)>(func));
572 }
573
578 // not noexcept because it calls timed_out which is not noexcept
580
581 // TODO(doc)
582 std::string string_why_we_stopped() const;
583
595 // Not noexcept because finished_impl isn't
596 [[nodiscard]] bool finished() const;
597
604 [[nodiscard]] virtual bool success() const {
605 return finished();
606 }
607
620 [[nodiscard]] bool started() const noexcept {
622 }
623
636 [[nodiscard]] bool running() const noexcept {
640 }
641
652 void kill() noexcept {
653 set_state(state::dead);
654 }
655
668 [[nodiscard]] bool dead() const noexcept {
669 return current_state() == state::dead;
670 }
671
681 // not noexcept because timed_out isn't
682 [[nodiscard]] bool stopped() const {
683 return (running() ? (timed_out() || stopped_by_predicate())
685 }
686
703 // noexcept should depend on whether _stopper can throw or not
704 [[nodiscard]] inline bool stopped_by_predicate() const {
705 if (running_until()) {
706 LIBSEMIGROUPS_ASSERT(_stopper.valid());
707 return _stopper();
708 } else {
710 }
711 }
712
728 [[nodiscard]] bool running_for() const noexcept {
729 return _state == state::running_for;
730 }
731
745 [[nodiscard]] std::chrono::nanoseconds
746 running_for_how_long() const noexcept {
747 return _run_for;
748 }
749
765 [[nodiscard]] bool running_until() const noexcept {
766 return _state == state::running_until;
767 }
768
781 [[nodiscard]] state current_state() const noexcept {
782 return _state;
783 }
784
785 private:
786 virtual void run_impl() = 0;
787 [[nodiscard]] virtual bool finished_impl() const = 0;
788
789 // Thread-safe
790 void set_state(state val) const noexcept;
791 }; // class Runner
792} // namespace libsemigroups
793#include "runner.tpp"
794#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:277
std::string const & report_divider() const noexcept
Get the current divider string for reporting.
Definition runner.hpp:361
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:230
Reporter const & reset_start_time() const
Reset the start time (and last report) to now.
Definition runner.hpp:258
Reporter & report_every(Time t) noexcept
Set the minimum elapsed time between reports in a unit of time other than nanoseconds.
Definition runner.hpp:212
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:294
std::chrono::high_resolution_clock::time_point time_point
Alias for std::chrono::high_resolution_clock::time_point.
Definition runner.hpp:94
std::string const & report_prefix() const noexcept
Get the current prefix string for reporting.
Definition runner.hpp:328
Reporter & report_prefix(std::string const &val)
Set the prefix string for reporting.
Definition runner.hpp:311
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:64
void emit_divider()
Emits the current divider string for reporting.
Definition runner.hpp:372
Reporter()
Default constructor.
Reporter(Reporter const &that)
Default copy constructor.
std::chrono::nanoseconds nanoseconds
Alias for std::chrono::nanoseconds.
Definition runner.hpp:96
Reporter & report_every(nanoseconds val) noexcept
Set the minimum elapsed time between reports in nanoseconds.
Definition runner.hpp:185
time_point start_time() const noexcept
Get the start time.
Definition runner.hpp:246
Reporter & report_divider(std::string const &val)
Set the divider string for reporting.
Definition runner.hpp:344
void run()
Run until finished.
bool started() const noexcept
Check if run has been called at least once before.
Definition runner.hpp:620
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:570
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:682
bool dead() const noexcept
Check if the runner is dead.
Definition runner.hpp:668
void run_for(Time t)
Run for a specified amount of time.
Definition runner.hpp:541
Runner()
Default constructor.
bool running_until() const noexcept
Check if the runner is currently running until a nullary predicate returns true.
Definition runner.hpp:765
Runner & operator=(Runner const &other)
Copy assignment operator.
virtual bool success() const
Check if run has been run to completion successfully.
Definition runner.hpp:604
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:746
Runner & init()
Initialize an existing Runner object.
bool running() const noexcept
Check if currently running.
Definition runner.hpp:636
bool timed_out() const
Check if the amount of time passed to run_for has elapsed.
Definition runner.hpp:553
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:401
@ running_for
Definition runner.hpp:410
@ not_running
Definition runner.hpp:423
@ timed_out
Definition runner.hpp:416
@ stopped_by_predicate
Definition runner.hpp:419
@ running_to_finish
Definition runner.hpp:407
@ never_run
Definition runner.hpp:404
@ running_until
Definition runner.hpp:413
@ dead
Indicates that the Runner was killed (by another thread).
Definition runner.hpp:425
state current_state() const noexcept
Return the current state.
Definition runner.hpp:781
bool running_for() const noexcept
Check if the runner is currently running for a particular length of time.
Definition runner.hpp:728
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:704
void kill() noexcept
Stop run from running (thread-safe).
Definition runner.hpp:652
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:78
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