diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index f38087a..bc1390b 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -105,39 +104,29 @@ namespace cpptrace { } std::string stacktrace_frame::to_string() const { - std::ostringstream oss; - oss << *this; - return std::move(oss).str(); - } - - std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) { - stream - << std::hex - << "0x" - << std::setw(2 * sizeof(frame_ptr)) - << std::setfill('0') - << frame.raw_address - << std::dec - << std::setfill(' '); - if(!frame.symbol.empty()) { - stream - << " in " - << frame.symbol; + std::string str; + if(is_inline) { + str += microfmt::format("{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)"); + } else { + str += microfmt::format("0x{<{}:0h}", 2 * sizeof(frame_ptr), raw_address); } - if(!frame.filename.empty()) { - stream - << " at " - << frame.filename; - if(frame.line.has_value()) { - stream - << ":" - << frame.line.value(); - if(frame.column.has_value()) { - stream << frame.column.value(); + if(!symbol.empty()) { + str += microfmt::format(" in {}", symbol); + } + if(!filename.empty()) { + str += microfmt::format(" at {}", filename); + if(line.has_value()) { + str += microfmt::format(":{}", line.value()); + if(column.has_value()) { + str += microfmt::format(":{}", column.value()); } } } - return stream; + return str; + } + + std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) { + return stream << frame.to_string(); } CPPTRACE_FORCE_NO_INLINE @@ -173,56 +162,25 @@ namespace cpptrace { const auto green = color ? GREEN : ""; const auto yellow = color ? YELLOW : ""; const auto blue = color ? BLUE : ""; - stream - << '#' - << std::setw(static_cast(frame_number_width)) - << std::left - << counter - << std::right - << " "; + std::string line = microfmt::format("#{<{}} ", frame_number_width, counter); if(frame.is_inline) { - stream - << std::setw(2 * sizeof(frame_ptr) + 2) - << "(inlined)"; + line += microfmt::format("{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)"); } else { - stream - << std::hex - << blue - << "0x" - << std::setw(2 * sizeof(frame_ptr)) - << std::setfill('0') - << frame.raw_address - << std::dec - << std::setfill(' ') - << reset; + line += microfmt::format("{}0x{<{}:0h}{}", blue, 2 * sizeof(frame_ptr), frame.raw_address, reset); } if(!frame.symbol.empty()) { - stream - << " in " - << yellow - << frame.symbol - << reset; + line += microfmt::format(" in {}{}{}", yellow, frame.symbol, reset); } if(!frame.filename.empty()) { - stream - << " at " - << green - << frame.filename - << reset; + line += microfmt::format(" at {}{}{}", green, frame.filename, reset); if(frame.line.has_value()) { - stream - << ":" - << blue - << frame.line.value() - << reset; + line += microfmt::format(":{}{}{}", blue, frame.line.value(), reset); if(frame.column.has_value()) { - stream << ':' - << blue - << std::to_string(frame.column.value()) - << reset; + line += microfmt::format(":{}{}{}", blue, frame.column.value(), reset); } } } + stream << line; } void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const { @@ -233,10 +191,10 @@ namespace cpptrace { ) { detail::enable_virtual_terminal_processing_if_needed(); } - stream<<(header ? header : "Stack trace (most recent call first):") << '\n'; + stream << (header ? header : "Stack trace (most recent call first):") << '\n'; std::size_t counter = 0; if(frames.empty()) { - stream<<"" << '\n'; + stream << "\n"; return; } const auto frame_number_width = detail::n_digits(static_cast(frames.size()) - 1); @@ -269,10 +227,10 @@ namespace cpptrace { ) { detail::enable_virtual_terminal_processing_if_needed(); } - stream<<(header ? header : "Stack trace (most recent call first):") << '\n'; + stream << (header ? header : "Stack trace (most recent call first):") << '\n'; std::size_t counter = 0; if(frames.empty()) { - stream<<"" << '\n'; + stream << "" << '\n'; return; } const auto frame_number_width = detail::n_digits(static_cast(frames.size()) - 1); @@ -433,29 +391,28 @@ namespace cpptrace { try { auto ptr = std::current_exception(); if(ptr == nullptr) { - std::cerr << "terminate called without an active exception\n"; + fputs("terminate called without an active exception", stderr); print_terminate_trace(); } else { std::rethrow_exception(ptr); } } catch(cpptrace::exception& e) { - std::cerr << "Terminate called after throwing an instance of " - << demangle(typeid(e).name()) - << ": " - << e.message() - << '\n'; + microfmt::print( + stderr, + "Terminate called after throwing an instance of {}: {}\n", + demangle(typeid(e).name()), + e.message() + ); e.trace().print(std::cerr, isatty(stderr_fileno)); } catch(std::exception& e) { - std::cerr << "Terminate called after throwing an instance of " - << demangle(typeid(e).name()) - << ": " - << e.what() - << '\n'; + microfmt::print( + stderr, "Terminate called after throwing an instance of {}: {}\n", demangle(typeid(e).name()), e.what() + ); print_terminate_trace(); } catch(...) { - std::cerr << "Terminate called after throwing an instance of " - << detail::exception_type_name() - << "\n"; + microfmt::print( + stderr, "Terminate called after throwing an instance of {}\n", detail::exception_type_name() + ); print_terminate_trace(); } std::flush(std::cerr); diff --git a/src/snippets/snippet.cpp b/src/snippets/snippet.cpp index 660d375..83b61d7 100644 --- a/src/snippets/snippet.cpp +++ b/src/snippets/snippet.cpp @@ -130,7 +130,7 @@ namespace detail { snippet += YELLOW; } auto line_str = std::to_string(line); - snippet += std::string(margin_width - std::min(line_str.size(), margin_width), ' ') + line_str + ": "; + snippet += microfmt::format("{>{}}: ", margin_width, line_str); if(color && line == target_line) { snippet += RESET; } diff --git a/src/symbols/symbols_with_addr2line.cpp b/src/symbols/symbols_with_addr2line.cpp index 842ddd6..5bcbb7a 100644 --- a/src/symbols/symbols_with_addr2line.cpp +++ b/src/symbols/symbols_with_addr2line.cpp @@ -289,12 +289,15 @@ namespace addr2line { } std::string address_input; for(const auto& pair : entries_vec) { - address_input += to_hex(pair.first.get().object_address); + address_input += microfmt::format( + "{:h}{}", + pair.first.get().object_address, #if !IS_WINDOWS - address_input += '\n'; + '\n' #else - address_input += ' '; + ' ' #endif + ); } auto output = split(trim(resolve_addresses(address_input, object_name)), "\n"); VERIFY(output.size() == entries_vec.size()); diff --git a/src/utils/microfmt.hpp b/src/utils/microfmt.hpp index 3642071..30c939c 100644 --- a/src/utils/microfmt.hpp +++ b/src/utils/microfmt.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -320,6 +321,12 @@ namespace microfmt { void print(std::ostream& ostream, const S& fmt, Args&&... args) { ostream< + void print(std::FILE* stream, const S& fmt, Args&&... args) { + auto str = format(fmt, args...); + fwrite(str.data(), 1, str.size(), stream); + } } #endif diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 226d0df..3ab3903 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -107,12 +107,6 @@ namespace detail { return str.substr(left, right - left); } - inline std::string to_hex(std::uintptr_t addr) { - std::stringstream sstream; - sstream<