FE 0.13.1
Header-only C++ frontend library
Loading...
Searching...
No Matches
log.h
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <concepts>
5
6#include <ostream>
7#include <print>
8#include <source_location>
9#include <string_view>
10#include <type_traits>
11
12#include "fe/assert.h"
13#include "fe/format.h"
14#include "fe/loc.h"
15#include "fe/term.h"
16
17namespace fe {
18
19/// Facility to log what you are doing.
20class Log {
21public:
22 enum class Level { Error, Warn, Info, Verbose, Debug, Trace };
23
24 /// @name Getters
25 ///@{
26 Level level() const { return max_level_; }
27 std::ostream& ostream() const {
28 assert(ostream_);
29 return *ostream_;
30 }
31 explicit operator bool() const { return ostream_; } ///< Checks if Log::ostream_ is set.
32 ///@}
33
34 /// @name Setters
35 ///@{
36 Log& set(std::ostream* ostream) {
37 ostream_ = ostream;
38 return *this;
39 }
40 Log& set(Level max_level) {
41 max_level_ = max_level;
42 return *this;
43 }
44 ///@}
45
46 /// A std::format_string that remembers where it was written.
47 template<class... Args>
48 struct FmtLoc {
49 template<class S>
50 requires std::convertible_to<const S&, std::string_view>
51 consteval FmtLoc(const S& fmt, std::source_location loc = std::source_location::current())
52 : fmt(fmt)
53 , loc(loc) {}
54
55 std::format_string<Args...> fmt;
56 std::source_location loc;
57 };
58
59 /// Puts the `Args` of a Log::FmtLoc parameter into a non-deduced context, so that they are deduced from the
60 /// trailing arguments and the format string keeps capturing its call site.
61 template<class... Args>
63
64 /// @name Log
65 /// Output @p fmt to Log::ostream; does nothing if Log::ostream is `nullptr`.
66 ///@{
67 template<class... Args>
68 void log(Level level, Loc loc, std::format_string<Args...> fmt, Args&&... args) const {
69 if (ostream_ && level <= max_level_) emit(level, loc, fmt, std::forward<Args>(args)...);
70 }
71
72 /// A std::source_location is no Loc: it points into *your* source, which has no fe::Src.
73 template<class... Args>
74 void log(Level level, std::source_location where, std::format_string<Args...> fmt, Args&&... args) const {
75 if (ostream_ && level <= max_level_)
76 emit(level, std::format("{}:{}", where.file_name(), where.line()), fmt, std::forward<Args>(args)...);
77 }
78
79 /// Points at the call site.
80 template<class... Args>
81 void log(Level level, Fmt<Args...> fmt, Args&&... args) const {
82 log(level, fmt.loc, fmt.fmt, std::forward<Args>(args)...);
83 }
84 ///@}
85
86 /// @name Level Shorthands
87 /// Log at a fixed Level, pointing at the call site.
88 ///@{
89 template<class... Args>
90 void e(Fmt<Args...> fmt, Args&&... args) const {
91 log(Level::Error, fmt, std::forward<Args>(args)...);
92 }
93 template<class... Args>
94 void w(Fmt<Args...> fmt, Args&&... args) const {
95 log(Level::Warn, fmt, std::forward<Args>(args)...);
96 }
97 template<class... Args>
98 void i(Fmt<Args...> fmt, Args&&... args) const {
99 log(Level::Info, fmt, std::forward<Args>(args)...);
100 }
101 template<class... Args>
102 void v(Fmt<Args...> fmt, Args&&... args) const {
103 log(Level::Verbose, fmt, std::forward<Args>(args)...);
104 }
105 ///@}
106
107 /// @name Debug Shorthands
108 /// Vaporize to nothingness in `Release` build; the arguments are still evaluated.
109 ///@{
110#ifndef NDEBUG
111 template<class... Args>
112 void d(Fmt<Args...> fmt, Args&&... args) const {
113 log(Level::Debug, fmt, std::forward<Args>(args)...);
114 }
115 template<class... Args>
116 void t(Fmt<Args...> fmt, Args&&... args) const {
117 log(Level::Trace, fmt, std::forward<Args>(args)...);
118 }
119#else
120 template<class... Args>
121 void d(Fmt<Args...>, Args&&...) const {}
122 template<class... Args>
123 void t(Fmt<Args...>, Args&&...) const {}
124#endif
125 ///@}
126
127 /// @name Breakpoints
128 ///@{
129 bool break_on_error = false;
130 bool break_on_warn = false;
131 ///@}
132
133 /// @name Conversions
134 ///@{
135 // clang-format off
136 static char level2acro(Level level) {
137 switch (level) {
138 case Level::Trace: return 'T';
139 case Level::Debug: return 'D';
140 case Level::Verbose: return 'V';
141 case Level::Info: return 'I';
142 case Level::Warn: return 'W';
143 case Level::Error: return 'E';
144 default: unreachable();
145 }
146 }
147
149 switch (level) {
150 case Level::Trace: return term::FG::Magenta;
151 case Level::Debug: return term::FG::Cyan;
152 case Level::Verbose: return term::FG::Blue;
153 case Level::Info: return term::FG::Green;
154 case Level::Warn: return term::FG::Yellow;
155 case Level::Error: return term::FG::Red;
156 default: unreachable();
157 }
158 }
159 // clang-format on
160 ///@}
161
162private:
163 template<class W, class... Args>
164 void emit(Level level, const W& where, std::format_string<Args...> fmt, Args&&... args) const {
165 std::print(ostream(), "{}{}:{}{}:{} ", level2color(level), level2acro(level), term::FG::Gray, where,
167 std::println(ostream(), fmt, std::forward<Args>(args)...);
169 }
170
171 std::ostream* ostream_ = nullptr;
172 Level max_level_ = Level::Error;
173};
174
175} // namespace fe
Collects diagnostics and hands each to the Diag that lays it out.
Definition error.h:27
Facility to log what you are doing.
Definition log.h:20
Log & set(std::ostream *ostream)
Definition log.h:36
void e(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:90
void log(Level level, std::source_location where, std::format_string< Args... > fmt, Args &&... args) const
A std::source_location is no Loc: it points into your source, which has no fe::Src.
Definition log.h:74
bool break_on_warn
Definition log.h:130
FmtLoc< std::type_identity_t< Args >... > Fmt
Puts the Args of a Log::FmtLoc parameter into a non-deduced context, so that they are deduced from th...
Definition log.h:62
static term::FG level2color(Level level)
Definition log.h:148
void d(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:112
static char level2acro(Level level)
Definition log.h:136
void t(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:116
Log & set(Level max_level)
Definition log.h:40
bool break_on_error
Definition log.h:129
Level level() const
Definition log.h:26
void w(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:94
void v(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:102
void log(Level level, Fmt< Args... > fmt, Args &&... args) const
Points at the call site.
Definition log.h:81
std::ostream & ostream() const
Definition log.h:27
void log(Level level, Loc loc, std::format_string< Args... > fmt, Args &&... args) const
Definition log.h:68
Level
Definition log.h:22
void i(Fmt< Args... > fmt, Args &&... args) const
Definition log.h:98
FG
Foreground colors that can be streamed into an std::ostream.
Definition term.h:60
@ Magenta
Definition term.h:66
Definition algo.h:17
void breakpoint()
Raise a breakpoint in the debugger.
Definition assert.h:41
void unreachable()
Definition assert.h:31
Location within a Src: the half-open byte range [Loc::begin, Loc::end).
Definition loc.h:46
A std::format_string that remembers where it was written.
Definition log.h:48
consteval FmtLoc(const S &fmt, std::source_location loc=std::source_location::current())
Definition log.h:51
std::format_string< Args... > fmt
Definition log.h:55