From ab6cb7483e917380fe710468d72c2604373ecb2f Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 12 Oct 2016 20:26:09 +0300 Subject: [PATCH] Added support for hashing --- include/boost/stacktrace.hpp | 14 ++++++++++++++ .../detail/backtrace_holder_libunwind.hpp | 4 ---- .../stacktrace/detail/backtrace_holder_linux.hpp | 1 - .../stacktrace/detail/backtrace_holder_noop.hpp | 2 +- include/boost/stacktrace/detail/stacktrace.ipp | 6 ++++-- .../stacktrace/detail/stacktrace_libunwind.hpp | 8 +++++++- .../boost/stacktrace/detail/stacktrace_linux.hpp | 10 ++++++++-- .../boost/stacktrace/detail/stacktrace_noop.hpp | 4 +++- .../boost/stacktrace/detail/stacktrace_windows.hpp | 8 ++++++-- src/stacktrace_src.ipp | 13 ++++++++++--- test/test.cpp | 7 +++++++ 11 files changed, 60 insertions(+), 17 deletions(-) diff --git a/include/boost/stacktrace.hpp b/include/boost/stacktrace.hpp index f82235b..93d0ecf 100644 --- a/include/boost/stacktrace.hpp +++ b/include/boost/stacktrace.hpp @@ -86,6 +86,8 @@ class stacktrace { boost::stacktrace::detail::backtrace_holder impl_; #endif + std::size_t hash_code_; + public: /// @brief Stores the current function call sequence inside the class. /// @@ -136,6 +138,13 @@ public: /// /// @b Complexity: Amortized O(1); worst case O(size()) BOOST_STACKTRACE_FUNCTION bool operator==(const stacktrace& rhs) const BOOST_NOEXCEPT; + + /// @brief Returns hashed code of the stacktrace. + /// + /// @b Complexity: O(1) + std::size_t hash_code() const BOOST_NOEXCEPT { + return hash_code_; + } }; /// Additional comparison operators for stacktraces that have amortized O(1) complexity. @@ -144,6 +153,11 @@ inline bool operator<=(const stacktrace& lhs, const stacktrace& rhs) BOOST_NOEXC 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); } +/// Hashing support +inline std::size_t hash_value(const stacktrace& st) BOOST_NOEXCEPT { + return st.hash_code(); +} + /// Outputs stacktrace in a human readable format to output stream. template std::basic_ostream& operator<<(std::basic_ostream& os, const stacktrace& bt) { diff --git a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp b/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp index dadc673..9c9e5bb 100644 --- a/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp +++ b/include/boost/stacktrace/detail/backtrace_holder_libunwind.hpp @@ -28,10 +28,6 @@ struct backtrace_holder { std::size_t frames_count; boost::shared_ptr frames; - BOOST_FORCEINLINE backtrace_holder() BOOST_NOEXCEPT - : frames_count(0) - {} - inline std::size_t size() const BOOST_NOEXCEPT { return frames_count; } diff --git a/include/boost/stacktrace/detail/backtrace_holder_linux.hpp b/include/boost/stacktrace/detail/backtrace_holder_linux.hpp index 1e80ed9..6a5fdbd 100644 --- a/include/boost/stacktrace/detail/backtrace_holder_linux.hpp +++ b/include/boost/stacktrace/detail/backtrace_holder_linux.hpp @@ -36,7 +36,6 @@ struct backtrace_holder { return res; } - Dl_info dli; if (!!dladdr(buffer[frame], &dli) && dli.dli_sname) { boost::core::scoped_demangled_name demangled(dli.dli_sname); diff --git a/include/boost/stacktrace/detail/backtrace_holder_noop.hpp b/include/boost/stacktrace/detail/backtrace_holder_noop.hpp index 9903a03..6577aab 100644 --- a/include/boost/stacktrace/detail/backtrace_holder_noop.hpp +++ b/include/boost/stacktrace/detail/backtrace_holder_noop.hpp @@ -23,7 +23,7 @@ struct backtrace_holder { inline std::string get_frame(std::size_t /*frame*/) const { return std::string(); } - + inline bool operator< (const backtrace_holder& rhs) const BOOST_NOEXCEPT { return false; } diff --git a/include/boost/stacktrace/detail/stacktrace.ipp b/include/boost/stacktrace/detail/stacktrace.ipp index e16f9e1..3435f0a 100644 --- a/include/boost/stacktrace/detail/stacktrace.ipp +++ b/include/boost/stacktrace/detail/stacktrace.ipp @@ -36,10 +36,12 @@ namespace boost { namespace stacktrace { stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT : impl_(bt.impl_) + , hash_code_(bt.hash_code_) {} stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT { impl_ = bt.impl_; + hash_code_ = bt.hash_code_; return *this; } @@ -54,11 +56,11 @@ std::string stacktrace::operator[](std::size_t frame) const { } bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT { - return impl_ < rhs.impl_; + return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && impl_ < rhs.impl_); } bool stacktrace::operator==(const stacktrace& rhs) const BOOST_NOEXCEPT { - return impl_ == rhs.impl_; + return hash_code_ == rhs.hash_code_ && impl_ == rhs.impl_; } }} diff --git a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp index 8ccbb71..e5687e6 100644 --- a/include/boost/stacktrace/detail/stacktrace_libunwind.hpp +++ b/include/boost/stacktrace/detail/stacktrace_libunwind.hpp @@ -16,10 +16,15 @@ #include #include +#include + namespace boost { namespace stacktrace { -stacktrace::stacktrace() BOOST_NOEXCEPT { +stacktrace::stacktrace() BOOST_NOEXCEPT + : hash_code_(0) +{ boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_); + bt.frames_count = 0; unw_context_t uc; if (unw_getcontext(&uc) != 0) { @@ -47,6 +52,7 @@ stacktrace::stacktrace() BOOST_NOEXCEPT { 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]); ++ i; } } BOOST_CATCH(...) {} diff --git a/include/boost/stacktrace/detail/stacktrace_linux.hpp b/include/boost/stacktrace/detail/stacktrace_linux.hpp index 9a5693b..0720d5d 100644 --- a/include/boost/stacktrace/detail/stacktrace_linux.hpp +++ b/include/boost/stacktrace/detail/stacktrace_linux.hpp @@ -16,14 +16,20 @@ #include #include +#include + namespace boost { namespace stacktrace { -stacktrace::stacktrace() BOOST_NOEXCEPT { +stacktrace::stacktrace() BOOST_NOEXCEPT + : hash_code_(0) +{ boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_); bt.frames_count = ::backtrace(bt.buffer, boost::stacktrace::detail::backtrace_holder::max_size); - if (bt.buffer[bt.frames_count] == 0) { + if (bt.buffer[bt.frames_count - 1] == 0) { -- bt.frames_count; } + + hash_code_ = boost::hash_range(bt.buffer, bt.buffer + bt.frames_count); } }} // namespace boost::stacktrace diff --git a/include/boost/stacktrace/detail/stacktrace_noop.hpp b/include/boost/stacktrace/detail/stacktrace_noop.hpp index ebff503..82c86c2 100644 --- a/include/boost/stacktrace/detail/stacktrace_noop.hpp +++ b/include/boost/stacktrace/detail/stacktrace_noop.hpp @@ -18,7 +18,9 @@ namespace boost { namespace stacktrace { -stacktrace::stacktrace() BOOST_NOEXCEPT { +stacktrace::stacktrace() BOOST_NOEXCEPT + : hash_code_(0) +{ boost::stacktrace::detail::construct_bt_and_return(impl_); } diff --git a/include/boost/stacktrace/detail/stacktrace_windows.hpp b/include/boost/stacktrace/detail/stacktrace_windows.hpp index f23d8f1..b2c747c 100644 --- a/include/boost/stacktrace/detail/stacktrace_windows.hpp +++ b/include/boost/stacktrace/detail/stacktrace_windows.hpp @@ -18,9 +18,13 @@ namespace boost { namespace stacktrace { -stacktrace::stacktrace() BOOST_NOEXCEPT { +stacktrace::stacktrace() BOOST_NOEXCEPT + : hash_code_(0) +{ boost::stacktrace::detail::backtrace_holder& bt = boost::stacktrace::detail::construct_bt_and_return(impl_); - bt.frames_count = CaptureStackBackTrace(0, boost::stacktrace::detail::backtrace_holder::max_size, bt.buffer, 0); + boost::detail::winapi::ULONG_ hc = 0; + bt.frames_count = CaptureStackBackTrace(0, boost::stacktrace::detail::backtrace_holder::max_size, bt.buffer, &hc); + boost::hash_combine(hash_code_, hc); } }} // namespace boost::stacktrace diff --git a/src/stacktrace_src.ipp b/src/stacktrace_src.ipp index 42a2380..7f85e3f 100644 --- a/src/stacktrace_src.ipp +++ b/src/stacktrace_src.ipp @@ -43,7 +43,9 @@ namespace boost { namespace stacktrace { // requered to avoid `boost::stacktrace::detail::backtrace_holder` apearing in // stack traces. -stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT { +stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT + : hash_code_(bt.hash_code_) +{ new (&impl_) boost::stacktrace::detail::backtrace_holder( boost::stacktrace::detail::to_bt(bt.impl_) ); @@ -51,6 +53,7 @@ stacktrace::stacktrace(const stacktrace& bt) BOOST_NOEXCEPT { stacktrace& stacktrace::operator=(const stacktrace& bt) BOOST_NOEXCEPT { boost::stacktrace::detail::to_bt(impl_) = boost::stacktrace::detail::to_bt(bt.impl_); + hash_code_ = bt.hash_code_; return *this; } @@ -68,11 +71,15 @@ std::string stacktrace::operator[](std::size_t frame) const { } bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT { - return boost::stacktrace::detail::to_bt(impl_) < boost::stacktrace::detail::to_bt(rhs.impl_); + return hash_code_ < rhs.hash_code_ + || (hash_code_ == rhs.hash_code_ && boost::stacktrace::detail::to_bt(impl_) < boost::stacktrace::detail::to_bt(rhs.impl_)) + ; } bool stacktrace::operator==(const stacktrace& rhs) const BOOST_NOEXCEPT { - return boost::stacktrace::detail::to_bt(impl_) == boost::stacktrace::detail::to_bt(rhs.impl_); + return hash_code_ == rhs.hash_code_ + && boost::stacktrace::detail::to_bt(impl_) == boost::stacktrace::detail::to_bt(rhs.impl_) + ; } }} diff --git a/test/test.cpp b/test/test.cpp index b01f52d..acd8453 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -91,6 +91,13 @@ void test_comparisons() { BOOST_TEST(nst < cst || cst < nst); BOOST_TEST(nst > cst || cst > nst); + + + BOOST_TEST(hash_value(nst) == hash_value(nst)); + BOOST_TEST(hash_value(cst) == hash_value(st)); + + BOOST_TEST(hash_value(nst) != hash_value(cst)); + BOOST_TEST(hash_value(st) != hash_value(nst)); } int main() {