libsemigroups  v3.1.2
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
report.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 a class for reporting things during a computation.
20
21#ifndef LIBSEMIGROUPS_DETAIL_REPORT_HPP_
22#define LIBSEMIGROUPS_DETAIL_REPORT_HPP_
23
24#include <chrono> // for std::chrono
25#include <cstddef> // for size_t
26#include <functional> // for std::function
27#include <mutex> // for mutex, lock_guard
28#include <string> // for string
29#include <thread> // for get_id, thread, thread::id
30#include <utility> // for pair
31
32#include "libsemigroups/exception.hpp" // LIBSEMIGROUPS_EXCEPTION
33
34#include "fmt.hpp" // for fmtlib includes
35#include "formatters.hpp" // for custom formatters
36#include "timer.hpp" // for string_format, to_strin
37
38namespace libsemigroups {
39
40 namespace detail {
41 using t_id = size_t;
42
43 t_id this_threads_id();
44 t_id thread_id(std::thread::id);
45 void reset_thread_ids();
46
47 bool is_report_suppressed_for(std::string_view);
48
49 // This class provides a thread-safe means of calling a function every
50 // second in a detached thread. The purpose of this class is so that the
51 // TickerImpl, which contains the data required by the function to be
52 // called, inside the Ticker, can outlive the Ticker, the TickerImpl is
53 // deleted by the function called in the thread.
54 // TODO(1) prevent too many Tickers being created at a time, really just
55 // launch a single thread to do reporting for the duration.
56 class Ticker {
57 class TickerImpl;
58
59 TickerImpl* _ticker_impl;
60
61 public:
62 // Construct a Ticker that calls \c func every \c time, until the Ticker
63 // object is destructed.
64 template <typename Func, typename Time = std::chrono::seconds>
65 explicit Ticker(Func&& func, Time time = std::chrono::seconds(1));
66
67 template <typename Func, typename Time = std::chrono::seconds>
68 void operator()(Func&& func, Time time = std::chrono::seconds(1));
69
70 Ticker() : _ticker_impl(nullptr) {}
71 Ticker(Ticker const&) = delete;
72 Ticker(Ticker&&) = delete;
73 Ticker& operator=(Ticker const&) = delete;
74 Ticker& operator=(Ticker&&) = delete;
75
76 ~Ticker();
77 };
78
79 // This object is a helper for formatting information reported by various
80 // classes in libsemigroups such as ToddCoxeterImpl, KnuthBendixImpl, etc.
81 //
82 // The idea is to store the rows in the _rows, and to properly align the
83 // values in each column. This is done by storing the rows and their widths,
84 // then using std::apply to call report_default on the properly aligned
85 // columns. This happens when the ReportCell object is destroyed.
86 template <size_t C>
87 class ReportCell {
88 private:
89 using Row = std::array<std::string, C + 1>;
90
91 std::array<size_t, C + 1> _col_widths;
92 std::vector<Row> _rows;
93
94 public:
95 ReportCell() : _col_widths(), _rows() {
96 _col_widths.fill(0);
97 }
98
99 ReportCell(ReportCell const&) = delete;
100 ReportCell(ReportCell&&) = delete;
101 ReportCell& operator=(ReportCell const&) = delete;
102 ReportCell& operator=(ReportCell&&) = delete;
103
104 ~ReportCell() {
105 emit();
106 }
107
108 // Set the minimum width of every column
109 ReportCell& min_width(size_t val) {
110 _col_widths.fill(val);
111 return *this;
112 }
113
114 // Set the minimum width of a specific column
115 ReportCell& min_width(size_t col, size_t val) {
116 LIBSEMIGROUPS_ASSERT(col < C);
117 _col_widths[col + 1] = val;
118 return *this;
119 }
120
121 // Insert a row using a format string and arguments
122 template <typename... Args>
123 void operator()(std::string_view fmt_str, Args&&... args);
124
125 // Insert a row using a function, format string, and arguments. The
126 // function is called on each of the arguments.
127 template <typename Func, typename... Args>
128 void operator()(Func&& f, char const* fmt_str, Args&&... args) {
129 operator()(fmt_str, f(args)...);
130 }
131
132 private:
133 size_t line_width() const;
134
135 void emit();
136 }; // ReportCell
137 } // namespace detail
138
140 bool reporting_enabled() noexcept;
141
143 template <typename... Args>
144 std::string fmt_default(std::string_view sv, Args&&... args) {
145 std::string prefix = fmt::format("#{}: ", detail::this_threads_id());
146 return prefix + fmt::format(sv, std::forward<Args>(args)...);
147 }
148
150 template <typename... Args>
151 void report_no_prefix(std::string_view sv, Args&&... args) {
152 static std::mutex mtx;
153
154 if (reporting_enabled()) {
156 fmt::print(sv, std::forward<Args>(args)...);
157 }
158 }
159
161 template <typename... Args>
162 void report_default(std::string_view sv, Args&&... args) {
163 if (reporting_enabled()) {
164 std::string_view prefix(sv);
165 auto pos = prefix.find(":");
166 if (pos != std::string::npos) {
167 prefix.remove_suffix(prefix.size() - prefix.find(":"));
168 if (detail::is_report_suppressed_for((prefix))) {
169 return;
170 }
171 }
173 }
174 }
175
177 static inline void
178 report_elapsed_time(std::string_view prefix,
179 libsemigroups::detail::Timer const& tmr) {
180 report_default("{} elapsed time {}", prefix, tmr);
181 }
182
192 struct ReportGuard {
198 explicit ReportGuard(bool val = true);
199 ~ReportGuard();
200 };
201
202 class SuppressReportFor {
203 std::string_view _prefix;
204
205 public:
206 explicit SuppressReportFor(std::string_view);
207 ~SuppressReportFor();
208 };
209} // namespace libsemigroups
210
211#include "report.tpp"
212
213#endif // LIBSEMIGROUPS_DETAIL_REPORT_HPP_
T forward(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
bool reporting_enabled() noexcept
No doc.
void report_default(std::string_view sv, Args &&... args)
No doc.
Definition report.hpp:162
static void report_elapsed_time(std::string_view prefix, libsemigroups::detail::Timer const &tmr)
No doc.
Definition report.hpp:178
std::string fmt_default(std::string_view sv, Args &&... args)
No doc.
Definition report.hpp:144
void report_no_prefix(std::string_view sv, Args &&... args)
No doc.
Definition report.hpp:151
ReportGuard(bool val=true)
Constructs a ReportGuard with reporting enabled by default.