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