6#ifndef MIMICPP_UTILITIES_STACKTRACE_HPP
7#define MIMICPP_UTILITIES_STACKTRACE_HPP
20#ifndef MIMICPP_DETAIL_IS_MODULE
27 #include <type_traits>
38 struct find_stacktrace_backend;
101 template <
typename Backend>
108 template <
typename T>
110 std::semiregular<std::remove_cvref_t<T>>
112 {
decltype(traits)
::current(value) } -> std::convertible_to<std::remove_cvref_t<T>>;
113 {
decltype(traits)
::current(value, value) } -> std::convertible_to<std::remove_cvref_t<T>>;
114 {
decltype(traits)::size(
backend) } -> std::convertible_to<std::size_t>;
116 {
decltype(traits)::description(
backend, value) } -> std::convertible_to<std::string>;
117 {
decltype(traits)::source_file(
backend, value) } -> std::convertible_to<std::string>;
118 {
decltype(traits)::source_line(
backend, value) } -> std::convertible_to<std::size_t>;
138 static constexpr NullBackend current([[maybe_unused]] std::size_t
const skip, [[maybe_unused]] std::size_t
const max)
noexcept
163 raise_unsupported_operation();
168 raise_unsupported_operation();
174 raise_unsupported_operation();
179 static void raise_unsupported_operation()
181 throw std::runtime_error{
"stacktrace::NullBackend doesn't support this operation."};
187 "stacktrace::NullBackend does not satisfy the stacktrace::backend concept");
202 constexpr virtual bool empty()
const = 0;
205 constexpr virtual std::size_t
size()
const = 0;
208 constexpr virtual std::string
description(std::size_t at)
const = 0;
211 constexpr virtual std::string
source_file(std::size_t at)
const = 0;
214 constexpr virtual std::size_t
source_line(std::size_t at)
const = 0;
217 virtual ~Concept() =
default;
219 Concept(Concept
const&) =
default;
220 Concept&
operator=(Concept
const&) =
default;
221 Concept(Concept&&) =
default;
225 template <
typename Backend>
233 explicit Model(Backend&& backend)
noexcept(std::is_nothrow_move_constructible_v<Backend>)
234 : m_Backend{std::move(backend)}
239 constexpr bool empty()
const override
241 return std::invoke(BackendTraits::empty, m_Backend);
245 constexpr std::size_t
size()
const override
247 return std::invoke(BackendTraits::size, m_Backend);
251 constexpr std::string
description(std::size_t
const at)
const override
253 return std::invoke(BackendTraits::description, m_Backend, at);
257 constexpr std::string
source_file(std::size_t
const at)
const override
259 return std::invoke(BackendTraits::source_file, m_Backend, at);
263 constexpr std::size_t
source_line(std::size_t
const at)
const override
265 return std::invoke(BackendTraits::source_line, m_Backend, at);
290 template <
typename Backend>
291 requires(!std::same_as<Stacktrace, std::remove_cvref_t<Backend>>)
295 : m_Backend{std::make_shared<Model<Backend>>(std::move(backend))}
327 return backend().size();
337 return backend().empty();
348 return backend().description(at);
359 return backend().source_file(at);
370 return backend().source_line(at);
377 && std::ranges::all_of(
378 std::views::iota(0u, lhs.
size()),
379 [&](std::size_t
const index) {
380 return lhs.description(index) == rhs.description(index)
381 && lhs.source_file(index) == rhs.source_file(index)
382 && lhs.source_line(index) == rhs.source_line(index);
387 std::shared_ptr<Concept> m_Backend;
390 Concept
const& backend() const noexcept
399namespace mimicpp::util::stacktrace::detail
401 template <
typename T>
402 concept backend_finder =
requires {
407 template <
template <
typename>
typename Traits, backend_finder FindBackend = custom::find_stacktrace_backend>
408 Traits<typename FindBackend::type> find_traits_impl([[maybe_unused]] priority_tag<1u>);
411#ifndef MIMICPP_CONFIG_EXPERIMENTAL_USE_CUSTOM_STACKTRACE
412 template <
template <
typename>
typename Traits, backend_finder FindBackend = stacktrace::find_backend>
413 Traits<typename FindBackend::type> find_traits_impl([[maybe_unused]] priority_tag<0u>);
417 template <
template <
typename>
typename Traits>
420 return find_traits_impl<Traits>(priority_tag<1u>{});
424 inline std::size_t calc_skip(std::size_t
const skip)
427 MIMICPP_ASSERT(skip < std::numeric_limits<std::size_t>::max() - 1u,
"Skip is too high.");
428 MIMICPP_ASSERT(skip < std::numeric_limits<std::size_t>::max() - baseSkip,
"Skip + base-skip is too high.");
430 return skip + 1u + baseSkip;
435 template <
typename... Canary,
template <
typename>
typename TraitsTemplate = backend_traits>
437 Stacktrace operator()(std::size_t
const skip, std::size_t
const max)
const
439 using Traits =
decltype(find_traits<TraitsTemplate>());
441 return Stacktrace{Traits::current(calc_skip(skip), max)};
444 template <
typename... Canary,
template <
typename>
typename TraitsTemplate = backend_traits>
446 Stacktrace operator()(std::size_t
const skip)
const
448 using Traits =
decltype(find_traits<TraitsTemplate>());
450 return Stacktrace{Traits::current(calc_skip(skip))};
453 template <
typename... Canary,
template <
typename>
typename TraitsTemplate = backend_traits>
455 Stacktrace operator()()
const
457 using Traits =
decltype(find_traits<TraitsTemplate>());
459 return Stacktrace{Traits::current(calc_skip(0u))};
473 inline constexpr detail::current_fn
current{};
476namespace mimicpp::util::stacktrace::detail
478 template <pr
int_iterator OutIter>
479 constexpr OutIter print_entry(OutIter out, Stacktrace
const& stacktrace, std::size_t
const index)
481 MIMICPP_ASSERT(index < stacktrace.size(),
"Index out of bounds.");
483 return printing::detail::print_source_location(
485 stacktrace.source_file(index),
486 stacktrace.source_line(index),
487 stacktrace.description(index));
492struct mimicpp::printing::detail::state::common_type_printer<
mimicpp::util::Stacktrace>
494 template <pr
int_iterator OutIter>
495 static constexpr OutIter
print(OutIter out, util::Stacktrace
const& stacktrace)
497 if (stacktrace.empty())
499 return format::format_to(std::move(out),
"empty");
502 for (std::size_t
const i : std::views::iota(0u, stacktrace.size()))
504 out = format::format_to(std::move(out),
"#{} ", i);
505 out = util::stacktrace::detail::print_entry(
509 out = format::format_to(std::move(out),
"\n");
516#if MIMICPP_CONFIG_EXPERIMENTAL_USE_CXX23_STACKTRACE
518 #define MIMICPP_DETAIL_HAS_WORKING_STACKTRACE_BACKEND 1
519#elif MIMICPP_CONFIG_EXPERIMENTAL_USE_BOOST_STACKTRACE
521 #define MIMICPP_DETAIL_HAS_WORKING_STACKTRACE_BACKEND 1
522#elif MIMICPP_CONFIG_EXPERIMENTAL_USE_CPPTRACE
524 #define MIMICPP_DETAIL_HAS_WORKING_STACKTRACE_BACKEND 1
#define MIMICPP_ASSERT(condition, msg)
Definition Config.hpp:51
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
~Stacktrace()=default
Defaulted destructor.
std::size_t source_line(std::size_t const at) const
Queries the underlying stacktrace-backend for the source-line of the selected stacktrace-entry.
Definition Stacktrace.hpp:368
std::string source_file(std::size_t const at) const
Queries the underlying stacktrace-backend for the source-file of the selected stacktrace-entry.
Definition Stacktrace.hpp:357
Stacktrace(Stacktrace &&)=default
Defaulted move-constructor.
Stacktrace()
Default constructor.
Definition Stacktrace.hpp:281
friend bool operator==(Stacktrace const &lhs, Stacktrace const &rhs)
Definition Stacktrace.hpp:374
std::string description(std::size_t const at) const
Queries the underlying stacktrace-backend for the description of the selected stacktrace-entry.
Definition Stacktrace.hpp:346
Stacktrace(Stacktrace const &)=default
Defaulted copy-constructor.
bool empty() const
Queries the underlying stacktrace-backend whether it's empty.
Definition Stacktrace.hpp:335
std::size_t size() const
Queries the underlying stacktrace-backend for its size.
Definition Stacktrace.hpp:325
Stacktrace(Backend backend)
Constructor storing the given stacktrace-backend.
Definition Stacktrace.hpp:294
Stacktrace & operator=(Stacktrace const &)=default
Defaulted copy-assignment-operator.
Stacktrace & operator=(Stacktrace &&)=default
Defaulted move-assignment-operator.
The fallback stacktrace-backend.
Definition Stacktrace.hpp:126
Determines, whether B behaves as a the builtin type bool.
Definition Concepts.hpp:66
Checks whether the given type satisfies the requirements of a stacktrace backend.
Definition Stacktrace.hpp:109
constexpr printing::PrintFn print
Functional object, converting the given object to its textual representation.
Definition Print.hpp:183
std::atomic_size_t & stacktrace_base_skip() noexcept
Controls whether the base stacktrace-skip value.
Definition Settings.hpp:46
constexpr detail::current_fn current
Function object, which generates the current-stacktrace.
Definition Stacktrace.hpp:473
static constexpr bool empty(NullBackend const &stacktrace) noexcept
Definition Stacktrace.hpp:156
static std::size_t source_line(NullBackend const &stacktrace, std::size_t const at)
Definition Stacktrace.hpp:172
static constexpr NullBackend current(std::size_t const skip) noexcept
Definition Stacktrace.hpp:144
static constexpr NullBackend current(std::size_t const skip, std::size_t const max) noexcept
Definition Stacktrace.hpp:138
static std::string source_file(NullBackend const &stacktrace, std::size_t const at)
Definition Stacktrace.hpp:166
static std::string description(NullBackend const &stacktrace, std::size_t const at)
Definition Stacktrace.hpp:161
static constexpr std::size_t size(NullBackend const &stacktrace) noexcept
Definition Stacktrace.hpp:150
Trait type for stacktrace backends.
Definition Fwd.hpp:453
Definition Stacktrace.hpp:529
NullBackend type
Definition Stacktrace.hpp:530