Compare commits

...

4 Commits

7 changed files with 657 additions and 3 deletions

View File

@@ -2,7 +2,7 @@
#include <type_traits>
#include "types.h"
#include "types/types.h"
template <typename E>
struct is_flag_enum : std::false_type {

104
src/core/logger.cpp Normal file
View File

@@ -0,0 +1,104 @@
#include "logger.h"
#include <spdlog/async.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
mirai::logger::logger(logger_config config) : config_(config){
sinks_.clear();
if (config_.console_enabled) {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(to_spdlog_level(config_.level));
sinks_.push_back(console_sink);
}
if (config_.file_enabled) {
auto log_dir = config_.file_path.parent_path();
if (!log_dir.empty() && !std::filesystem::exists(log_dir)) {
std::filesystem::create_directory(log_dir);
}
if (config_.file_rotation_enabled) {
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
config_.file_path.string(),
config_.max_file_size,
config_.max_files
);
file_sink->set_level(to_spdlog_level(config_.level));
sinks_.push_back(file_sink);
} else {
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
config_.file_path.string(),
true
);
file_sink->set_level(to_spdlog_level(config_.level));
sinks_.push_back(file_sink);
}
}
if (config_.async_enabled) {
// 初始化异步日志线程池
spdlog::init_thread_pool(config_.async_queue_size, 1);
spdlog_logger_ = std::make_shared<spdlog::async_logger>(
config_.name,
sinks_.begin(),
sinks_.end(),
spdlog::thread_pool(),
spdlog::async_overflow_policy::block
);
} else {
spdlog_logger_ = std::make_shared<spdlog::logger>(
config_.name,
sinks_.begin(),
sinks_.end()
);
}
// 设置日志级别
spdlog_logger_->set_level(to_spdlog_level(config_.level));
// 设置日志格式
spdlog_logger_->set_pattern(config_.pattern);
// 设置刷新策略
spdlog_logger_->flush_on(spdlog::level::warn);
// 注册到 spdlog
spdlog::register_logger(spdlog_logger_);
}
mirai::logger::~logger() {
if (spdlog_logger_) {
spdlog_logger_->flush();
spdlog::drop(spdlog_logger_->name());
}
}
void mirai::logger::set_level(log_level level) {
config_.level = level;
if (spdlog_logger_) {
spdlog_logger_->set_level(to_spdlog_level(level));
}
for (auto& sink : sinks_) {
sink->set_level(to_spdlog_level(level));
}
}
void mirai::logger::set_pattern(const std::string& pattern) {
config_.pattern = pattern;
if (spdlog_logger_) {
spdlog_logger_->set_pattern(pattern);
}
}
bool mirai::logger::should_log(log_level level) const noexcept {
return spdlog_logger_ && spdlog_logger_->should_log(to_spdlog_level(level));
}
void mirai::logger::flush() {
if (spdlog_logger_) {
spdlog_logger_->flush();
}
}

347
src/core/logger.h Normal file
View File

@@ -0,0 +1,347 @@
#pragma once
#include <filesystem>
#include <source_location>
#include <string_view>
#include <spdlog/spdlog.h>
#include "types/types.h"
namespace mirai {
enum class log_level : u8 {
trace = 0,
debug = 1,
info = 2,
warn = 3,
error = 4,
critical = 5,
off = 6
};
[[nodiscard]] constexpr std::string_view log_level_to_string(log_level level) noexcept {
switch (level) {
case log_level::trace: return "trace";
case log_level::debug: return "debug";
case log_level::info: return "info";
case log_level::warn: return "warn";
case log_level::error: return "error";
case log_level::critical: return "critical";
case log_level::off: return "off";
default: return "unknown";
}
}
[[nodiscard]] constexpr spdlog::level::level_enum to_spdlog_level(log_level level) noexcept {
switch (level) {
case log_level::trace: return spdlog::level::trace;
case log_level::debug: return spdlog::level::debug;
case log_level::info: return spdlog::level::info;
case log_level::warn: return spdlog::level::warn;
case log_level::error: return spdlog::level::err;
case log_level::critical: return spdlog::level::critical;
case log_level::off: return spdlog::level::off;
default: return spdlog::level::info;
}
}
struct logger_config {
std::string name{"mirai"};
log_level level{log_level::info};
bool console_enabled{true};
bool file_enabled{true};
std::filesystem::path file_path{"logs/mirai.log"};
bool file_rotation_enabled{true};
size_type max_file_size{10 * 1024 * 1024}; // 10 MB
size_type max_files{5};
std::string pattern{"[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%t] %v"};
bool include_source_location{true};
bool async_enabled{false};
size_type async_queue_size{8192};
};
class logger {
public:
explicit logger(logger_config config = {});
~logger();
logger(const logger&) = delete;
logger& operator=(const logger&) = delete;
[[nodiscard]] const auto& name() const noexcept { return config_.name; }
[[nodiscard]] auto level() const noexcept { return config_.level; }
void set_level(log_level level);
void set_pattern(const std::string& pattern);
[[nodiscard]] bool should_log(log_level level) const noexcept;
void flush();
template <typename... Args>
void trace(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::trace, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void debug(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::debug, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void info(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::info, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void warn(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::warn, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void error(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::error, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void critical(fmt::format_string<Args...> fmt, Args&&... args) {
log(log_level::critical, fmt, std::forward<Args>(args)...);
}
template <typename... Args>
void log(log_level level, fmt::format_string<Args...> fmt, Args&&... args) {
if (should_log(level)) {
spdlog_logger_->log(to_spdlog_level(level), fmt, std::forward<Args>(args)...);
}
}
template <typename... Args>
void log_with_location(
log_level level,
const std::source_location& location,
fmt::format_string<Args...> fmt,
Args&&... args
) {
if (should_log(level)) {
std::string message = fmt::format(fmt, std::forward<Args>(args)...);
std::string full_message = fmt::format(
"{} [{}:{}:{}]",
message,
location.file_name(),
location.line(),
location.function_name()
);
spdlog_logger_->log(to_spdlog_level(level), "{}", full_message);
}
}
private:
logger_config config_;
std::shared_ptr<spdlog::logger> spdlog_logger_;
std::vector<spdlog::sink_ptr> sinks_;
};
inline auto& get_global_logger_ref() {
static std::shared_ptr<logger> instance;
return instance;
}
inline auto& get_global_logger_mutex() {
static std::mutex mutex;
return mutex;
}
inline void init_logger(const logger_config& config = logger_config{}) {
std::lock_guard lock(get_global_logger_mutex());
get_global_logger_ref() = std::make_shared<logger>(config);
}
inline void shutdown_logger() {
std::lock_guard lock(get_global_logger_mutex());
if (auto& logger = get_global_logger_ref()) {
logger->flush();
logger.reset();
}
spdlog::shutdown();
}
inline auto get_logger() {
std::lock_guard lock(get_global_logger_mutex());
auto& logger = get_global_logger_ref();
if (!logger) {
// 自动初始化默认日志器
logger = std::make_shared<mirai::logger>();}
return logger;
}
inline void set_log_level(log_level level) {
if (auto logger = get_logger()) {
logger->set_level(level);
}
}
inline void flush_logger() {
if (auto logger = get_logger()) {
logger->flush();
}
}
/**
* @brief 记录 trace 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_trace(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->trace(fmt, std::forward<Args>(args)...);
}
}
/**
* @brief 记录 debug 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_debug(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->debug(fmt, std::forward<Args>(args)...);
}
}
/**
* @brief 记录 info 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_info(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->info(fmt, std::forward<Args>(args)...);
}
}
/**
* @brief 记录 warn 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_warn(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->warn(fmt, std::forward<Args>(args)...);
}
}
/**
* @brief 记录 error 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_error(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->error(fmt, std::forward<Args>(args)...);
}
}
/**
* @brief 记录 critical 级别日志
* @tparam Args 参数类型
* @param fmt 格式字符串
* @param args 格式参数
*/
template<typename... Args>
void log_critical(fmt::format_string<Args...> fmt, Args&&... args) {
if (auto logger = get_logger()) {
logger->critical(fmt, std::forward<Args>(args)...);
}
}
}
/**
* @def MIRAI_LOG_TRACE(...)
* @brief 记录 trace 级别日志
*/
#define MIRAI_LOG_TRACE(...) ::mirai::log_trace(__VA_ARGS__)
/**
* @def MIRAI_LOG_DEBUG(...)
* @brief 记录 debug 级别日志
*/
#define MIRAI_LOG_DEBUG(...) ::mirai::log_debug(__VA_ARGS__)
/**
* @def MIRAI_LOG_INFO(...)
* @brief 记录 info 级别日志
*/
#define MIRAI_LOG_INFO(...) ::mirai::log_info(__VA_ARGS__)
/**
* @def MIRAI_LOG_WARN(...)
* @brief 记录 warn 级别日志
*/
#define MIRAI_LOG_WARN(...) ::mirai::log_warn(__VA_ARGS__)
/**
* @def MIRAI_LOG_ERROR(...)
* @brief 记录 error 级别日志
*/
#define MIRAI_LOG_ERROR(...) ::mirai::log_error(__VA_ARGS__)
/**
* @def MIRAI_LOG_CRITICAL(...)
* @brief 记录 critical 级别日志
*/
#define MIRAI_LOG_CRITICAL(...) ::mirai::log_critical(__VA_ARGS__)
/**
* @def MIRAI_LOG(level, ...)
* @brief 记录指定级别的日志
*/
#define MIRAI_LOG(level, ...) \
do { \
if (auto _logger = ::mirai::get_logger()) { \
_logger->log(level, __VA_ARGS__); \
} \
} while (false)
/**
* @def MIRAI_LOG_IF(condition, level, ...)
* @brief 条件日志记录
*/
#define MIRAI_LOG_IF(condition, level, ...) \
do { \
if (condition) { \
MIRAI_LOG(level, __VA_ARGS__); \
} \
} while (false)
// Debug 模式专用日志宏
#if MIRAI_DEBUG
/**
* @def MIRAI_DLOG_TRACE(...)
* @brief Debug 模式 trace 日志
*/
#define MIRAI_DLOG_TRACE(...) MIRAI_LOG_TRACE(__VA_ARGS__)
/**
* @def MIRAI_DLOG_DEBUG(...)
* @brief Debug 模式 debug 日志
*/
#define MIRAI_DLOG_DEBUG(...) MIRAI_LOG_DEBUG(__VA_ARGS__)
/**
* @def MIRAI_DLOG_INFO(...)
* @brief Debug 模式 info 日志
*/
#define MIRAI_DLOG_INFO(...) MIRAI_LOG_INFO(__VA_ARGS__)
#else
#define MIRAI_DLOG_TRACE(...) ((void)0)
#define MIRAI_DLOG_DEBUG(...) ((void)0)
#define MIRAI_DLOG_INFO(...) ((void)0)
#endif

View File

@@ -3,7 +3,7 @@
#include <string>
#include <string_view>
#include "types.h"
#include "types/types.h"
#include "property.h"
namespace mirai {

View File

@@ -6,7 +6,7 @@
#include <string_view>
#include "flag_enum.h"
#include "types.h"
#include "types/types.h"
namespace mirai {
class object;

203
src/types/color.h Normal file
View File

@@ -0,0 +1,203 @@
#pragma once
#include "types.h"
#include <cmath>
namespace mirai {
/**
* @brief 颜色类型 (RGBA)
*/
template<typename T = f32>
struct color {
T r{0.0}; ///< 红色分量 (0-1)
T g{0.0}; ///< 绿色分量 (0-1)
T b{0.0}; ///< 蓝色分量 (0-1)
T a{1.0}; ///< 透明度 (0-1)
constexpr color() noexcept = default;
constexpr color(T r_, T g_, T b_, T a_ = 1.0) noexcept : r(r_), g(g_), b(b_), a(a_) {
}
[[nodiscard]] constexpr color operator+(const color& other) const noexcept {
return color{r + other.r, g + other.g, b + other.b, a + other.a};
}
[[nodiscard]] constexpr color operator-(const color& other) const noexcept {
return color{r - other.r, g - other.g, b - other.b, a - other.a};
}
[[nodiscard]] constexpr color operator*(f64 scalar) const noexcept {
return color{r * scalar, g * scalar, b * scalar, a * scalar};
}
[[nodiscard]] constexpr bool operator==(const color& other) const noexcept = default;
/**
* @brief 从 RGB 整数值创建颜色
* @param r_ 红色 (0-255)
* @param g_ 绿色 (0-255)
* @param b_ 蓝色 (0-255)
* @param a_ 透明度 (0-255)
* @return 颜色对象
*/
[[nodiscard]] static constexpr color from_rgb(u8 r_, u8 g_, u8 b_, u8 a_ = 255) noexcept {
return color{
static_cast<T>(r_) / 255.0,
static_cast<T>(g_) / 255.0,
static_cast<T>(b_) / 255.0,
static_cast<T>(a_) / 255.0
};
}
/**
* @brief 从十六进制值创建颜色
* @param hex 十六进制值 (0xRRGGBB 或 0xRRGGBBAA)
* @return 颜色对象
*/
[[nodiscard]] static constexpr color from_hex(u32 hex) noexcept {
if (hex <= 0xFFFFFF) {
// 0xRRGGBB 格式
return from_rgb(
static_cast<u8>((hex >> 16) & 0xFF),
static_cast<u8>((hex >> 8) & 0xFF),
static_cast<u8>(hex & 0xFF)
);
}
// 0xRRGGBBAA 格式
return from_rgb(
static_cast<u8>((hex >> 24) & 0xFF),
static_cast<u8>((hex >> 16) & 0xFF),
static_cast<u8>((hex >> 8) & 0xFF),
static_cast<u8>(hex & 0xFF)
);
}
/**
* @brief 从 32 位 RGBA 整数创建
* @param rgba 0xRRGGBBAA 格式的颜色值
* @return 颜色对象
*/
[[nodiscard]] static constexpr color from_rgba(u32 rgba) noexcept {
return color{
static_cast<f32>((rgba >> 24) & 0xFF) / 255.0f,
static_cast<f32>((rgba >> 16) & 0xFF) / 255.0f,
static_cast<f32>((rgba >> 8) & 0xFF) / 255.0f,
static_cast<f32>(rgba & 0xFF) / 255.0f
};
}
/**
* @brief 从 32 位 ARGB 整数创建
* @param argb 0xAARRGGBB 格式的颜色值
* @return 颜色对象
*/
[[nodiscard]] static constexpr color from_argb(u32 argb) noexcept {
return color{
static_cast<f32>((argb >> 16) & 0xFF) / 255.0f,
static_cast<f32>((argb >> 8) & 0xFF) / 255.0f,
static_cast<f32>(argb & 0xFF) / 255.0f,
static_cast<f32>((argb >> 24) & 0xFF) / 255.0f
};
}
/**
* @brief 从 HSL 创建颜色
* @param h 色相 [0.0, 360.0)
* @param s 饱和度 [0.0, 1.0]
* @param l 亮度 [0.0, 1.0]
* @param a 透明度 [0.0, 1.0]
* @return 颜色对象
*/
[[nodiscard]] static color from_hsl(f32 h, f32 s, f32 l, f32 a = 1.0f) noexcept {
f32 c = (1.0f - std::fabs(2.0f * l - 1.0f)) * s;
f32 x = c * (1.0f - std::fabs(std::fmod(h / 60.0f, 2.0f) - 1.0f));
f32 m = l - c / 2.0f;
f32 r1 = 0.0f, g1 = 0.0f, b1 = 0.0f;
if (h >= 0.0f && h < 60.0f) {
r1 = c; g1 = x; b1 = 0.0f;
}
else if (h >= 60.0f && h < 120.0f) {
r1 = x; g1 = c; b1 = 0.0f;
}
else if (h >= 120.0f && h < 180.0f) {
r1 = 0.0f; g1 = c; b1 = x;
}
else if (h >= 180.0f && h < 240.0f) {
r1 = 0.0f; g1 = x; b1 = c;
}
else if (h >= 240.0f && h < 300.0f) {
r1 = x; g1 = 0.0f; b1 = c;
}
else if (h >= 300.0f && h < 360.0f) {
r1 = c; g1 = 0.0f; b1 = x;
}
return color{
r1 + m,
g1 + m,
b1 + m,
a
};
}
/**
* @brief 转换为 32 位 RGBA 整数
* @return 0xRRGGBBAA 格式的颜色值
*/
[[nodiscard]] constexpr u32 to_rgba() const noexcept {
return (static_cast<u32>(r * 255.0f) << 24) |
(static_cast<u32>(g * 255.0f) << 16) |
(static_cast<u32>(b * 255.0f) << 8) |
static_cast<u32>(a * 255.0f);
}
/**
* @brief 转换为 32 位 ARGB 整数
* @return 0xAARRGGBB 格式的颜色值
*/
[[nodiscard]] constexpr u32 to_argb() const noexcept {
return (static_cast<u32>(a * 255.0f) << 24) |
(static_cast<u32>(r * 255.0f) << 16) |
(static_cast<u32>(g * 255.0f) << 8) |
static_cast<u32>(b * 255.0f);
}
/**
* @brief 颜色混合
* @param other 另一个颜色
* @param t 混合因子 [0.0, 1.0]
* @return 混合后的颜色
*/
[[nodiscard]] constexpr color lerp(const color& other, f32 t) const noexcept {
return color{
r + (other.r - r) * t,
g + (other.g - g) * t,
b + (other.b - b) * t,
a + (other.a - a) * t
};
}
/**
* @brief 使用指定透明度创建新颜色
* @param alpha 新的透明度值
* @return 新颜色
*/
[[nodiscard]] constexpr color with_alpha(f32 alpha) const noexcept {
return color{r, g, b, alpha};
}
// 预定义颜色
[[nodiscard]] static constexpr color white() noexcept { return color{1.0, 1.0, 1.0, 1.0}; }
[[nodiscard]] static constexpr color black() noexcept { return color{0.0, 0.0, 0.0, 1.0}; }
[[nodiscard]] static constexpr color red() noexcept { return color{1.0, 0.0, 0.0, 1.0}; }
[[nodiscard]] static constexpr color green() noexcept { return color{0.0, 1.0, 0.0, 1.0}; }
[[nodiscard]] static constexpr color blue() noexcept { return color{0.0, 0.0, 1.0, 1.0}; }
[[nodiscard]] static constexpr color transparent() noexcept { return color{0.0, 0.0, 0.0, 0.0}; }
[[nodiscard]] static constexpr color yellow() noexcept { return color{1.0, 1.0, 0.0, 1.0}; }
[[nodiscard]] static constexpr color cyan() noexcept { return color{0.0, 1.0, 1.0, 1.0}; }
[[nodiscard]] static constexpr color magenta() noexcept { return color{1.0, 0.0, 1.0, 1.0}; }
[[nodiscard]] static constexpr color gray() noexcept { return color{0.5, 0.5, 0.5, 1.0}; }
};
}