254 lines
7.9 KiB
C++
254 lines
7.9 KiB
C++
#pragma once
|
||
#include <ctime>
|
||
#include <string>
|
||
#include <vector>
|
||
#include <chrono>
|
||
#include <variant>
|
||
#include "Export.h"
|
||
#include <functional>
|
||
#include <string_view>
|
||
#include <type_traits>
|
||
|
||
namespace uns
|
||
{
|
||
// 前置声明捕获器
|
||
struct RangeCapturer;
|
||
struct PairCapturer;
|
||
struct FuncCapturer;
|
||
struct TimeCapturer;
|
||
|
||
// 终极 Variant 池:容纳所有可能解包出的原子形态
|
||
using LogVariant = std::variant<
|
||
bool, char, int, unsigned int, long long, unsigned long long, double, std::string_view, const void*,
|
||
std::string, // 专门用于承载宽字符转换后的 UTF-8 临时字符串
|
||
RangeCapturer, // 专门用于承载 std::vector / std::list 等容器
|
||
PairCapturer, // 专门用于承载 std::pair (支持 std::map)
|
||
FuncCapturer, //承载 std::function
|
||
TimeCapturer //承载时间
|
||
>;
|
||
|
||
// --- 编译期类型推导工具链 ---
|
||
template <typename T, typename = void>
|
||
struct is_container : std::false_type
|
||
{
|
||
};
|
||
|
||
// 识别标准容器(排除字符串本身)
|
||
template <typename T>
|
||
struct is_container<T, std::void_t<typename T::value_type, decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>> : std::integral_constant<bool, !std::is_same_v<T, std::string> && !std::is_same_v<T, std::string_view>>
|
||
{
|
||
};
|
||
|
||
template <typename T> struct is_pair : std::false_type
|
||
{
|
||
};
|
||
|
||
template <typename F, typename S> struct is_pair<std::pair<F, S>> : std::true_type
|
||
{
|
||
};
|
||
|
||
// --- 延迟桥接结构体 ---
|
||
struct LogArg;
|
||
|
||
struct RangeCapturer
|
||
{
|
||
const void* ptr;
|
||
void (*to_log_args)(const void*, std::vector<LogArg>&);
|
||
};
|
||
|
||
struct PairCapturer
|
||
{
|
||
const void* ptr;
|
||
void (*to_log_args)(const void*, std::vector<LogArg>&);
|
||
};
|
||
|
||
struct FuncCapturer
|
||
{
|
||
const void* code_ptr; // 真正改变:这里存真正的函数代码地址
|
||
bool is_closure; // 标记:这究竟是个纯函数,还是个 Lambda 闭包
|
||
};
|
||
|
||
// 升级版 Trait:不仅识别,还提取原生函数指针类型(R(*)(Args...))
|
||
template <typename T> struct function_traits
|
||
{
|
||
static constexpr bool is_func = false;
|
||
using pointer_type = void*;
|
||
};
|
||
|
||
template <typename R, typename... Args>
|
||
struct function_traits<std::function<R(Args...)>>
|
||
{
|
||
static constexpr bool is_func = true;
|
||
using pointer_type = R(*)(Args...); // 提取出原生函数指针类型
|
||
};
|
||
|
||
enum class TimeMode
|
||
{
|
||
Point,
|
||
TMPoint,
|
||
Duration
|
||
};
|
||
|
||
struct TimeCapturer
|
||
{
|
||
TimeMode mode{ TimeMode::Point };
|
||
|
||
std::tm _tm{};
|
||
std::chrono::system_clock::time_point tp{};
|
||
std::chrono::nanoseconds duration{ 0 };
|
||
|
||
std::string format_spec; // "%Y-%m-%d %H:%M:%S" or empty
|
||
|
||
// 可选:单位策略控制
|
||
bool smart_unit = true;
|
||
};
|
||
|
||
template<typename T>
|
||
struct is_time_point : std::false_type
|
||
{
|
||
};
|
||
|
||
template<typename Clock, typename Dur>
|
||
struct is_time_point<std::chrono::time_point<Clock, Dur>> : std::true_type
|
||
{
|
||
};
|
||
|
||
template<>
|
||
struct is_time_point<std::tm> : std::true_type
|
||
{
|
||
};
|
||
|
||
template<typename T>
|
||
inline constexpr bool is_time_point_v = is_time_point<T>::value;
|
||
|
||
template<typename T>
|
||
struct is_duration : std::false_type
|
||
{
|
||
};
|
||
|
||
template<typename Rep, typename Period>
|
||
struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type
|
||
{
|
||
};
|
||
|
||
template<typename T>
|
||
inline constexpr bool is_duration_v = is_duration<T>::value;
|
||
|
||
inline TimeCapturer MakeTimeCapturer(std::chrono::system_clock::time_point tp)
|
||
{
|
||
TimeCapturer c;
|
||
c.mode = TimeMode::Point;
|
||
c.tp = tp;
|
||
return c;
|
||
}
|
||
|
||
template<typename Rep, typename Period>
|
||
inline TimeCapturer MakeTimeCapturer(std::chrono::duration<Rep, Period> d)
|
||
{
|
||
TimeCapturer c;
|
||
c.mode = TimeMode::Duration;
|
||
c.duration = std::chrono::duration_cast<std::chrono::nanoseconds>(d);
|
||
c.smart_unit = true;
|
||
return c;
|
||
}
|
||
|
||
inline TimeCapturer MakeTimeCapturer(const std::tm& tm)
|
||
{
|
||
TimeCapturer c;
|
||
c.mode = TimeMode::TMPoint;
|
||
c._tm = tm;
|
||
return c;
|
||
}
|
||
|
||
// --- 宽字符转换声明(实现卸载到 .cpp) ---
|
||
std::string UNSWSC_DLL_EXPORT ConvertWStringToUtf8(std::wstring_view wstr);
|
||
|
||
// --- 核心包装类 ---
|
||
struct LogArg
|
||
{
|
||
LogVariant value;
|
||
|
||
template<typename T>
|
||
LogArg(T&& val)
|
||
{
|
||
using D = std::decay_t<T>;
|
||
|
||
// 1. 窄字符串系列(0拷贝)
|
||
if constexpr (std::is_same_v<D, std::string> || std::is_same_v<D, std::string_view>)
|
||
value = std::string_view(val);
|
||
else if constexpr (std::is_same_v<D, const char*> || std::is_same_v<D, char*>)
|
||
value = val ? std::string_view(val) : std::string_view("<null>");
|
||
// 2. 宽字符串系列(特殊处理:触发内部 UTF-8 转换)
|
||
else if constexpr (std::is_same_v<D, std::wstring> || std::is_same_v<D, std::wstring_view>)
|
||
value = ConvertWStringToUtf8(val);
|
||
else if constexpr (std::is_same_v<D, const wchar_t*> || std::is_same_v<D, wchar_t*>)
|
||
value = val ? ConvertWStringToUtf8(val) : std::string("<null>");
|
||
// 3. 基础原子类型(防范 wchar_t 被误判为整数)
|
||
else if constexpr (std::is_same_v<D, wchar_t> || std::is_same_v<D, char16_t> || std::is_same_v<D, char32_t>)
|
||
value = ConvertWStringToUtf8(std::wstring_view((const wchar_t*)&val, 1));
|
||
else if constexpr (std::is_same_v<D, bool>)
|
||
value = static_cast<bool>(val);
|
||
else if constexpr (std::is_same_v<D, char> || std::is_same_v<D, signed char>)
|
||
value = static_cast<char>(val);
|
||
// 3.5 时间点类型系列(防止时间对象退化为未知类型)
|
||
else if constexpr (is_time_point_v<D>)
|
||
value = MakeTimeCapturer(val);
|
||
else if constexpr (is_duration_v<D>)
|
||
value = MakeTimeCapturer(val);
|
||
// 4. 全整型变种矩阵 (short, int, long, long long, unsigned...)
|
||
else if constexpr (std::is_integral_v<D> && std::is_signed_v<D>)
|
||
{
|
||
if constexpr (sizeof(D) <= sizeof(int))
|
||
value = static_cast<int>(val);
|
||
else
|
||
value = static_cast<long long>(val);
|
||
}
|
||
else if constexpr (std::is_integral_v<D> && std::is_unsigned_v<D>)
|
||
{
|
||
if constexpr (sizeof(D) <= sizeof(unsigned int))
|
||
value = static_cast<unsigned int>(val);
|
||
else
|
||
value = static_cast<unsigned long long>(val);
|
||
}
|
||
// 5. 浮点矩阵
|
||
else if constexpr (std::is_floating_point_v<D>)
|
||
value = static_cast<double>(val);
|
||
// 6. 指针
|
||
else if constexpr (std::is_pointer_v<D>)
|
||
value = static_cast<const void*>(val);
|
||
// 7. 标准库容器(关键点:利用 Lambda 闭包在不引入 fmt 的情况下擦除容器类型!)
|
||
else if constexpr (is_container<D>::value)
|
||
{
|
||
value = RangeCapturer{ &val, [] (const void* p, std::vector<LogArg>& out)
|
||
{
|
||
for (const auto& item : *static_cast<const D*>(p))
|
||
out.emplace_back(item); // 递归包装子元素
|
||
}
|
||
};
|
||
}
|
||
// 8. 键值对(支持 Map 展开)
|
||
else if constexpr (is_pair<D>::value)
|
||
{
|
||
value = PairCapturer{ &val, [] (const void* p, std::vector<LogArg>& out)
|
||
{
|
||
const auto& pair = *static_cast<const D*>(p);
|
||
out.emplace_back(pair.first);
|
||
out.emplace_back(pair.second);
|
||
}
|
||
};
|
||
}
|
||
else if constexpr (function_traits<D>::is_func)
|
||
{
|
||
using TargetPtr = typename function_traits<D>::pointer_type;
|
||
// 关键点:尝试用 target() 拿底层指针
|
||
// std::function::target<T>() 返回的是 T*,所以如果 T 是函数指针,返回的就是“函数指针的指针”
|
||
if (auto* const* func_ptr = val.template target<TargetPtr>()) // 情况 A:内部装的是普通纯函数或静态成员函数
|
||
value = FuncCapturer{ reinterpret_cast<const void*>(*func_ptr), false };
|
||
else // 情况 B:内部装的是 Lambda 表达式或带状态的仿函数, 此时它在堆/栈上有一个闭包实体,我们退而求其次,打印这个闭包对象的地址
|
||
value = FuncCapturer{ static_cast<const void*>(&val), true };
|
||
}
|
||
else
|
||
value = std::string_view("<unsupported type>");
|
||
}
|
||
};
|
||
} |