diff --git a/source/mijin/debug/stacktrace.hpp b/source/mijin/debug/stacktrace.hpp index ac7e485..536ab72 100644 --- a/source/mijin/debug/stacktrace.hpp +++ b/source/mijin/debug/stacktrace.hpp @@ -5,6 +5,7 @@ #define MIJIN_DEBUG_STACKTRACE_HPP_INCLUDED 1 #include +#include #include #include #if __has_include() @@ -87,6 +88,68 @@ TStream& operator<<(TStream& stream, const Stacktrace& stacktrace) } // namespace mijin +template +struct std::formatter +{ + using char_t = TChar; + + template + constexpr TContext::iterator parse(TContext& ctx) + { + auto it = ctx.begin(); + auto end = ctx.end(); + + if (it != end && *it != MIJIN_SMART_QUOTE(char_t, '}')) + { + throw std::format_error("invalid format"); + } + + return it; + } + + template + TContext::iterator format(const mijin::Stackframe& stackframe, TContext& ctx) const + { + auto it = ctx.out(); + it = std::format_to(it, MIJIN_SMART_QUOTE(char_t, "[{}] {}:{} in {}"), stackframe.address, stackframe.filename, + stackframe.lineNumber, mijin::demangleCPPIdentifier(stackframe.function.c_str())); + return it; + } +}; + +template +struct std::formatter +{ + using char_t = TChar; + + template + constexpr TContext::iterator parse(TContext& ctx) + { + auto it = ctx.begin(); + auto end = ctx.end(); + + if (it != end && *it != MIJIN_SMART_QUOTE(char_t, '}')) + { + throw std::format_error("invalid format"); + } + + return it; + } + + template + TContext::iterator format(const mijin::Stacktrace& stacktrace, TContext& ctx) const + { + const int numDigits = static_cast(std::ceil(std::log10(stacktrace.getFrames().size()))); + auto it = ctx.out(); + it = std::format_to(it, MIJIN_SMART_QUOTE(char_t, "[{} frames]"), stacktrace.getFrames().size()); + for (const auto& [idx, frame] : mijin::enumerate(stacktrace.getFrames())) + { + it = std::format_to(it, MIJIN_SMART_QUOTE(char_t, "\n #{:<{}} at {}"), idx, numDigits, frame); + } + return it; + } +}; + #if __has_include() template<> struct fmt::formatter