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
#include <concepts>
#include <functional>
#include <optional>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <typeindex>
namespace mamba
{
@ -78,8 +80,9 @@ namespace mamba
// implementation
template <class T>
concept LogHandler = std::equality_comparable<T> //
&& requires(
concept LogHandler = std::movable<T> // at a minimum it must be movable
and std::equality_comparable<T> // and comparable TODO: is this really necessary?
and requires(
T& handler,
const T& const_handler //
,
@ -94,14 +97,14 @@ namespace mamba
handler.set_log_level(params.logging_level); //
handler.set_params(std::as_const(params)); //
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
// specific source
handler.log_stacktrace_no_guards(); // log stacktrace in all
// sources
handler.log_stacktrace_no_guards(source); // log stacktrace
// only in specific
// source
handler.log_stacktrace_no_guards(source); // log stacktrace
// only in specific
// source
handler.flush(); // flush all
handler.flush(std::optional<log_source>{}); // flush only a
// specific source
@ -155,14 +158,15 @@ namespace mamba
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:
struct Interface
{
virtual ~Interface() = 0;
};
};
@ -174,7 +178,7 @@ namespace mamba
-> AnyLogHandler;
// not thread-safe
auto get_log_handler() -> const AnyLogHandler&;
auto get_log_handler() -> AnyLogHandler&;
// thread-safe
auto set_log_level(log_level new_level) -> log_level;
@ -188,16 +192,16 @@ namespace mamba
// thread-safe
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;
// 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;
// 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;
// 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;
///////////////////////////////////////////////////////
@ -227,6 +231,48 @@ namespace mamba
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.
AnyLogHandler current_log_handler;
// 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>
auto
synchronize_with_value(util::synchronized_value<T, OtherArgs...>& sv, const std::optional<U>& new_value)
auto synchronize_with_value(
util::synchronized_value<T, OtherArgs...>& sv,
const std::optional<U>& new_value
)
{
auto synched_value = sv.synchronize();
if (new_value)
@ -54,7 +55,6 @@ namespace mamba::logging
}
}
auto set_log_handler(AnyLogHandler new_handler, std::optional<LoggingParams> maybe_params)
-> AnyLogHandler
{
@ -63,7 +63,6 @@ namespace mamba::logging
current_log_handler.stop_log_handling();
}
auto previous_handler = std::exchange(current_log_handler, std::move(new_handler));
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());
}
return previous_handler;
}
auto get_log_handler() -> const AnyLogHandler&
auto get_log_handler() -> AnyLogHandler&
{
return current_log_handler;
}
@ -84,7 +85,10 @@ namespace mamba::logging
auto synched_params = logging_params.synchronize();
const auto previous_level = synched_params->logging_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;
}
@ -100,28 +104,14 @@ namespace mamba::logging
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
@ -133,12 +123,10 @@ namespace mamba::logging
///////////////////////////////////////////////////////////////////
// MessageLogger
struct MessageLoggerData
{
static std::mutex m_mutex;
static bool use_buffer;
static std::vector<std::pair<std::string, log_level>> m_buffer;
};
static std::atomic<bool> message_logger_use_buffer;
using MessageLoggerBuffer = std::vector<std::pair<std::string, log_level>>;
static util::synchronized_value<MessageLoggerBuffer> message_logger_buffer;
MessageLogger::MessageLogger(log_level level)
: m_level(level)
@ -147,14 +135,13 @@ namespace mamba::logging
MessageLogger::~MessageLogger()
{
if (!MessageLoggerData::use_buffer && Console::is_available())
if (!message_logger_use_buffer && Console::is_available())
{
emit(m_stream.str(), m_level);
}
else
{
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
MessageLoggerData::m_buffer.push_back({ m_stream.str(), m_level });
message_logger_buffer->push_back({ m_stream.str(), m_level });
}
}
@ -178,22 +165,18 @@ namespace mamba::logging
void MessageLogger::activate_buffer()
{
MessageLoggerData::use_buffer = true;
message_logger_use_buffer = true;
}
void MessageLogger::deactivate_buffer()
{
MessageLoggerData::use_buffer = false;
message_logger_use_buffer = false;
}
void MessageLogger::print_buffer(std::ostream& /*ostream*/)
{
decltype(MessageLoggerData::m_buffer) tmp;
{
const std::lock_guard<std::mutex> lock(MessageLoggerData::m_mutex);
MessageLoggerData::m_buffer.swap(tmp);
}
MessageLoggerBuffer tmp;
message_logger_buffer->swap(tmp);
for (const auto& [msg, level] : tmp)
{