6#ifndef MIMICPP_STACKTRACE_HPP
7#define MIMICPP_STACKTRACE_HPP
32 struct find_stacktrace_backend;
96 template <
typename Backend>
103 template <
typename T>
107 {
decltype(traits)
::current(value) } -> std::convertible_to<std::remove_cvref_t<T>>;
108 {
decltype(traits)::size(
backend) } -> std::convertible_to<std::size_t>;
109 {
decltype(traits)::empty(
backend) } -> std::convertible_to<bool>;
110 {
decltype(traits)::description(
backend, value) } -> std::convertible_to<std::string>;
111 {
decltype(traits)::source_file(
backend, value) } -> std::convertible_to<std::string>;
112 {
decltype(traits)::source_line(
backend, value) } -> std::convertible_to<std::size_t>;
120namespace mimicpp::stacktrace::detail
122 template <
typename Backend>
124 std::size_t size(
const std::any& backend)
126 return backend_traits<Backend>::size(
127 std::any_cast<const Backend&>(backend));
130 template <
typename Backend>
132 bool empty(
const std::any& backend)
134 return backend_traits<Backend>::empty(
135 std::any_cast<const Backend&>(backend));
138 template <
typename Backend>
140 std::string description(
const std::any& backend,
const std::size_t index)
142 return backend_traits<Backend>::description(
143 std::any_cast<const Backend&>(backend),
147 template <
typename Backend>
149 std::string source_file(
const std::any& backend,
const std::size_t index)
151 return backend_traits<Backend>::source_file(
152 std::any_cast<const Backend&>(backend),
156 template <
typename Backend>
158 std::size_t source_line(
const std::any& backend,
const std::size_t index)
160 return backend_traits<Backend>::source_line(
161 std::any_cast<const Backend&>(backend),
175 using size_fn = std::size_t (*)(
const std::any&);
192 template <
typename Inner>
193 requires(!std::same_as<Stacktrace, std::remove_cvref_t<Inner>>)
197 : m_Inner{std::forward<Inner>(inner)},
198 m_SizeFn{&stacktrace::detail::size<std::remove_cvref_t<Inner>>},
199 m_EmptyFn{&stacktrace::detail::empty<std::remove_cvref_t<Inner>>},
200 m_DescriptionFn{&stacktrace::detail::description<std::remove_cvref_t<Inner>>},
201 m_SourceFileFn{&stacktrace::detail::source_file<std::remove_cvref_t<Inner>>},
202 m_SourceLineFn{&stacktrace::detail::source_line<std::remove_cvref_t<Inner>>}
233 constexpr std::size_t
size()
const
235 return std::invoke(m_SizeFn, m_Inner);
245 return std::invoke(m_EmptyFn, m_Inner);
256 return std::invoke(m_DescriptionFn, m_Inner, at);
267 return std::invoke(m_SourceFileFn, m_Inner, at);
278 return std::invoke(m_SourceLineFn, m_Inner, at);
285 && std::ranges::all_of(
286 std::views::iota(0u, lhs.
size()),
287 [&](
const std::size_t index) {
288 return lhs.description(index) == rhs.description(index)
289 && lhs.source_file(index) == rhs.source_file(index)
290 && lhs.source_line(index) == rhs.source_line(index);
304namespace mimicpp::stacktrace::detail::current_hook
306 template <
typename FindBackend,
template <
typename>
typename Traits>
307 concept existing_backend =
requires {
310 typename FindBackend::type>
::current(std::size_t{})
315 template <
typename>
typename Traits,
316 existing_backend<Traits> FindBackendT = custom::find_stacktrace_backend>
318 constexpr auto current([[maybe_unused]]
const priority_tag<2>,
const std::size_t skip)
321 typename FindBackendT::type>
::current(skip + 1u);
325 template <
typename>
typename Traits,
326 existing_backend<Traits> FindBackendT = find_backend>
328 constexpr auto current([[maybe_unused]]
const priority_tag<1>,
const std::size_t skip)
331 typename FindBackendT::type>
::current(skip + 1u);
334 template <
template <
typename>
typename Traits>
335 constexpr auto current([[maybe_unused]]
const priority_tag<0>, [[maybe_unused]]
const std::size_t skip)
338 always_false<Traits<void>>{},
339 "mimic++ does not have a registered stacktrace-backend.");
342 constexpr priority_tag<2> maxTag;
346 template <
typename... Canary,
template <
typename>
typename Traits = backend_traits>
348 Stacktrace operator()(
const std::size_t skip)
const
351 current_hook::current<Traits>(maxTag, skip + 1u)};
354 template <
typename... Canary,
template <
typename>
typename Traits = backend_traits>
356 Stacktrace operator()()
const
359 current_hook::current<Traits>(maxTag, 1u)};
374 constexpr detail::current_hook::current_fn
current{};
378class mimicpp::detail::Printer<
mimicpp::Stacktrace>
381 template <pr
int_iterator OutIter>
382 static OutIter
print(OutIter out,
const Stacktrace& stacktrace)
384 if (stacktrace.empty())
386 return format::format_to(
391 for (
const std::size_t i : std::views::iota(0u, stacktrace.size()))
393 out = format::format_to(
396 stacktrace.source_file(i),
397 stacktrace.source_line(i),
398 stacktrace.description(i));
439 raise_unsupported_operation();
444 raise_unsupported_operation();
450 raise_unsupported_operation();
455 static void raise_unsupported_operation()
457 throw std::runtime_error{
"stacktrace::NullBackend doesn't support this operation."};
463 "stacktrace::NullBackend does not satisfy the stacktrace::backend concept");
465#if defined(MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE) \
466 && not defined(NDEBUG)
468 #ifdef MIMICPP_CONFIG_EXPERIMENTAL_USE_CPPTRACE
470 #if __has_include(<cpptrace/basic.hpp>)
471 #include <cpptrace/basic.hpp>
472 #elif __has_include(<cpptrace/cpptrace.hpp>)
475 #include <cpptrace/cpptrace.hpp>
477 #error "The cpptrace stacktrace backend is explicitly enabled, but the the required include-file can not be found."
482 class CpptraceBackend
485 ~CpptraceBackend() =
default;
488 explicit CpptraceBackend(cpptrace::raw_trace&& trace) noexcept
489 : m_Trace{std::move(trace)}
493 CpptraceBackend(
const CpptraceBackend&) =
default;
494 CpptraceBackend& operator=(
const CpptraceBackend&) =
default;
495 CpptraceBackend(CpptraceBackend&&) =
default;
496 CpptraceBackend& operator=(CpptraceBackend&&) =
default;
499 const cpptrace::stacktrace& data()
const
501 if (
const auto* raw = std::get_if<cpptrace::raw_trace>(&m_Trace))
503 m_Trace = raw->resolve();
506 return std::get<cpptrace::stacktrace>(m_Trace);
510 using TraceT = std::variant<cpptrace::raw_trace, cpptrace::stacktrace>;
511 mutable TraceT m_Trace;
517 using type = CpptraceBackend;
524 static CpptraceBackend
current(
const std::size_t skip)
526 return CpptraceBackend{cpptrace::generate_raw_trace(skip + 1)};
530 static std::size_t size(
const CpptraceBackend& backend)
532 return backend.data().frames.size();
536 static bool empty(
const CpptraceBackend& backend)
538 return backend.data().empty();
542 static std::string description(
const CpptraceBackend& backend,
const std::size_t at)
544 return frame(backend, at).symbol;
548 static std::string source_file(
const CpptraceBackend& backend,
const std::size_t at)
550 return frame(backend, at).filename;
554 static std::size_t source_line(
const CpptraceBackend& backend,
const std::size_t at)
556 return frame(backend, at).line.value_or(0u);
560 static const cpptrace::stacktrace_frame& frame(
const CpptraceBackend& backend,
const std::size_t at)
562 return backend.data().frames.at(at);
568 "stacktrace::CpptraceBackend does not satisfy the stacktrace::backend concept");
570 #define MIMICPP_DETAIL_WORKING_STACKTRACE_BACKEND
572 #elif defined(__cpp_lib_stacktrace)
574 #include <stacktrace>
578 using type = std::stacktrace;
581template <
typename Allocator>
584 using BackendT = std::basic_stacktrace<Allocator>;
587 static BackendT
current(
const std::size_t skip)
589 return BackendT::current(skip + 1);
593 static std::size_t size(
const BackendT& backend)
595 return backend.size();
599 static bool empty(
const BackendT& backend)
601 return backend.empty();
605 static std::string description(
const BackendT& backend,
const std::size_t at)
607 return entry(backend, at).description();
611 static std::string source_file(
const BackendT& backend,
const std::size_t at)
613 return entry(backend, at).source_file();
617 static std::size_t source_line(
const BackendT& backend,
const std::size_t at)
619 return entry(backend, at).source_line();
623 static const std::stacktrace_entry& entry(
const BackendT& backend,
const std::size_t at)
625 return backend.at(at);
631 "std::stacktrace does not satisfy the stacktrace::backend concept");
633 #define MIMICPP_DETAIL_WORKING_STACKTRACE_BACKEND
646#ifndef MIMICPP_DETAIL_WORKING_STACKTRACE_BACKEND
Stacktrace(const Stacktrace &)=default
Defaulted move-constructor.
friend bool operator==(const Stacktrace &lhs, const Stacktrace &rhs)
Definition Stacktrace.hpp:282
Stacktrace(Stacktrace &&)=default
Defaulted copy-constructor.
constexpr Stacktrace(Inner &&inner)
Constructor storing the given stacktrace-backend type-erased.
Definition Stacktrace.hpp:196
~Stacktrace()=default
Defaulted destructor.
std::size_t(*)(const std::any &) size_fn
Definition Stacktrace.hpp:175
constexpr std::string description(const std::size_t at) const
Queries the underlying stacktrace-backend for the description of the selected stacktrace-entry.
Definition Stacktrace.hpp:254
std::string(*)(const std::any &, std::size_t) description_fn
Definition Stacktrace.hpp:177
constexpr std::size_t size() const
Queries the underlying stacktrace-backend for its size.
Definition Stacktrace.hpp:233
Stacktrace & operator=(const Stacktrace &)=default
Defaulted move-assignment-operator.
std::string(*)(const std::any &, std::size_t) source_file_fn
Definition Stacktrace.hpp:178
constexpr bool empty() const
Queries the underlying stacktrace-backend whether its empty.
Definition Stacktrace.hpp:243
Stacktrace & operator=(Stacktrace &&)=default
Defaulted copy-assignment-operator.
constexpr std::size_t source_line(const std::size_t at) const
Queries the underlying stacktrace-backend for the source-line of the selected stacktrace-entry.
Definition Stacktrace.hpp:276
constexpr std::string source_file(const std::size_t at) const
Queries the underlying stacktrace-backend for the source-file of the selected stacktrace-entry.
Definition Stacktrace.hpp:265
std::size_t(*)(const std::any &, std::size_t) source_line_fn
Definition Stacktrace.hpp:179
bool(*)(const std::any &) empty_fn
Definition Stacktrace.hpp:176
The fallback stacktrace-backend.
Definition Stacktrace.hpp:412
Checks whether the given type satisfies the requirements of a stacktrace backend.
Definition Stacktrace.hpp:104
constexpr detail::current_hook::current_fn current
Function object, which generates the current-stacktrace.
Definition Stacktrace.hpp:374
constexpr detail::PrintFn print
Functional object, converting the given object to its textual representation.
Definition Printer.hpp:590
Definition BoostTest.hpp:20
Trait type for stacktrace backends.
Definition Stacktrace.hpp:97
static std::string description(const NullBackend &backend, const std::size_t at)
Definition Stacktrace.hpp:437
static constexpr bool empty(const NullBackend &backend) noexcept
Definition Stacktrace.hpp:432
static constexpr std::size_t size(const NullBackend &backend) noexcept
Definition Stacktrace.hpp:426
static std::string source_file(const NullBackend &backend, const std::size_t at)
Definition Stacktrace.hpp:442
static NullBackend current(const std::size_t skip) noexcept
Definition Stacktrace.hpp:420
static std::size_t source_line(const NullBackend &backend, const std::size_t at)
Definition Stacktrace.hpp:448
Definition Stacktrace.hpp:649
NullBackend type
Definition Stacktrace.hpp:650