#pragma once #include #include #include namespace orbis { inline namespace logs { enum class LogLevel : unsigned char { Always, Fatal, Error, Todo, Success, Warning, Notice, Trace }; // Currently enabled log level inline std::atomic logs_level = LogLevel::Notice; template struct log_class_string { static const T &get_object(const void *arg) { return *static_cast(arg); } static void format(std::string &out, const void *arg); }; template <> struct log_class_string { static void format(std::string &out, const void *arg); }; template struct log_class_string : log_class_string {}; template <> struct log_class_string { static void format_n(std::string &out, const void *str, std::size_t n); static void format(std::string &out, const void *arg); }; template <> struct log_class_string : log_class_string {}; template struct log_class_string { static void format(std::string &out, const void *arg) { log_class_string::format_n(out, arg, N); } }; template struct log_class_string { static void format(std::string &out, const void *arg) { log_class_string::format_n(out, arg, N); } }; template <> struct log_class_string : log_class_string {}; template <> struct log_class_string : log_class_string {}; template using log_args_t = const void *(&&)[sizeof...(Args) + 1]; struct log_type_info { decltype(&log_class_string::format) log_string; template static constexpr log_type_info make() { return log_type_info{ &log_class_string::format, }; } }; template constexpr const log_type_info type_info_v[sizeof...(Args) + 1]{ log_type_info::make>()...}; void _orbis_log_print(LogLevel lvl, const char *msg, std::string_view names, const log_type_info *sup, ...); template void _orbis_log_impl(LogLevel lvl, const char *msg, const char *names, const Args &...args) { // Fast filtering if (logs_level.load(std::memory_order::relaxed) < lvl) return; _orbis_log_print(lvl, msg, names, type_info_v, static_cast(&args)...); } } // namespace logs } // namespace orbis #define ORBIS_LOG_FATAL(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Fatal, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_ERROR(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Error, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_TODO(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Todo, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_SUCCESS(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Success, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_WARNING(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Warning, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_NOTICE(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Notice, (msg), #__VA_ARGS__, \ ##__VA_ARGS__) #define ORBIS_LOG_TRACE(msg, ...) \ ::orbis::_orbis_log_impl(::orbis::LogLevel::Trace, (msg), #__VA_ARGS__, \ ##__VA_ARGS__)