11#pragma once
22
3- #include < iostream>
43#include < atomic>
4+ #include < concepts>
5+ #include < format>
56#include < functional>
7+ #include < string>
68#include < string_view>
79
8- #include < vector>
9- #include < mutex>
10-
11- #include < algorithm>
12-
1310namespace sndx ::utility {
11+ struct LogLevel {
12+ using T = intmax_t ;
13+
14+ static constexpr T increment = 10 ;
15+
16+ static constexpr T Info = 0 ;
17+ static constexpr T Debug = Info - increment;
18+ static constexpr T Trace = Debug - increment;
19+
20+ static constexpr T Warning = Info + increment;
21+ static constexpr T Error = Warning + increment;
22+
23+ #ifdef _DEBUG
24+ static constexpr T Default = Debug;
25+ #else
26+ static constexpr T Default = Info;
27+ #endif
28+ [[nodiscard]]
29+ static constexpr std::string_view toString (T level) {
30+ if (level >= Error) {
31+ return " Error" ;
32+ }
33+ if (level >= Warning) {
34+ return " Warning" ;
35+ }
36+ if (level >= Info) {
37+ return " Info" ;
38+ }
39+ if (level >= Debug) {
40+ return " Debug" ;
41+ }
42+ return " Trace" ;
43+ }
44+ };
45+ using LogLevelT = LogLevel::T;
1446
15- template <typename CharT = char >
16- using Formatter = std::function<std::basic_string<CharT>(std::basic_string_view<CharT>)>;
17-
18- template <typename CharT = char >
19- std::basic_string<CharT> formatterNone (std::basic_string_view<CharT> str) { return std::basic_string<CharT>(str); }
20-
21- template <typename CharT = char >
2247 class Logger {
48+ private:
49+ std::atomic<LogLevelT> m_level{ LogLevel::Default };
50+
2351 protected:
24- std::basic_ostream<CharT> stream ;
52+ virtual void log_impl (LogLevelT level, std::string&& str) = 0 ;
2553
2654 public:
27- std::atomic_bool active;
2855
29- Logger (std::basic_streambuf<CharT>* target) :
30- active (false ), stream(target) {}
56+ template <class ... Args>
57+ void log (LogLevelT level, std::format_string<Args...> fmt, Args&&... args) {
58+ if (level >= m_level.load (std::memory_order_acquire)) {
59+ log_impl (level, std::format (fmt, std::forward<Args>(args)...));
60+ }
61+ }
3162
32- virtual void log (std::basic_string_view<CharT> msg) {
33- if (active) stream << msg;
63+ template <class ... Args>
64+ void vlog (LogLevelT level, std::string_view fmt, Args&&... args) {
65+ if (level >= m_level.load (std::memory_order_acquire)) {
66+ log_impl (level, std::vformat (fmt, std::make_format_args (args...)));
67+ }
3468 }
3569
36- bool setActive ( bool newVal) {
37- return active .exchange (newVal );
70+ auto setLevel (LogLevelT level) noexcept {
71+ return m_level .exchange (level, std::memory_order_acq_rel );
3872 }
3973
40- template <typename T>
41- Logger& operator <<(const T& msg) {
42- if (active) {
43- stream << msg;
44- }
45- return *this ;
74+ [[nodiscard]]
75+ auto level () const noexcept {
76+ return m_level.load (std::memory_order_acquire);
4677 }
4778
4879 virtual ~Logger () = default ;
49- };
50-
51- // Warning: operator<< is still raw logging
52- template <typename CharT = char >
53- class FormatLogger : public Logger <CharT> {
54- public:
55- Formatter<CharT> formatter;
5680
57- FormatLogger (std::basic_streambuf<CharT>* target, Formatter<CharT> formatter = formatterNone<CharT>) :
58- Logger<CharT>(target), formatter(formatter) {}
59-
60- void log (std::basic_string_view<CharT> msg) {
61- Logger<CharT>::log (formatter (msg));
62- }
6381 };
6482
65- // non-owning container
66- template <typename CharT = char >
67- class LoggingContext {
68- protected:
69- std::vector<Logger<CharT>*> loggers;
70- std::mutex contextMtx;
71-
72- public:
73- using LoggerT = Logger<CharT>;
74-
75- void addLogger (LoggerT& logger) {
76- std::unique_lock lock (contextMtx);
77- loggers.emplace_back (&logger);
78- }
83+ template <std::invocable F>
84+ struct LazyArg {
85+ F fnc;
86+ };
87+ }
7988
80- void activateLogger (LoggerT& logger) {
81- logger.setActive (true );
82- std::unique_lock lock (contextMtx);
83- loggers.emplace_back (&logger);
84- }
89+ #define SNDX_MAKE_LAZY (func ) \
90+ sndx::utility::LazyArg{[&](){ return (func); }}
8591
86- void removeLogger (LoggerT& logger) {
87- std::unique_lock lock (contextMtx);
88- loggers.erase (std::ranges::remove (loggers, &logger));
92+ namespace std {
93+ template <std::invocable F>
94+ struct formatter <sndx::utility::LazyArg<F>> {
95+ constexpr auto parse (std::format_parse_context& ctx) {
96+ return ctx.begin ();
8997 }
9098
91- void log (std::basic_string_view<CharT> msg) {
92- std::unique_lock lock (contextMtx);
93- for (auto & logger : loggers) {
94- logger->log (msg);
95- }
99+ auto format (const sndx::utility::LazyArg<F>& arg, std::format_context& ctx) const {
100+ return std::format_to (ctx.out (), " {}" , arg.fnc ());
96101 }
97102 };
98- }
103+ }
0 commit comments