inline ops, fixes, rebase fixes, type_id

This commit is contained in:
Klaim (Joël Lamotte) 2025-07-09 11:33:43 +02:00 committed by Joël Lamotte (Klaim)
parent 11641d374e
commit 349de7a205
2 changed files with 88 additions and 59 deletions

View File

@ -8,11 +8,13 @@
#define MAMBA_CORE_LOGGING_HPP #define MAMBA_CORE_LOGGING_HPP
#include <concepts> #include <concepts>
#include <functional>
#include <optional> #include <optional>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <typeindex>
namespace mamba namespace mamba
{ {
@ -78,8 +80,9 @@ namespace mamba
// implementation // implementation
template <class T> template <class T>
concept LogHandler = std::equality_comparable<T> // concept LogHandler = std::movable<T> // at a minimum it must be movable
&& requires( and std::equality_comparable<T> // and comparable TODO: is this really necessary?
and requires(
T& handler, T& handler,
const T& const_handler // const T& const_handler //
, ,
@ -94,14 +97,14 @@ namespace mamba
handler.set_log_level(params.logging_level); // handler.set_log_level(params.logging_level); //
handler.set_params(std::as_const(params)); // handler.set_params(std::as_const(params)); //
handler.log(log_record); // handler.log(log_record); //
handler.log_stacktrace(); // log stacktrace in all sources handler.log_stacktrace(); // log stacktrace in all sources
handler.log_stacktrace(source); // log stacktrace only in handler.log_stacktrace(source); // log stacktrace only in
// specific source // specific source
handler.log_stacktrace_no_guards(); // log stacktrace in all handler.log_stacktrace_no_guards(); // log stacktrace in all
// sources // sources
handler.log_stacktrace_no_guards(source); // log stacktrace handler.log_stacktrace_no_guards(source); // log stacktrace
// only in specific // only in specific
// source // source
handler.flush(); // flush all handler.flush(); // flush all
handler.flush(std::optional<log_source>{}); // flush only a handler.flush(std::optional<log_source>{}); // flush only a
// specific source // specific source
@ -155,14 +158,15 @@ namespace mamba
return has_value(); return has_value();
} }
/// @returns An identifier for the stored object's type, or `std::nullopt` if there is no
/// stored object.
std::optional<std::type_index> type_id() const;
private: private:
struct Interface struct Interface
{ {
virtual ~Interface() = 0; virtual ~Interface() = 0;
}; };
}; };
@ -174,7 +178,7 @@ namespace mamba
-> AnyLogHandler; -> AnyLogHandler;
// not thread-safe // not thread-safe
auto get_log_handler() -> const AnyLogHandler&; auto get_log_handler() -> AnyLogHandler&;
// thread-safe // thread-safe
auto set_log_level(log_level new_level) -> log_level; auto set_log_level(log_level new_level) -> log_level;
@ -188,16 +192,16 @@ namespace mamba
// thread-safe // thread-safe
auto set_logging_params(LoggingParams new_params); auto set_logging_params(LoggingParams new_params);
// as thread-safe as handler's implementation // as thread-safe as handler's implementation if set
auto log(LogRecord record) noexcept -> void; auto log(LogRecord record) noexcept -> void;
// as thread-safe as handler's implementation // as thread-safe as handler's implementation if set
auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void; auto log_stacktrace(std::optional<log_source> source = {}) noexcept -> void;
// as thread-safe as handler's implementation // as thread-safe as handler's implementation if set
auto flush_logs(std::optional<log_source> source = {}) noexcept -> void; auto flush_logs(std::optional<log_source> source = {}) noexcept -> void;
// as thread-safe as handler's implementation // as thread-safe as handler's implementation if set
auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void; auto log_stacktrace_no_guards(std::optional<log_source> source = {}) noexcept -> void;
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
@ -227,6 +231,48 @@ namespace mamba
static void emit(const std::string& msg, const log_level& level); static void emit(const std::string& msg, const log_level& level);
}; };
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
// NOTE: the following definitions are inline to help with performance.
// TODO: find a better name?
template <typename Func, typename... Args>
requires std::invocable<Func, AnyLogHandler&, Args...>
auto call_log_handler_if_existing(Func&& func, Args&&... args) -> void
{
// TODO: consider enabling for user to specify that no check is needed (one less branch)
if (auto& log_handler = get_log_handler())
{
std::invoke(std::forward<Func>(func), log_handler, std::forward<Args>(args)...);
}
}
// as thread-safe as handler's implementation
inline auto log(LogRecord record) noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::log, std::move(record));
}
// as thread-safe as handler's implementation
inline auto log_stacktrace(std::optional<log_source> source) noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::log_stacktrace, std::move(source));
}
// as thread-safe as handler's implementation
inline auto flush_logs(std::optional<log_source> source) noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::flush, std::move(source));
}
// as thread-safe as handler's implementation
inline auto log_stacktrace_no_guards(std::optional<log_source> source) noexcept -> void
{
call_log_handler_if_existing(&AnyLogHandler::log_stacktrace_no_guards, std::move(source));
}
} }
} }

View File

@ -38,12 +38,13 @@ namespace mamba::logging
// require it with the documentation which should guide the implementers anyway. // require it with the documentation which should guide the implementers anyway.
AnyLogHandler current_log_handler; AnyLogHandler current_log_handler;
// FIXME: maybe generalize and move in synchronized_value.hpp // FIXME: maybe generalize and move in synchronized_value.hpp
template<std::default_initializable T, typename U, typename... OtherArgs> template <std::default_initializable T, typename U, typename... OtherArgs>
requires std::assignable_from<T&, U> requires std::assignable_from<T&, U>
auto auto synchronize_with_value(
synchronize_with_value(util::synchronized_value<T, OtherArgs...>& sv, const std::optional<U>& new_value) util::synchronized_value<T, OtherArgs...>& sv,
const std::optional<U>& new_value
)
{ {
auto synched_value = sv.synchronize(); auto synched_value = sv.synchronize();
if (new_value) if (new_value)
@ -54,7 +55,6 @@ namespace mamba::logging
} }
} }
auto set_log_handler(AnyLogHandler new_handler, std::optional<LoggingParams> maybe_params) auto set_log_handler(AnyLogHandler new_handler, std::optional<LoggingParams> maybe_params)
-> AnyLogHandler -> AnyLogHandler
{ {
@ -63,7 +63,6 @@ namespace mamba::logging
current_log_handler.stop_log_handling(); current_log_handler.stop_log_handling();
} }
auto previous_handler = std::exchange(current_log_handler, std::move(new_handler)); auto previous_handler = std::exchange(current_log_handler, std::move(new_handler));
auto params = synchronize_with_value(logging_params, maybe_params); auto params = synchronize_with_value(logging_params, maybe_params);
@ -72,9 +71,11 @@ namespace mamba::logging
{ {
current_log_handler.start_log_handling(*params, all_log_sources()); current_log_handler.start_log_handling(*params, all_log_sources());
} }
return previous_handler;
} }
auto get_log_handler() -> const AnyLogHandler& auto get_log_handler() -> AnyLogHandler&
{ {
return current_log_handler; return current_log_handler;
} }
@ -84,7 +85,10 @@ namespace mamba::logging
auto synched_params = logging_params.synchronize(); auto synched_params = logging_params.synchronize();
const auto previous_level = synched_params->logging_level; const auto previous_level = synched_params->logging_level;
synched_params->logging_level = new_level; synched_params->logging_level = new_level;
current_log_handler.set_log_level(synched_params->logging_level); if (current_log_handler)
{
current_log_handler.set_log_level(synched_params->logging_level);
}
return previous_level; return previous_level;
} }
@ -100,28 +104,14 @@ namespace mamba::logging
auto set_logging_params(LoggingParams new_params) auto set_logging_params(LoggingParams new_params)
{ {
logging_params = std::move(new_params); auto synched_params = logging_params.synchronize();
*synched_params = std::move(new_params);
if (current_log_handler)
{
current_log_handler.set_params(*synched_params);
}
} }
auto log(LogRecord record) noexcept -> void
{
current_log_handler.log(std::move(record));
}
auto log_stacktrace(std::optional<log_source> source) noexcept -> void
{
current_log_handler.log_stacktrace(std::move(source));
}
auto flush_logs(std::optional<log_source> source) noexcept -> void
{
current_log_handler.flush(std::move(source));
}
auto log_stacktrace_no_guards(std::optional<log_source> source) noexcept -> void
{
current_log_handler.log_stacktrace_no_guards(std::move(source));
}
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// AnyLogHandler // AnyLogHandler
@ -133,12 +123,10 @@ namespace mamba::logging
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// MessageLogger // MessageLogger
struct MessageLoggerData static std::atomic<bool> message_logger_use_buffer;
{
static std::mutex m_mutex; using MessageLoggerBuffer = std::vector<std::pair<std::string, log_level>>;
static bool use_buffer; static util::synchronized_value<MessageLoggerBuffer> message_logger_buffer;
static std::vector<std::pair<std::string, log_level>> m_buffer;
};
MessageLogger::MessageLogger(log_level level) MessageLogger::MessageLogger(log_level level)
: m_level(level) : m_level(level)
@ -147,14 +135,13 @@ namespace mamba::logging
MessageLogger::~MessageLogger() MessageLogger::~MessageLogger()
{ {
if (!MessageLoggerData::use_buffer && Console::is_available()) if (!message_logger_use_buffer && Console::is_available())
{ {
emit(m_stream.str(), m_level); emit(m_stream.str(), m_level);
} }
else else
{ {
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex); message_logger_buffer->push_back({ m_stream.str(), m_level });
MessageLoggerData::m_buffer.push_back({ m_stream.str(), m_level });
} }
} }
@ -178,22 +165,18 @@ namespace mamba::logging
void MessageLogger::activate_buffer() void MessageLogger::activate_buffer()
{ {
MessageLoggerData::use_buffer = true; message_logger_use_buffer = true;
} }
void MessageLogger::deactivate_buffer() void MessageLogger::deactivate_buffer()
{ {
MessageLoggerData::use_buffer = false; message_logger_use_buffer = false;
} }
void MessageLogger::print_buffer(std::ostream& /*ostream*/) void MessageLogger::print_buffer(std::ostream& /*ostream*/)
{ {
decltype(MessageLoggerData::m_buffer) tmp; MessageLoggerBuffer tmp;
message_logger_buffer->swap(tmp);
{
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
MessageLoggerData::m_buffer.swap(tmp);
}
for (const auto& [msg, level] : tmp) for (const auto& [msg, level] : tmp)
{ {