| 72 | /// @tparam Allocator Allocator to use during stack capture. |
| 73 | template <class Allocator> |
| 74 | class basic_stacktrace { |
| 75 | std::vector<boost::stacktrace::frame, Allocator> impl_; |
| 76 | typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t; |
| 77 | |
| 78 | /// @cond |
| 79 | void fill(native_frame_ptr_t* begin, std::size_t size) { |
| 80 | if (!size) { |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | impl_.reserve(static_cast<std::size_t>(size)); |
| 85 | for (std::size_t i = 0; i < size; ++i) { |
| 86 | if (!begin[i]) { |
| 87 | return; |
| 88 | } |
| 89 | impl_.push_back( |
| 90 | frame(begin[i]) |
| 91 | ); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept { |
| 96 | const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0); |
| 97 | return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes |
| 98 | } |
| 99 | |
| 100 | BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) { |
| 101 | constexpr std::size_t buffer_size = 128; |
| 102 | if (!max_depth) { |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | BOOST_TRY { |
| 107 | { // Fast path without additional allocations |
| 108 | native_frame_ptr_t buffer[buffer_size]; |
| 109 | const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1); |
| 110 | if (buffer_size > frames_count || frames_count == max_depth) { |
| 111 | fill(buffer, frames_count); |
| 112 | return; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | // Failed to fit in `buffer_size`. Allocating memory: |
| 117 | #ifdef BOOST_NO_CXX11_ALLOCATOR |
| 118 | typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t; |
| 119 | #else |
| 120 | typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t; |
| 121 | #endif |
| 122 | std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator()); |
| 123 | do { |
| 124 | const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1); |
| 125 | if (buf.size() > frames_count || frames_count == max_depth) { |
| 126 | fill(&buf[0], frames_count); |
| 127 | return; |
| 128 | } |
| 129 | |
| 130 | buf.resize(buf.size() * 2); |
| 131 | } while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`. |
nothing calls this directly
no outgoing calls
no test coverage detected