iterative-solver 0.0
 
Loading...
Searching...
No Matches
Logger.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LOGGER_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LOGGER_H
3#include <cmath>
4#include <complex>
5#include <concepts>
6#include <cstddef>
7#include <format>
8#include <functional>
9#include <iomanip>
10#include <limits>
11#include <optional>
12#include <ranges>
13#include <sstream>
14#include <string>
15#include <string_view>
16#include <type_traits>
17#include <typeinfo>
18#include <utility>
19#include <vector>
20
21#include <molpro/iostream.h>
22
59
63enum class Verbosity : short {
64 Trace,
65 Debug,
66 Info,
67 None,
68};
69
73enum class Severity : short {
74 Normal,
75 Warning,
76 Error,
77 Fatal,
78};
79
83constexpr const std::size_t default_precision = std::numeric_limits<std::size_t>::max();
84
88template <typename Scalar>
89using real_t = decltype(std::abs(std::declval<Scalar>()));
90
91namespace detail {
92template <typename T>
93struct is_complex : std::false_type {};
94template <typename T>
95struct is_complex<std::complex<T>> : std::true_type {};
96} // namespace detail
97
101template <typename T>
102concept complex_number = detail::is_complex<std::remove_cvref_t<T>>::value;
103
107template <typename T>
108concept pair_like = requires(const std::remove_cvref_t<T> &t) {
109 t.first;
110 t.second;
111};
112
116template <typename T>
117concept streamable = requires(std::ostream &stream, const std::remove_cvref_t<T> &t) { stream << t; };
118
122template <typename T>
123concept formattable = requires(const std::remove_cvref_t<T> &t, std::format_context ctx) {
124 std::formatter<std::remove_cvref_t<T>>().format(t, ctx);
125};
126
130template <typename T>
131concept string_like = std::convertible_to<const std::remove_cvref_t<T> &, std::string_view>;
132
133
134namespace detail {
136template <typename T>
137consteval bool is_printable_range() {
138 if constexpr (std::ranges::input_range<const T>)
139 return !std::same_as<std::remove_cvref_t<std::ranges::range_reference_t<const T>>, T>;
140 else
141 return false;
142}
143
145template <typename T>
146consteval bool is_stringifiable() {
147 using U = std::remove_cvref_t<T>;
148 if constexpr (string_like<U> || complex_number<U> || std::floating_point<U>) {
149 return true;
150 } else if constexpr (pair_like<U>) {
153 } else if constexpr (is_printable_range<U>()) {
155 } else {
157 }
158}
159} // namespace detail
160
164template <typename T>
165concept stringifiable = detail::is_stringifiable<T>();
166
176template <typename T>
177 requires stringifiable<T>
178std::string stringify(const T &t, std::size_t precision = default_precision) {
179 using U = std::remove_cvref_t<T>;
180 const bool precise = precision != default_precision;
181
182 if constexpr (string_like<U>) {
183 return std::string(std::string_view(t));
184 } else if constexpr (complex_number<U> || (std::floating_point<U> && !formattable<U>)) {
185 std::ostringstream stream;
186 if (precise)
188 stream << t;
189 return stream.str();
190 } else if constexpr (std::floating_point<U>) {
191 return precise ? std::format("{:.{}}", t, precision) : std::format("{}", t);
192 } else if constexpr (pair_like<U>) {
193 return "{ " + stringify(t.first, precision) + ": " + stringify(t.second, precision) + " }";
194 } else if constexpr (detail::is_printable_range<U>()) {
195 std::string result = "[";
196 bool first = true;
197 for (auto &&element : t) {
198 if (!first)
199 result += ", ";
200 first = false;
201 result += stringify(element, precision);
202 }
203 return result + "]";
204 } else if constexpr (formattable<U>) {
205 if (precise) {
206 try {
207 return std::vformat("{:." + std::to_string(precision) + "}", std::make_format_args(t));
208 } catch (const std::format_error &) {
209 // the type's formatter has no notion of precision
210 }
211 }
212 return std::format("{}", t);
213 } else {
214 std::ostringstream stream;
215 if (precise)
217 stream << t;
218 return stream.str();
219 }
220}
221
225template <typename Ctx>
226concept event_context = requires {
227 { Ctx::name } -> std::convertible_to<std::string_view>;
228 typename Ctx::Payload;
229};
230
234template <typename Ctx>
235concept formattable_context = event_context<Ctx> && requires(const typename Ctx::Payload &p) {
236 { Ctx::format(p) } -> std::convertible_to<std::string>;
237};
238
242template <typename Ctx>
244 requires Ctx::is_data_dump;
245};
246
250struct Generic {
251 static constexpr std::string_view name = "Generic";
252 struct Payload {};
253};
254
258template <typename T>
259struct DataDump {
260 static constexpr std::string_view name = "DataDump";
261 static constexpr bool is_data_dump = true;
262 struct Payload {
263 const T &data;
264 std::size_t precision;
265 };
266 static std::string format(const Payload &p)
267 requires stringifiable<T>
268 {
269 return stringify(p.data, p.precision);
270 }
271};
272
276inline std::string compose(std::string_view message, std::string_view suffix) {
277 if (suffix.empty())
278 return std::string(message);
279 if (!message.empty() && message.back() != ' ')
280 return std::string(message) + " -> " + std::string(suffix);
281 return std::string(message) + std::string(suffix);
282}
283
287class Record {
288public:
289 std::string_view context;
292 std::string_view message;
293
297 const std::type_info &type() const { return *m_type; }
298
302 template <event_context Ctx>
303 bool is() const {
304 return *m_type == typeid(Ctx);
305 }
306
310 template <event_context Ctx>
311 const typename Ctx::Payload *get() const {
312 return is<Ctx>() ? static_cast<const typename Ctx::Payload *>(m_payload) : nullptr;
313 }
314
318 std::string text() const { return m_format ? compose(message, m_format(m_payload)) : std::string(message); }
319
323 bool is_data_dump() const { return m_data_dump; }
324
325 template <event_context Ctx>
327 const typename Ctx::Payload &payload) {
328 Record record{Ctx::name, severity, verbosity, message};
329 record.m_type = &typeid(Ctx);
330 record.m_payload = &payload;
331 record.m_data_dump = data_dump_context<Ctx>;
332 if constexpr (formattable_context<Ctx>)
333 record.m_format = [](const void *p) {
334 return std::string(Ctx::format(*static_cast<const typename Ctx::Payload *>(p)));
335 };
336 return record;
337 }
338
339private:
340 Record(std::string_view context, Severity severity, Verbosity verbosity, std::string_view message)
342
343 const std::type_info *m_type = nullptr;
344 const void *m_payload = nullptr;
345 std::string (*m_format)(const void *) = nullptr;
346 bool m_data_dump = false;
347};
348
352struct Filter {
353 std::optional<Severity> min_severity;
354 std::optional<Verbosity> verbosity;
355 std::optional<bool> data_dumps;
356
358 static Filter all() { return {Severity::Normal, Verbosity::Trace, true}; }
359};
360
361} // namespace molpro::linalg::itsolv::log
362
363namespace molpro::linalg::itsolv {
364
370class Logger {
371public:
372 using Sink = std::function<void(const log::Record &)>;
373 using SinkId = std::size_t;
374
378 virtual ~Logger() = default;
379
384 SinkId add_sink(Sink sink, log::Filter filter = {}) {
385 m_sinks.push_back({m_next_id, filter, nullptr, std::move(sink)});
386 return m_next_id++;
387 }
388
395 template <log::event_context Ctx, typename F>
396 requires std::invocable<F &, const log::Record &, const typename Ctx::Payload &>
397 SinkId on(F &&f) {
398 m_sinks.push_back({m_next_id, log::Filter::all(), &typeid(Ctx),
399 [f = std::forward<F>(f)](const log::Record &record) mutable { f(record, *record.get<Ctx>()); }});
400 return m_next_id++;
401 }
402
407 std::erase_if(m_sinks, [id](const SinkEntry &entry) { return entry.id == id; });
408 }
409
415 template <log::event_context Ctx, typename MakePayload>
416 requires std::invocable<MakePayload &>
417 void emit(log::Severity severity, log::Verbosity verbosity, std::string_view message, MakePayload &&make) const {
418 if (!wants(typeid(Ctx), severity, verbosity, log::data_dump_context<Ctx>))
419 return;
420 const typename Ctx::Payload payload = make();
421 dispatch(log::Record::make<Ctx>(severity, verbosity, message, payload));
422 }
423
428 template <log::event_context Ctx>
430 return wants(typeid(Ctx), severity, verbosity, log::data_dump_context<Ctx>);
431 }
432
436 template <log::event_context Ctx>
437 requires std::default_initializable<typename Ctx::Payload>
438 void emit(log::Severity severity, log::Verbosity verbosity, std::string_view message) const {
439 emit<Ctx>(severity, verbosity, message, [] { return typename Ctx::Payload{}; });
440 }
441
445 template <typename... Ts>
446 void msg(log::Severity severity, log::Verbosity verbosity, std::string_view message, const Ts &...args) const {
447 static_assert((log::stringifiable<Ts> && ...), "All types passed to logger must be stringify-able");
448 if (!wants(typeid(log::Generic), severity, verbosity, false))
449 return;
451 if constexpr (sizeof...(args) > 0) {
452 std::string arg_str;
453 bool first = true;
454 ((arg_str += (first ? "" : ", ") + log::stringify(args), first = false), ...);
455 const std::string text = log::compose(message, arg_str);
456 dispatch(log::Record::make<log::Generic>(severity, verbosity, text, payload));
457 } else {
458 dispatch(log::Record::make<log::Generic>(severity, verbosity, message, payload));
459 }
460 }
461
462 template <typename... Ts>
463 void trace(std::string_view message, const Ts &...args) const {
465 }
466
467 template <typename... Ts>
468 void debug(std::string_view message, const Ts &...args) const {
470 }
471
472 template <typename... Ts>
473 void info(std::string_view message, const Ts &...args) const {
475 }
476
477 template <typename... Ts>
478 void warn(std::string_view message, const Ts &...args) const {
480 }
481
482 template <typename... Ts>
483 void error(std::string_view message, const Ts &...args) const {
485 }
486
487 template <typename... Ts>
488 void fatal(std::string_view message, const Ts &...args) const {
490 }
491
495 template <std::size_t precision = log::default_precision, typename T>
496 void data_dump(std::string_view what, const T &data) const {
498 [&] { return typename log::DataDump<T>::Payload{data, precision}; });
499 }
500
501 log::Severity min_severity() const { return m_min_severity; }
502
503 void set_min_severity(log::Severity severity) { m_min_severity = severity; }
504
505 log::Verbosity verbosity() const { return m_verbosity; }
506
508
509 bool data_dumps_enabled() const { return m_dump_data; }
510
511 void enable_data_dumps(bool enable) { m_dump_data = enable; }
512
513 bool default_output() const { return m_default_output; }
514
518 void set_default_output(bool enable) { m_default_output = enable; }
519
520protected:
526 virtual void default_message_handler(std::string_view ctx, log::Severity severity, log::Verbosity verbosity,
527 std::string_view msg) const {
528 bool add_colon = false;
529 switch (severity) {
531 break;
533 molpro::cout << "[WARNING]";
534 add_colon = true;
535 break;
537 molpro::cout << "[ERROR]:";
538 add_colon = true;
539 break;
541 molpro::cout << "[FATAL]:";
542 add_colon = true;
543 break;
544 }
545 switch (verbosity) {
547 break;
549 molpro::cout << "[INFO]";
550 add_colon = true;
551 break;
553 molpro::cout << "[DEBUG]";
554 add_colon = true;
555 break;
557 molpro::cout << "[TRACE]";
558 add_colon = true;
559 break;
560 };
561
562 if (ctx != log::Generic::name) {
563 molpro::cout << "[" << ctx << "]";
564 add_colon = true;
565 }
566
567 molpro::cout << (add_colon ? ": " : "") << msg;
568 if (severity >= log::Severity::Error) {
569 molpro::cout << std::endl;
570 } else {
571 molpro::cout << "\n";
572 }
573 }
574
575private:
576 struct SinkEntry {
577 SinkId id;
578 log::Filter filter;
579 const std::type_info *context;
580 Sink sink;
581 };
582
583 bool passes(const log::Filter &filter, log::Severity severity, log::Verbosity verbosity, bool data_dump) const {
584 return severity >= filter.min_severity.value_or(m_min_severity) &&
585 verbosity >= filter.verbosity.value_or(m_verbosity) &&
586 (!data_dump || filter.data_dumps.value_or(m_dump_data));
587 }
588
589 bool wants(const std::type_info &context, log::Severity severity, log::Verbosity verbosity, bool data_dump) const {
590 if (m_default_output && passes({}, severity, verbosity, data_dump))
591 return true;
592 for (const auto &entry : m_sinks)
593 if ((!entry.context || *entry.context == context) && passes(entry.filter, severity, verbosity, data_dump))
594 return true;
595 return false;
596 }
597
598 void dispatch(const log::Record &record) const {
599 const bool data_dump = record.is_data_dump();
600 for (const auto &entry : m_sinks)
601 if ((!entry.context || *entry.context == record.type()) &&
602 passes(entry.filter, record.severity, record.verbosity, data_dump))
603 entry.sink(record);
604 if (m_default_output && passes({}, record.severity, record.verbosity, data_dump))
605 default_message_handler(record.context, record.severity, record.verbosity, record.text());
606 }
607
611 log::Severity m_min_severity = log::Severity::Normal;
613 bool m_dump_data = false;
615 bool m_default_output = true;
617 std::vector<SinkEntry> m_sinks;
618 SinkId m_next_id = 1;
619};
620
621} // namespace molpro::linalg::itsolv
622
623#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_LOGGER_H
Logger class implementation. Provides (customizable) logging functionalities.
Definition Logger.h:370
void set_min_severity(log::Severity severity)
Definition Logger.h:503
void fatal(std::string_view message, const Ts &...args) const
Definition Logger.h:488
bool is_wanted(log::Severity severity, log::Verbosity verbosity) const
Definition Logger.h:429
void msg(log::Severity severity, log::Verbosity verbosity, std::string_view message, const Ts &...args) const
Logs a free-text message (context log::Generic). The arguments are stringified and appended.
Definition Logger.h:446
Logger(log::Severity min_severity=log::Severity::Normal, log::Verbosity verbosity=log::Verbosity::Info, bool enable_data_dumps=false)
Definition Logger.h:375
void info(std::string_view message, const Ts &...args) const
Definition Logger.h:473
void warn(std::string_view message, const Ts &...args) const
Definition Logger.h:478
void emit(log::Severity severity, log::Verbosity verbosity, std::string_view message) const
Emits an event of a context whose payload is default-constructible (usually empty)
Definition Logger.h:438
std::function< void(const log::Record &)> Sink
Definition Logger.h:372
void trace(std::string_view message, const Ts &...args) const
Definition Logger.h:463
log::Verbosity verbosity() const
Definition Logger.h:505
void error(std::string_view message, const Ts &...args) const
Definition Logger.h:483
SinkId add_sink(Sink sink, log::Filter filter={})
Registers a sink receiving all events that pass the given filter.
Definition Logger.h:384
void emit(log::Severity severity, log::Verbosity verbosity, std::string_view message, MakePayload &&make) const
Emits an event of context Ctx.
Definition Logger.h:417
void remove_sink(SinkId id)
Removes a previously registered sink.
Definition Logger.h:406
bool default_output() const
Definition Logger.h:513
virtual void default_message_handler(std::string_view ctx, log::Severity severity, log::Verbosity verbosity, std::string_view msg) const
Built-in text output. Receives every event passing the logger's thresholds and data-dump flag.
Definition Logger.h:526
bool data_dumps_enabled() const
Definition Logger.h:509
std::size_t SinkId
Definition Logger.h:373
void set_default_output(bool enable)
Switches the built-in text output (default_message_handler()) on or off.
Definition Logger.h:518
log::Severity min_severity() const
Definition Logger.h:501
void debug(std::string_view message, const Ts &...args) const
Definition Logger.h:468
void data_dump(std::string_view what, const T &data) const
Dumps data (context log::DataDump<T>, verbosity Trace). Nothing is copied.
Definition Logger.h:496
SinkId on(F &&f)
Registers f(const log::Record &, const Ctx::Payload &) to be called for every event of context Ctx.
Definition Logger.h:397
void enable_data_dumps(bool enable)
Definition Logger.h:511
void set_verbosity(log::Verbosity verbosity)
Definition Logger.h:507
A single logged event, as passed to sinks.
Definition Logger.h:287
std::string_view message
The message without the payload's text representation.
Definition Logger.h:292
bool is_data_dump() const
Definition Logger.h:323
Severity severity
Definition Logger.h:290
const Ctx::Payload * get() const
Definition Logger.h:311
static Record make(Severity severity, Verbosity verbosity, std::string_view message, const typename Ctx::Payload &payload)
Definition Logger.h:326
bool is() const
Definition Logger.h:303
const std::type_info & type() const
Definition Logger.h:297
std::string text() const
Definition Logger.h:318
Verbosity verbosity
Definition Logger.h:291
std::string_view context
Name of the context.
Definition Logger.h:289
consteval bool is_stringifiable()
Mirrors the branches of stringify(), in the same order.
Definition Logger.h:146
consteval bool is_printable_range()
Whether T is a range whose elements are of a different type than T (to exclude e.g....
Definition Logger.h:137
Definition IterativeSolverTemplate.h:82
constexpr const std::size_t default_precision
Definition Logger.h:83
decltype(std::abs(std::declval< Scalar >())) real_t
Definition Logger.h:89
std::string compose(std::string_view message, std::string_view suffix)
Definition Logger.h:276
std::string stringify(const T &t, std::size_t precision=default_precision)
Converts the given object into a string.
Definition Logger.h:178
Verbosity
Different levels of logging.
Definition Logger.h:63
Severity
Severity of a given message.
Definition Logger.h:73
4-parameter interpolation of a 1-dimensional function given two points for which function values and ...
Definition helper.h:14
std::unique_ptr< LinearEigensystem< R, Q, P > > create_LinearEigensystem(const LinearEigensystemOptions &options, const std::shared_ptr< ArrayHandlers< R, Q, P > > &handlers=std::make_shared< molpro::linalg::itsolv::ArrayHandlers< R, Q, P > >())
Definition SolverFactory.h:111
std::size_t precision
Requested precision (default_precision if unspecified)
Definition Logger.h:264
const T & data
The dumped data.
Definition Logger.h:263
static constexpr bool is_data_dump
Definition Logger.h:261
static std::string format(const Payload &p)
Definition Logger.h:266
static constexpr std::string_view name
Definition Logger.h:260
Selects which events an untyped sink receives. Unset fields inherit the logger's current settings.
Definition Logger.h:352
static Filter all()
A filter that lets everything pass.
Definition Logger.h:358
std::optional< bool > data_dumps
Whether data dumps are passed on.
Definition Logger.h:355
std::optional< Severity > min_severity
Lowest severity that is passed on.
Definition Logger.h:353
std::optional< Verbosity > verbosity
Lowest verbosity that is passed on.
Definition Logger.h:354
static constexpr std::string_view name
Definition Logger.h:251