diff --git a/include/boost/stacktrace.hpp b/include/boost/stacktrace.hpp index 78e527b..85b9ec0 100644 --- a/include/boost/stacktrace.hpp +++ b/include/boost/stacktrace.hpp @@ -12,8 +12,6 @@ # pragma once #endif -#include - #include #include @@ -101,8 +99,12 @@ class stacktrace { /// @endcond public: +#ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED /// @brief Random access iterator that returns frame_view. - class iterator; + typedef implementation_specific iterator; +#else + class iterator; // forward declaration +#endif class frame_view { /// @cond @@ -222,10 +224,9 @@ public: /// is the function index where stacktrace was constructed and /// index close to this->size() contains function `main()`. /// @returns frame_view that references the actual frame info, stored inside *this. - /// @throws std::bad_alloc if not enough memory to construct resulting string. /// /// @b Complexity: Amortized O(1), O(1) for noop backend. - frame_view operator[](std::size_t frame_no) const { + frame_view operator[](std::size_t frame_no) const BOOST_NOEXCEPT { return *(cbegin() + frame_no); } @@ -277,27 +278,29 @@ public: const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator( const_iterator(this, size()) ); } }; -/// Comparison operators that order in a platform dependant order and have amortized O(1) complexity; O(size()) worst case conmlexity. +/// Comparison operators that order in a platform dependant order and have amortized O(1) complexity; O(size()) worst case complexity. inline bool operator> (const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return rhs < lhs; } inline bool operator<=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); } inline bool operator>=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); } inline bool operator!=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); } +/// Comparison operators that order in a platform dependant order and have O(1) complexity. +inline bool operator< (const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return lhs.address() < rhs.address(); } +inline bool operator> (const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return rhs < lhs; } +inline bool operator<=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs > rhs); } +inline bool operator>=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs < rhs); } +inline bool operator==(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return lhs.address() == rhs.address(); } +inline bool operator!=(const stacktrace::frame_view& lhs, const stacktrace::frame_view& rhs) BOOST_NOEXCEPT { return !(lhs == rhs); } + + /// Hashing support, O(1) complexity. inline std::size_t hash_value(const stacktrace& st) BOOST_NOEXCEPT { return st.hash_code(); } -/// Outputs stacktrace::frame in a human readable format to output stream. -template -std::basic_ostream& operator<<(std::basic_ostream& os, const stacktrace::frame_view& f) { - os << f.name(); - - if (f.source_line()) { - return os << '\t' << f.source_file() << ':' << f.source_line(); - } - - return os; +/// Hashing support, O(1) complexity. +inline std::size_t hash_value(const stacktrace::frame_view& f) BOOST_NOEXCEPT { + return reinterpret_cast(f.address()); } /// Outputs stacktrace in a human readable format to output stream. @@ -317,6 +320,18 @@ std::basic_ostream& operator<<(std::basic_ostream +std::basic_ostream& operator<<(std::basic_ostream& os, const stacktrace::frame_view& f) { + os << f.name(); + + if (f.source_line()) { + return os << '\t' << f.source_file() << ':' << f.source_line(); + } + + return os; +} + }} // namespace boost::stacktrace /// @cond diff --git a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp b/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp index 3986635..96a6a10 100644 --- a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp +++ b/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp @@ -24,21 +24,34 @@ namespace boost { namespace stacktrace { namespace detail { +struct bt_pair { + std::string name; + const void* addr; +}; + +inline bool operator< (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT { + return lhs.addr < rhs.addr; +} + +inline bool operator== (const bt_pair& lhs, const bt_pair& rhs) BOOST_NOEXCEPT { + return lhs.addr == rhs.addr; +} + struct backtrace_holder { std::size_t frames_count; - boost::shared_ptr frames; + boost::shared_ptr frames; inline std::size_t size() const BOOST_NOEXCEPT { return frames_count; } inline const void* get_address(std::size_t frame) const BOOST_NOEXCEPT { - return &frames[frame]; + return frames[frame].addr; } inline std::string get_frame(std::size_t frame) const { if (frame < frames_count) { - return frames[frame]; + return frames[frame].name; } else { return std::string(); } @@ -48,7 +61,7 @@ struct backtrace_holder { std::string res; unw_word_t offp; char data[256]; - const int ret = unw_get_proc_name (&cursor, data, sizeof(data) / sizeof(char), &offp); + const int ret = unw_get_proc_name(&cursor, data, sizeof(data) / sizeof(char), &offp); if (ret == -UNW_ENOMEM) { res.resize(sizeof(data) * 2); diff --git a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp index e5687e6..af53a7f 100644 --- a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp +++ b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp @@ -48,11 +48,15 @@ stacktrace::stacktrace() BOOST_NOEXCEPT } BOOST_TRY { - bt.frames = boost::make_shared(bt.frames_count); + bt.frames = boost::make_shared(bt.frames_count); std::size_t i = 0; while (unw_step(&cursor) > 0){ - bt.frames[i] = boost::stacktrace::detail::backtrace_holder::get_frame_impl(cursor); - boost::hash_combine(hash_code_, bt.frames[i]); + bt.frames[i].name = boost::stacktrace::detail::backtrace_holder::get_frame_impl(cursor); + unw_proc_info_t inf; + const int res = unw_get_proc_info(&cursor, &inf); + (void)res; + bt.frames[i].addr = reinterpret_cast(inf.start_ip ? inf.start_ip : inf.gp); + boost::hash_combine(hash_code_, bt.frames[i].name); ++ i; } } BOOST_CATCH(...) {} diff --git a/test/test.cpp b/test/test.cpp index 5dbd997..b4d324e 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -168,6 +168,15 @@ void test_frame_view() { stacktrace::frame_view fv = nst[1]; BOOST_TEST(st[1].name() != fv.name()); + BOOST_TEST(st[1] != fv); + BOOST_TEST(st[1] == st[1]); + BOOST_TEST(st[1] <= st[1]); + BOOST_TEST(st[1] >= st[1]); + BOOST_TEST(st[1] < fv || st[1] > fv); + + BOOST_TEST(hash_value(st[1]) != hash_value(fv)); + fv = st[1]; + BOOST_TEST(hash_value(st[1]) == hash_value(fv)); } int main() {