From b8dcd2b55334090fa15007d614003e23a32daf2c Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 25 Oct 2016 21:52:29 +0300 Subject: [PATCH] Working version of iterator and frame --- include/boost/stacktrace.hpp | 163 ++++++++++-------- .../boost/stacktrace/detail/stacktrace.ipp | 11 +- src/stacktrace_src.ipp | 10 +- test/test_noop.cpp | 6 +- 4 files changed, 115 insertions(+), 75 deletions(-) diff --git a/include/boost/stacktrace.hpp b/include/boost/stacktrace.hpp index a51c9ab..2322d2f 100644 --- a/include/boost/stacktrace.hpp +++ b/include/boost/stacktrace.hpp @@ -12,12 +12,14 @@ # pragma once #endif -#include -#include +#include #include #include +#include +#include + #include #include @@ -82,71 +84,6 @@ namespace boost { namespace stacktrace { -class stacktrace; - -class frame { - void* frame_no_; -public: -}; - -//typedef std::string frame; - -/// @cond -namespace detail { - -class iterator : public boost::iterator_facade< - iterator, - const frame, - boost::random_access_traversal_tag> -{ - typedef boost::iterator_facade< - iterator, - const frame, - boost::random_access_traversal_tag - > base_t; - - const stacktrace* impl_; - std::size_t frame_no_; - - iterator(const stacktrace* impl, std::size_t frame_no) BOOST_NOEXCEPT - : impl_(impl) - , frame_no_(frame_no) - {} - - friend class ::boost::stacktrace::stacktrace; - friend class ::boost::iterators::iterator_core_access; - - const frame& dereference() const; /* { - return (*impl_)[frame_no_]; - }*/ - - bool equal(const iterator& it) const BOOST_NOEXCEPT { - return impl_ == it.impl_ && frame_no_ == it.frame_no_; - } - - void increment() BOOST_NOEXCEPT { - ++frame_no_; - } - - void decrement() BOOST_NOEXCEPT { - --frame_no_; - } - - void advance(std::size_t n) BOOST_NOEXCEPT { - frame_no_ += n; - } - - base_t::difference_type distance_to(const iterator& it) const { - BOOST_ASSERT(impl_ == it.impl_); - return it.frame_no_ - frame_no_; - } -public: - -}; - -} // namespace detail -/// @endcond - class stacktrace { #ifdef BOOST_STACKTRACE_LINK BOOST_STATIC_CONSTEXPR std::size_t max_implementation_size = sizeof(void*) * 110u; @@ -154,12 +91,79 @@ class stacktrace { #else boost::stacktrace::detail::backtrace_holder impl_; #endif - std::size_t hash_code_; + BOOST_STACKTRACE_FUNCTION std::string get_name(std::size_t frame_no) const; + BOOST_STACKTRACE_FUNCTION std::string get_source_file(std::size_t frame_no) const; + BOOST_STACKTRACE_FUNCTION std::size_t get_source_line(std::size_t frame_no) const BOOST_NOEXCEPT; + public: + class frame { + const stacktrace* impl_; + const std::size_t frame_no_; + + frame(const stacktrace* impl, std::size_t frame_no) BOOST_NOEXCEPT + : impl_(impl) + , frame_no_(frame_no) + {} + + friend class ::boost::stacktrace::stacktrace; + public: + std::string name() const; + std::string source_file() const; + std::size_t source_line() const BOOST_NOEXCEPT; + }; + + class iterator : public boost::iterator_facade< + iterator, + const frame, + boost::random_access_traversal_tag, + frame> + { + typedef boost::iterator_facade< + iterator, + const frame, + boost::random_access_traversal_tag + > base_t; + + const stacktrace* impl_; + std::size_t frame_no_; + + iterator(const stacktrace* impl, std::size_t frame_no) BOOST_NOEXCEPT + : impl_(impl) + , frame_no_(frame_no) + {} + + friend class ::boost::stacktrace::stacktrace; + friend class ::boost::iterators::iterator_core_access; + + frame dereference() const { + return (*impl_)[frame_no_]; + } + + bool equal(const iterator& it) const BOOST_NOEXCEPT { + return impl_ == it.impl_ && frame_no_ == it.frame_no_; + } + + void increment() BOOST_NOEXCEPT { + ++frame_no_; + } + + void decrement() BOOST_NOEXCEPT { + --frame_no_; + } + + void advance(std::size_t n) BOOST_NOEXCEPT { + frame_no_ += n; + } + + base_t::difference_type distance_to(const iterator& it) const { + BOOST_ASSERT(impl_ == it.impl_); + return it.frame_no_ - frame_no_; + } + }; + typedef frame value_type; - typedef boost::stacktrace::detail::iterator iterator; typedef iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; @@ -200,7 +204,9 @@ public: /// @throws std::bad_alloc if not enough memory to construct resulting string. /// /// @b Complexity: Amortized O(1), O(1) for noop backend. - BOOST_STACKTRACE_FUNCTION std::string operator[](std::size_t frame_no) const; + frame operator[](std::size_t frame_no) const { + return frame(this, frame_no); + } /// @cond bool operator!() const BOOST_NOEXCEPT { @@ -232,6 +238,17 @@ public: } }; +inline std::string stacktrace::frame::name() const { + return impl_->get_name(frame_no_); +} +inline std::string stacktrace::frame::source_file() const { + return impl_->get_source_file(frame_no_); +} +inline std::size_t stacktrace::frame::source_line() const BOOST_NOEXCEPT { + return impl_->get_source_line(frame_no_); +} + + /// Additional comparison operators for stacktraces that have amortized O(1) 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); } @@ -243,6 +260,12 @@ 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::frame& f) { + return os << f.name(); +} + /// 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/stacktrace.ipp b/include/boost/stacktrace/detail/stacktrace.ipp index 3435f0a..1c2e8f8 100644 --- a/include/boost/stacktrace/detail/stacktrace.ipp +++ b/include/boost/stacktrace/detail/stacktrace.ipp @@ -51,10 +51,19 @@ std::size_t stacktrace::size() const BOOST_NOEXCEPT { return impl_.size(); } -std::string stacktrace::operator[](std::size_t frame) const { +std::string stacktrace::get_name(std::size_t frame) const { return impl_.get_frame(frame); } + +std::string stacktrace::get_source_file(std::size_t frame) const { + return std::string(); +} + +std::size_t stacktrace::get_source_line(std::size_t frame) const BOOST_NOEXCEPT { + return 0; +} + bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT { return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && impl_ < rhs.impl_); } diff --git a/src/stacktrace_src.ipp b/src/stacktrace_src.ipp index 7f85e3f..00e9bfb 100644 --- a/src/stacktrace_src.ipp +++ b/src/stacktrace_src.ipp @@ -66,10 +66,18 @@ std::size_t stacktrace::size() const BOOST_NOEXCEPT { return boost::stacktrace::detail::to_bt(impl_).size(); } -std::string stacktrace::operator[](std::size_t frame) const { +std::string stacktrace::get_name(std::size_t frame) const { return boost::stacktrace::detail::to_bt(impl_).get_frame(frame); } +std::string stacktrace::get_source_file(std::size_t frame) const { + return std::string(); +} + +std::size_t stacktrace::get_source_line(std::size_t frame) const BOOST_NOEXCEPT { + return 0; +} + bool stacktrace::operator< (const stacktrace& rhs) const BOOST_NOEXCEPT { return hash_code_ < rhs.hash_code_ || (hash_code_ == rhs.hash_code_ && boost::stacktrace::detail::to_bt(impl_) < boost::stacktrace::detail::to_bt(rhs.impl_)) diff --git a/test/test_noop.cpp b/test/test_noop.cpp index 8b997f0..b75264e 100644 --- a/test/test_noop.cpp +++ b/test/test_noop.cpp @@ -15,16 +15,16 @@ BOOST_SYMBOL_IMPORT stacktrace return_from_nested_namespaces(); void test_deeply_nested_namespaces() { BOOST_TEST(return_from_nested_namespaces().size() == 0); - BOOST_TEST(return_from_nested_namespaces()[0] == ""); + BOOST_TEST(return_from_nested_namespaces()[0].name() == ""); } void test_nested() { std::pair res = foo2(15); BOOST_TEST(res.first.size() == 0); - BOOST_TEST(res.first[0] == ""); + BOOST_TEST(res.first[0].name() == ""); BOOST_TEST(res.second.size() == 0); - BOOST_TEST(res.second[0] == ""); + BOOST_TEST(res.second[0].name() == ""); }