From 3d259ba91cb7d4dbc60905b53f072a71581b1fbc Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Sat, 22 Jan 2022 14:35:11 +0100 Subject: [PATCH] [stacktrace] Move into [diagnostics] --- source/diagnostics.tex | 726 ++++++++++++++++++++++++++++++++++++++++- source/utilities.tex | 720 ---------------------------------------- 2 files changed, 724 insertions(+), 722 deletions(-) diff --git a/source/diagnostics.tex b/source/diagnostics.tex index 438d911c5b..d145ced062 100644 --- a/source/diagnostics.tex +++ b/source/diagnostics.tex @@ -10,7 +10,8 @@ \pnum The following subclauses describe components for reporting several kinds of exceptional conditions, -documenting program assertions, and +documenting program assertions, +obtaining stacktraces, and a global variable for error number codes, as summarized in \tref{diagnostics.summary}. @@ -18,7 +19,8 @@ \ref{std.exceptions} & Exception classes & \tcode{} \\ \rowsep \ref{assertions} & Assertions & \tcode{} \\ \rowsep \ref{errno} & Error numbers & \tcode{} \\ \rowsep -\ref{syserr} & System error support & \tcode{} \\ +\ref{syserr} & System error support & \tcode{} \\ \rowsep +\ref{stacktrace} & Stacktrace & \tcode{} \\ \end{libsumtab} \rSec1[std.exceptions]{Exception classes} @@ -1677,3 +1679,723 @@ code.message()}. \end{note} \end{itemdescr} + +\rSec1[stacktrace]{Stacktrace} + +\rSec2[stacktrace.general]{General} + +\pnum +Subclause \ref{stacktrace} describes components +that \Cpp{} programs may use to store +the stacktrace of the current thread of execution and +query information about the stored stacktrace at runtime. + +\pnum +The \defn{invocation sequence} of the current evaluation $x_0$ +in the current thread of execution +is a sequence $(x_0, \ldots, x_n)$ of evaluations such that, for $i \geq 0$, +$x_i$ is within the function invocation $x_{i+1}$\iref{intro.execution}. + +\pnum +A \defn{stacktrace} is an approximate representation of +an invocation sequence and consists of stacktrace entries. +A \defn{stacktrace entry} represents an evaluation in a stacktrace. + +\rSec2[stacktrace.syn]{Header \tcode{} synopsis} + +\indexheader{stacktrace}% +\begin{codeblock} +namespace std { + // \ref{stacktrace.entry}, class \tcode{stacktrace_entry} + class stacktrace_entry; + + // \ref{stacktrace.basic}, class template \tcode{basic_stacktrace} + template + class basic_stacktrace; + + // \tcode{basic_stacktrace} \grammarterm{typedef-name}s + using stacktrace = basic_stacktrace>; + + // \ref{stacktrace.basic.nonmem}, non-member functions + template + void swap(basic_stacktrace& a, basic_stacktrace& b) + noexcept(noexcept(a.swap(b))); + + string to_string(const stacktrace_entry& f); + + template + string to_string(const basic_stacktrace& st); + + template + basic_ostream& + operator<<(basic_ostream& os, const stacktrace_entry& f); + + template + basic_ostream& + operator<<(basic_ostream& os, const basic_stacktrace& st); + + namespace pmr { + using stacktrace = basic_stacktrace>; + } + + // \ref{stacktrace.basic.hash}, hash support + template struct hash; + template<> struct hash; + template struct hash>; +} +\end{codeblock} + +\rSec2[stacktrace.entry]{Class \tcode{stacktrace_entry}} + +\rSec3[stacktrace.entry.overview]{Overview} + +\begin{codeblock} +namespace std { + class @\libglobal{stacktrace_entry}@ { + public: + using native_handle_type = @\impdefx{\tcode{stacktrace_entry::native_handle_type}}@; + + // \ref{stacktrace.entry.ctor}, constructors + constexpr stacktrace_entry() noexcept; + constexpr stacktrace_entry(const stacktrace_entry& other) noexcept; + constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept; + + ~stacktrace_entry(); + + // \ref{stacktrace.entry.obs}, observers + constexpr native_handle_type native_handle() const noexcept; + constexpr explicit operator bool() const noexcept; + + // \ref{stacktrace.entry.query}, query + string description() const; + string source_file() const; + uint_least32_t source_line() const; + + // \ref{stacktrace.entry.cmp}, comparison + friend constexpr bool operator==(const stacktrace_entry& x, + const stacktrace_entry& y) noexcept; + friend constexpr strong_ordering operator<=>(const stacktrace_entry& x, + const stacktrace_entry& y) noexcept; + }; +} +\end{codeblock} + +\pnum +An object of type \tcode{stacktrace_entry} is either empty, +or represents a stacktrace entry and +provides operations for querying information about it. +The class \tcode{stacktrace_entry} models +\libconcept{regular}\iref{concepts.object} and +\tcode{\libconcept{three_way_comparable}}\iref{cmp.concept}. + +\rSec3[stacktrace.entry.ctor]{Constructors} + +\indexlibraryctor{stacktrace_entry}% +\begin{itemdecl} +constexpr stacktrace_entry() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{*this} is empty. +\end{itemdescr} + +\rSec3[stacktrace.entry.obs]{Observers} + +\indexlibrarymember{native_handle}{stacktrace_entry}% +\begin{itemdecl} +constexpr native_handle_type native_handle() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The semantics of this function are +\impldef{semantics of \tcode{stacktrace_entry::native_handle}}. + +\pnum +\remarks +Successive invocations of the \tcode{native_handle} function +for an unchanged \tcode{stacktrace_entry} object return identical values. +\end{itemdescr} + +\indexlibrarymember{operator bool}{stacktrace_entry}% +\begin{itemdecl} +constexpr explicit operator bool() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{false} if and only if \tcode{*this} is empty. +\end{itemdescr} + +\rSec3[stacktrace.entry.query]{Query} + +\pnum +\begin{note} +All the \tcode{stacktrace_entry} query functions treat +errors other than memory allocation errors +as ``no information available'' and do not throw in that case. +\end{note} + +\indexlibrarymember{description}{stacktrace_entry}% +\begin{itemdecl} +string description() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A description of the evaluation represented by \tcode{*this}, +or an empty string. + +\pnum +\throws +\tcode{bad_alloc} if memory for +the internal data structures or the resulting string cannot be allocated. +\end{itemdescr} + +\indexlibrarymember{source_file}{stacktrace_entry}% +\begin{itemdecl} +string source_file() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The presumed or actual name of the source file\iref{cpp.predefined} +that lexically contains the expression or statement +whose evaluation is represented by \tcode{*this}, or an empty string. + +\pnum +\throws +\tcode{bad_alloc} if memory for +the internal data structures or the resulting string cannot be allocated. +\end{itemdescr} + +\indexlibrarymember{source_line}{stacktrace_entry}% +\begin{itemdecl} +uint_least32_t source_line() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{0}, or a 1-based line number that lexically relates to the evaluation +represented by \tcode{*this}. +If \tcode{source_file} returns the presumed name of the source file, +returns the presumed line number; +if \tcode{source_file} returns the actual name of the source file, +returns the actual line number. + +\pnum +\throws +\tcode{bad_alloc} if memory for +the internal data structures cannot be allocated. +\end{itemdescr} + +\rSec3[stacktrace.entry.cmp]{Comparison} + +\indexlibrarymember{operator==}{stacktrace_entry}% +\begin{itemdecl} +friend constexpr bool operator==(const stacktrace_entry& x, const stacktrace_entry& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if and only if \tcode{x} and \tcode{y} represent +the same stacktrace entry or both \tcode{x} and \tcode{y} are empty. +\end{itemdescr} + +\rSec2[stacktrace.basic]{Class template \tcode{basic_stacktrace}} + +\rSec3[stacktrace.basic.overview]{Overview} + +\begin{codeblock} +namespace std { + template + class @\libglobal{basic_stacktrace}@ { + public: + using value_type = stacktrace_entry; + using const_reference = const value_type&; + using reference = value_type&; + using const_iterator = @\impdefx{type of \tcode{basic_stacktrace::const_iterator}}@; // see \ref{stacktrace.basic.obs} + using iterator = const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = @\impdefx{type of \tcode{basic_stacktrace::difference_type}}@; + using size_type = @\impdefx{type of \tcode{basic_stacktrace::size_type}}@; + using allocator_type = Allocator; + + // \ref{stacktrace.basic.ctor}, creation and assignment + static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; + static basic_stacktrace current(size_type skip, + const allocator_type& alloc = allocator_type()) noexcept; + static basic_stacktrace current(size_type skip, size_type max_depth, + const allocator_type& alloc = allocator_type()) noexcept; + + basic_stacktrace() noexcept(is_nothrow_default_constructible_v); + explicit basic_stacktrace(const allocator_type& alloc) noexcept; + + basic_stacktrace(const basic_stacktrace& other); + basic_stacktrace(basic_stacktrace&& other) noexcept; + basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc); + basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc); + basic_stacktrace& operator=(const basic_stacktrace& other); + basic_stacktrace& operator=(basic_stacktrace&& other) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); + + ~basic_stacktrace(); + + // \ref{stacktrace.basic.obs}, observers + allocator_type get_allocator() const noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + const_reference operator[](size_type) const; + const_reference at(size_type) const; + + // \ref{stacktrace.basic.cmp}, comparisons + template + friend bool operator==(const basic_stacktrace& x, + const basic_stacktrace& y) noexcept; + template + friend strong_ordering operator<=>(const basic_stacktrace& x, + const basic_stacktrace& y) noexcept; + + // \ref{stacktrace.basic.mod}, modifiers + void swap(basic_stacktrace& other) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); + + private: + vector frames_; // \expos + }; +} +\end{codeblock} + +\pnum +The class template \tcode{basic_stacktrace} satisfies +the requirements of +an allocator-aware container (\tref{container.alloc.req}), +a sequence container\iref{sequence.reqmts}, and +a reversible container\iref{container.requirements.general} +except that +\begin{itemize} +\item +only move, assignment, swap, and +operations defined for const-qualified sequence containers are supported and, +\item +the semantics of comparison functions +are different from those required for a container. +\end{itemize} + +\rSec3[stacktrace.basic.ctor]{Creation and assignment} + +\indexlibrarymember{current}{basic_stacktrace}% +\begin{itemdecl} +static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{basic_stacktrace} object +with \tcode{frames_} storing +the stacktrace of the current evaluation in the current thread of execution, or +an empty \tcode{basic_stacktrace} object +if the initialization of \tcode{frames_} failed. +\tcode{alloc} is passed to the constructor of the \tcode{frames_} object. + +\begin{note} +If the stacktrace was successfully obtained, +then \tcode{frames_.front()} is the \tcode{stacktrace_entry} +representing approximately the current evaluation, and +\tcode{frames_.back()} is the \tcode{stacktrace_entry} +representing approximately the initial function of +the current thread of execution. +\end{note} +\end{itemdescr} + +\indexlibrarymember{current}{basic_stacktrace}% +\begin{itemdecl} +static basic_stacktrace current(size_type skip, + const allocator_type& alloc = allocator_type()) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{t} be a stacktrace +as-if obtained via \tcode{basic_stacktrace::current(alloc)}. +Let \tcode{n} be \tcode{t.size()}. + +\pnum +\returns +A \tcode{basic_stacktrace} object +where \tcode{frames_} is direct-non-list-initialized from arguments +\tcode{t.begin() + min(n, skip)}, \tcode{t.end()}, and \tcode{alloc}, +or an empty \tcode{basic_stacktrace} object +if the initialization of \tcode{frames_} failed. +\end{itemdescr} + +\indexlibrarymember{current}{basic_stacktrace}% +\begin{itemdecl} +static basic_stacktrace current(size_type skip, size_type max_depth, + const allocator_type& alloc = allocator_type()) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{t} be a stacktrace +as-if obtained via \tcode{basic_stacktrace::current(alloc)}. +Let \tcode{n} be \tcode{t.size()}. + +\pnum +\expects +\tcode{skip <= skip + max_depth} is \tcode{true}. + +\pnum +\returns +A \tcode{basic_stacktrace} object +where \tcode{frames_} is direct-non-list-initialized from arguments +\tcode{t.begin() + min(n, skip)}, \tcode{t.begin() + min(n, skip + max_depth)}, +and \tcode{alloc}, +or an empty \tcode{basic_stacktrace} object +if the initialization of \tcode{frames_} failed. +\end{itemdescr} + +\indexlibraryctor{basic_stacktrace}% +\begin{itemdecl} +basic_stacktrace() noexcept(is_nothrow_default_constructible_v); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\ensures +\tcode{empty()} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{basic_stacktrace}% +\begin{itemdecl} +explicit basic_stacktrace(const allocator_type& alloc) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +\tcode{alloc} is passed to the \tcode{frames_} constructor. + +\pnum +\ensures +\tcode{empty()} is \tcode{true}. +\end{itemdescr} + +\indexlibraryctor{basic_stacktrace}% +\indexlibrarymember{operator=}{basic_stacktrace}% +\begin{itemdecl} +basic_stacktrace(const basic_stacktrace& other); +basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc); +basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc); +basic_stacktrace& operator=(const basic_stacktrace& other); +basic_stacktrace& operator=(basic_stacktrace&& other) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\remarks +Implementations may strengthen the exception specification +for these functions\iref{res.on.exception.handling} +by ensuring that \tcode{empty()} is \tcode{true} on failed allocation. +\end{itemdescr} + +\rSec3[stacktrace.basic.obs]{Observers} + +\indexlibrarymember{const_iterator}{basic_stacktrace}% +\begin{itemdecl} +using const_iterator = @\impdef@; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The type models +\libconcept{random_access_iterator}\iref{iterator.concept.random.access} and +meets the +\oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators}. +\end{itemdescr} + +\indexlibrarymember{get_allocator}{basic_stacktrace}% +\begin{itemdecl} +allocator_type get_allocator() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{frames_.get_allocator()}. +\end{itemdescr} + +\indexlibrarymember{begin}{basic_stacktrace}% +\indexlibrarymember{cbegin}{basic_stacktrace}% +\begin{itemdecl} +const_iterator begin() const noexcept; +const_iterator cbegin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An iterator referring to the first element in \tcode{frames_}. +If \tcode{empty()} is \tcode{true}, +then it returns the same value as \tcode{end()}. +\end{itemdescr} + +\indexlibrarymember{end}{basic_stacktrace}% +\indexlibrarymember{cend}{basic_stacktrace}% +\begin{itemdecl} +const_iterator end() const noexcept; +const_iterator cend() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The end iterator. +\end{itemdescr} + +\indexlibrarymember{rbegin}{basic_stacktrace}% +\indexlibrarymember{crbegin}{basic_stacktrace}% +\begin{itemdecl} +const_reverse_iterator rbegin() const noexcept; +const_reverse_iterator crbegin() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{reverse_iterator(cend())}. +\end{itemdescr} + +\indexlibrarymember{rend}{basic_stacktrace}% +\indexlibrarymember{crend}{basic_stacktrace}% +\begin{itemdecl} +const_reverse_iterator rend() const noexcept; +const_reverse_iterator crend() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{reverse_iterator(cbegin())}. +\end{itemdescr} + +\indexlibrarymember{empty}{basic_stacktrace}% +\begin{itemdecl} +[[nodiscard]] bool empty() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{frames_.empty()}. +\end{itemdescr} + +\indexlibrarymember{size}{basic_stacktrace}% +\begin{itemdecl} +size_type size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{frames_.size()}. +\end{itemdescr} + +\indexlibrarymember{max_size}{basic_stacktrace}% +\begin{itemdecl} +size_type max_size() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{frames_.max_size()}. +\end{itemdescr} + +\indexlibrarymember{operator[]}{basic_stacktrace}% +\begin{itemdecl} +const_reference operator[](size_type frame_no) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{frame_no < size()} is \tcode{true}. + +\pnum +\returns +\tcode{frames_[frame_no]}. + +\pnum +\throws +Nothing. +\end{itemdescr} + +\indexlibrarymember{at}{basic_stacktrace}% +\begin{itemdecl} +const_reference at(size_type frame_no) const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{frames_[frame_no]}. + +\pnum +\throws +\tcode{out_of_range} if \tcode{frame_no >= size()}. +\end{itemdescr} + +\rSec3[stacktrace.basic.cmp]{Comparisons} + +\indexlibrarymember{operator==}{basic_stacktrace}% +\begin{itemdecl} +template +friend bool operator==(const basic_stacktrace& x, const basic_stacktrace& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{equal(x.begin(), x.end(), y.begin(), y.end())}. +\end{itemdescr} + +\indexlibrarymember{operator<=>}{basic_stacktrace}% +\begin{itemdecl} +template +friend strong_ordering + operator<=>(const basic_stacktrace& x, const basic_stacktrace& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{x.size() <=> y.size()} if \tcode{x.size() != y.size()}; +\tcode{lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end())} +otherwise. +\end{itemdescr} + +\rSec3[stacktrace.basic.mod]{Modifiers} + +\indexlibrarymember{swap}{basic_stacktrace}% +\begin{itemdecl} +void swap(basic_stacktrace& other) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Exchanges the contents of \tcode{*this} and \tcode{other}. +\end{itemdescr} + +\rSec3[stacktrace.basic.nonmem]{Non-member functions} + +\indexlibrarymember{swap}{basic_stacktrace}% +\begin{itemdecl} +template +void swap(basic_stacktrace& a, basic_stacktrace& b) + noexcept(noexcept(a.swap(b))); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{a.swap(b)}. +\end{itemdescr} + +\indexlibrarymember{to_string}{basic_stacktrace}% +\begin{itemdecl} +string to_string(const stacktrace_entry& f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A string with a description of \tcode{f}. + +\recommended +The description should provide information about the contained evaluation, +including information from +\tcode{f.source_file()} and \tcode{f.source_line()}. +\end{itemdescr} + +\indexlibrarymember{to_string}{basic_stacktrace}% +\begin{itemdecl} +template +string to_string(const basic_stacktrace& st); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A string with a description of \tcode{st}. +\begin{note} +The number of lines is not guaranteed to be equal to \tcode{st.size()}. +\end{note} +\end{itemdescr} + +\indexlibrarymember{operator<<}{stacktrace_entry}% +\begin{itemdecl} +template +basic_ostream& + operator<<(basic_ostream& os, const stacktrace_entry& f); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return os << to_string(f);} +\end{itemdescr} + +\indexlibrarymember{operator<<}{basic_stacktrace}% +\begin{itemdecl} +template +basic_ostream& + operator<<(basic_ostream& os, const basic_stacktrace& st); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return os << to_string(st);} +\end{itemdescr} + +\rSec3[stacktrace.basic.hash]{Hash support} + +\begin{itemdecl} +template<> struct hash; +template struct hash>; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The specializations are enabled\iref{unord.hash}. +\end{itemdescr} diff --git a/source/utilities.tex b/source/utilities.tex index cffdb676f8..703d28592b 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -22674,723 +22674,3 @@ \ensures \tcode{strcmp(what(), what_arg) == 0}. \end{itemdescr} - -\rSec1[stacktrace]{Stacktrace} - -\rSec2[stacktrace.general]{General} - -\pnum -Subclause \ref{stacktrace} describes components -that \Cpp{} programs may use to store -the stacktrace of the current thread of execution and -query information about the stored stacktrace at runtime. - -\pnum -The \defn{invocation sequence} of the current evaluation $x_0$ -in the current thread of execution -is a sequence $(x_0, \ldots, x_n)$ of evaluations such that, for $i \geq 0$, -$x_i$ is within the function invocation $x_{i+1}$\iref{intro.execution}. - -\pnum -A \defn{stacktrace} is an approximate representation of -an invocation sequence and consists of stacktrace entries. -A \defn{stacktrace entry} represents an evaluation in a stacktrace. - -\rSec2[stacktrace.syn]{Header \tcode{} synopsis} - -\indexheader{stacktrace}% -\begin{codeblock} -namespace std { - // \ref{stacktrace.entry}, class \tcode{stacktrace_entry} - class stacktrace_entry; - - // \ref{stacktrace.basic}, class template \tcode{basic_stacktrace} - template - class basic_stacktrace; - - // \tcode{basic_stacktrace} \grammarterm{typedef-name}s - using stacktrace = basic_stacktrace>; - - // \ref{stacktrace.basic.nonmem}, non-member functions - template - void swap(basic_stacktrace& a, basic_stacktrace& b) - noexcept(noexcept(a.swap(b))); - - string to_string(const stacktrace_entry& f); - - template - string to_string(const basic_stacktrace& st); - - template - basic_ostream& - operator<<(basic_ostream& os, const stacktrace_entry& f); - - template - basic_ostream& - operator<<(basic_ostream& os, const basic_stacktrace& st); - - namespace pmr { - using stacktrace = basic_stacktrace>; - } - - // \ref{stacktrace.basic.hash}, hash support - template struct hash; - template<> struct hash; - template struct hash>; -} -\end{codeblock} - -\rSec2[stacktrace.entry]{Class \tcode{stacktrace_entry}} - -\rSec3[stacktrace.entry.overview]{Overview} - -\begin{codeblock} -namespace std { - class @\libglobal{stacktrace_entry}@ { - public: - using native_handle_type = @\impdefx{\tcode{stacktrace_entry::native_handle_type}}@; - - // \ref{stacktrace.entry.ctor}, constructors - constexpr stacktrace_entry() noexcept; - constexpr stacktrace_entry(const stacktrace_entry& other) noexcept; - constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept; - - ~stacktrace_entry(); - - // \ref{stacktrace.entry.obs}, observers - constexpr native_handle_type native_handle() const noexcept; - constexpr explicit operator bool() const noexcept; - - // \ref{stacktrace.entry.query}, query - string description() const; - string source_file() const; - uint_least32_t source_line() const; - - // \ref{stacktrace.entry.cmp}, comparison - friend constexpr bool operator==(const stacktrace_entry& x, - const stacktrace_entry& y) noexcept; - friend constexpr strong_ordering operator<=>(const stacktrace_entry& x, - const stacktrace_entry& y) noexcept; - }; -} -\end{codeblock} - -\pnum -An object of type \tcode{stacktrace_entry} is either empty, -or represents a stacktrace entry and -provides operations for querying information about it. -The class \tcode{stacktrace_entry} models -\libconcept{regular}\iref{concepts.object} and -\tcode{\libconcept{three_way_comparable}}\iref{cmp.concept}. - -\rSec3[stacktrace.entry.ctor]{Constructors} - -\indexlibraryctor{stacktrace_entry}% -\begin{itemdecl} -constexpr stacktrace_entry() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{*this} is empty. -\end{itemdescr} - -\rSec3[stacktrace.entry.obs]{Observers} - -\indexlibrarymember{native_handle}{stacktrace_entry}% -\begin{itemdecl} -constexpr native_handle_type native_handle() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The semantics of this function are -\impldef{semantics of \tcode{stacktrace_entry::native_handle}}. - -\pnum -\remarks -Successive invocations of the \tcode{native_handle} function -for an unchanged \tcode{stacktrace_entry} object return identical values. -\end{itemdescr} - -\indexlibrarymember{operator bool}{stacktrace_entry}% -\begin{itemdecl} -constexpr explicit operator bool() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{false} if and only if \tcode{*this} is empty. -\end{itemdescr} - -\rSec3[stacktrace.entry.query]{Query} - -\pnum -\begin{note} -All the \tcode{stacktrace_entry} query functions treat -errors other than memory allocation errors -as ``no information available'' and do not throw in that case. -\end{note} - -\indexlibrarymember{description}{stacktrace_entry}% -\begin{itemdecl} -string description() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A description of the evaluation represented by \tcode{*this}, -or an empty string. - -\pnum -\throws -\tcode{bad_alloc} if memory for -the internal data structures or the resulting string cannot be allocated. -\end{itemdescr} - -\indexlibrarymember{source_file}{stacktrace_entry}% -\begin{itemdecl} -string source_file() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The presumed or actual name of the source file\iref{cpp.predefined} -that lexically contains the expression or statement -whose evaluation is represented by \tcode{*this}, or an empty string. - -\pnum -\throws -\tcode{bad_alloc} if memory for -the internal data structures or the resulting string cannot be allocated. -\end{itemdescr} - -\indexlibrarymember{source_line}{stacktrace_entry}% -\begin{itemdecl} -uint_least32_t source_line() const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{0}, or a 1-based line number that lexically relates to the evaluation -represented by \tcode{*this}. -If \tcode{source_file} returns the presumed name of the source file, -returns the presumed line number; -if \tcode{source_file} returns the actual name of the source file, -returns the actual line number. - -\pnum -\throws -\tcode{bad_alloc} if memory for -the internal data structures cannot be allocated. -\end{itemdescr} - -\rSec3[stacktrace.entry.cmp]{Comparison} - -\indexlibrarymember{operator==}{stacktrace_entry}% -\begin{itemdecl} -friend constexpr bool operator==(const stacktrace_entry& x, const stacktrace_entry& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{true} if and only if \tcode{x} and \tcode{y} represent -the same stacktrace entry or both \tcode{x} and \tcode{y} are empty. -\end{itemdescr} - -\rSec2[stacktrace.basic]{Class template \tcode{basic_stacktrace}} - -\rSec3[stacktrace.basic.overview]{Overview} - -\begin{codeblock} -namespace std { - template - class @\libglobal{basic_stacktrace}@ { - public: - using value_type = stacktrace_entry; - using const_reference = const value_type&; - using reference = value_type&; - using const_iterator = @\impdefx{type of \tcode{basic_stacktrace::const_iterator}}@; // see \ref{stacktrace.basic.obs} - using iterator = const_iterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using difference_type = @\impdefx{type of \tcode{basic_stacktrace::difference_type}}@; - using size_type = @\impdefx{type of \tcode{basic_stacktrace::size_type}}@; - using allocator_type = Allocator; - - // \ref{stacktrace.basic.ctor}, creation and assignment - static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; - static basic_stacktrace current(size_type skip, - const allocator_type& alloc = allocator_type()) noexcept; - static basic_stacktrace current(size_type skip, size_type max_depth, - const allocator_type& alloc = allocator_type()) noexcept; - - basic_stacktrace() noexcept(is_nothrow_default_constructible_v); - explicit basic_stacktrace(const allocator_type& alloc) noexcept; - - basic_stacktrace(const basic_stacktrace& other); - basic_stacktrace(basic_stacktrace&& other) noexcept; - basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc); - basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc); - basic_stacktrace& operator=(const basic_stacktrace& other); - basic_stacktrace& operator=(basic_stacktrace&& other) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); - - ~basic_stacktrace(); - - // \ref{stacktrace.basic.obs}, observers - allocator_type get_allocator() const noexcept; - - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - const_reverse_iterator rbegin() const noexcept; - const_reverse_iterator rend() const noexcept; - - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - const_reverse_iterator crbegin() const noexcept; - const_reverse_iterator crend() const noexcept; - - [[nodiscard]] bool empty() const noexcept; - size_type size() const noexcept; - size_type max_size() const noexcept; - - const_reference operator[](size_type) const; - const_reference at(size_type) const; - - // \ref{stacktrace.basic.cmp}, comparisons - template - friend bool operator==(const basic_stacktrace& x, - const basic_stacktrace& y) noexcept; - template - friend strong_ordering operator<=>(const basic_stacktrace& x, - const basic_stacktrace& y) noexcept; - - // \ref{stacktrace.basic.mod}, modifiers - void swap(basic_stacktrace& other) - noexcept(allocator_traits::propagate_on_container_swap::value || - allocator_traits::is_always_equal::value); - - private: - vector frames_; // \expos - }; -} -\end{codeblock} - -\pnum -The class template \tcode{basic_stacktrace} satisfies -the requirements of -an allocator-aware container (\tref{container.alloc.req}), -a sequence container\iref{sequence.reqmts}, and -a reversible container\iref{container.requirements.general} -except that -\begin{itemize} -\item -only move, assignment, swap, and -operations defined for const-qualified sequence containers are supported and, -\item -the semantics of comparison functions -are different from those required for a container. -\end{itemize} - -\rSec3[stacktrace.basic.ctor]{Creation and assignment} - -\indexlibrarymember{current}{basic_stacktrace}% -\begin{itemdecl} -static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A \tcode{basic_stacktrace} object -with \tcode{frames_} storing -the stacktrace of the current evaluation in the current thread of execution, or -an empty \tcode{basic_stacktrace} object -if the initialization of \tcode{frames_} failed. -\tcode{alloc} is passed to the constructor of the \tcode{frames_} object. - -\begin{note} -If the stacktrace was successfully obtained, -then \tcode{frames_.front()} is the \tcode{stacktrace_entry} -representing approximately the current evaluation, and -\tcode{frames_.back()} is the \tcode{stacktrace_entry} -representing approximately the initial function of -the current thread of execution. -\end{note} -\end{itemdescr} - -\indexlibrarymember{current}{basic_stacktrace}% -\begin{itemdecl} -static basic_stacktrace current(size_type skip, - const allocator_type& alloc = allocator_type()) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{t} be a stacktrace -as-if obtained via \tcode{basic_stacktrace::current(alloc)}. -Let \tcode{n} be \tcode{t.size()}. - -\pnum -\returns -A \tcode{basic_stacktrace} object -where \tcode{frames_} is direct-non-list-initialized from arguments -\tcode{t.begin() + min(n, skip)}, \tcode{t.end()}, and \tcode{alloc}, -or an empty \tcode{basic_stacktrace} object -if the initialization of \tcode{frames_} failed. -\end{itemdescr} - -\indexlibrarymember{current}{basic_stacktrace}% -\begin{itemdecl} -static basic_stacktrace current(size_type skip, size_type max_depth, - const allocator_type& alloc = allocator_type()) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -Let \tcode{t} be a stacktrace -as-if obtained via \tcode{basic_stacktrace::current(alloc)}. -Let \tcode{n} be \tcode{t.size()}. - -\pnum -\expects -\tcode{skip <= skip + max_depth} is \tcode{true}. - -\pnum -\returns -A \tcode{basic_stacktrace} object -where \tcode{frames_} is direct-non-list-initialized from arguments -\tcode{t.begin() + min(n, skip)}, \tcode{t.begin() + min(n, skip + max_depth)}, -and \tcode{alloc}, -or an empty \tcode{basic_stacktrace} object -if the initialization of \tcode{frames_} failed. -\end{itemdescr} - -\indexlibraryctor{basic_stacktrace}% -\begin{itemdecl} -basic_stacktrace() noexcept(is_nothrow_default_constructible_v); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\ensures -\tcode{empty()} is \tcode{true}. -\end{itemdescr} - -\indexlibraryctor{basic_stacktrace}% -\begin{itemdecl} -explicit basic_stacktrace(const allocator_type& alloc) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -\tcode{alloc} is passed to the \tcode{frames_} constructor. - -\pnum -\ensures -\tcode{empty()} is \tcode{true}. -\end{itemdescr} - -\indexlibraryctor{basic_stacktrace}% -\indexlibrarymember{operator=}{basic_stacktrace}% -\begin{itemdecl} -basic_stacktrace(const basic_stacktrace& other); -basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc); -basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc); -basic_stacktrace& operator=(const basic_stacktrace& other); -basic_stacktrace& operator=(basic_stacktrace&& other) - noexcept(allocator_traits::propagate_on_container_move_assignment::value || - allocator_traits::is_always_equal::value); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\remarks -Implementations may strengthen the exception specification -for these functions\iref{res.on.exception.handling} -by ensuring that \tcode{empty()} is \tcode{true} on failed allocation. -\end{itemdescr} - -\rSec3[stacktrace.basic.obs]{Observers} - -\indexlibrarymember{const_iterator}{basic_stacktrace}% -\begin{itemdecl} -using const_iterator = @\impdef@; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The type models -\libconcept{random_access_iterator}\iref{iterator.concept.random.access} and -meets the -\oldconcept{RandomAccessIterator} requirements\iref{random.access.iterators}. -\end{itemdescr} - -\indexlibrarymember{get_allocator}{basic_stacktrace}% -\begin{itemdecl} -allocator_type get_allocator() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{frames_.get_allocator()}. -\end{itemdescr} - -\indexlibrarymember{begin}{basic_stacktrace}% -\indexlibrarymember{cbegin}{basic_stacktrace}% -\begin{itemdecl} -const_iterator begin() const noexcept; -const_iterator cbegin() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -An iterator referring to the first element in \tcode{frames_}. -If \tcode{empty()} is \tcode{true}, -then it returns the same value as \tcode{end()}. -\end{itemdescr} - -\indexlibrarymember{end}{basic_stacktrace}% -\indexlibrarymember{cend}{basic_stacktrace}% -\begin{itemdecl} -const_iterator end() const noexcept; -const_iterator cend() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -The end iterator. -\end{itemdescr} - -\indexlibrarymember{rbegin}{basic_stacktrace}% -\indexlibrarymember{crbegin}{basic_stacktrace}% -\begin{itemdecl} -const_reverse_iterator rbegin() const noexcept; -const_reverse_iterator crbegin() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{reverse_iterator(cend())}. -\end{itemdescr} - -\indexlibrarymember{rend}{basic_stacktrace}% -\indexlibrarymember{crend}{basic_stacktrace}% -\begin{itemdecl} -const_reverse_iterator rend() const noexcept; -const_reverse_iterator crend() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{reverse_iterator(cbegin())}. -\end{itemdescr} - -\indexlibrarymember{empty}{basic_stacktrace}% -\begin{itemdecl} -[[nodiscard]] bool empty() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{frames_.empty()}. -\end{itemdescr} - -\indexlibrarymember{size}{basic_stacktrace}% -\begin{itemdecl} -size_type size() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{frames_.size()}. -\end{itemdescr} - -\indexlibrarymember{max_size}{basic_stacktrace}% -\begin{itemdecl} -size_type max_size() const noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{frames_.max_size()}. -\end{itemdescr} - -\indexlibrarymember{operator[]}{basic_stacktrace}% -\begin{itemdecl} -const_reference operator[](size_type frame_no) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{frame_no < size()} is \tcode{true}. - -\pnum -\returns -\tcode{frames_[frame_no]}. - -\pnum -\throws -Nothing. -\end{itemdescr} - -\indexlibrarymember{at}{basic_stacktrace}% -\begin{itemdecl} -const_reference at(size_type frame_no) const; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{frames_[frame_no]}. - -\pnum -\throws -\tcode{out_of_range} if \tcode{frame_no >= size()}. -\end{itemdescr} - -\rSec3[stacktrace.basic.cmp]{Comparisons} - -\indexlibrarymember{operator==}{basic_stacktrace}% -\begin{itemdecl} -template -friend bool operator==(const basic_stacktrace& x, const basic_stacktrace& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{equal(x.begin(), x.end(), y.begin(), y.end())}. -\end{itemdescr} - -\indexlibrarymember{operator<=>}{basic_stacktrace}% -\begin{itemdecl} -template -friend strong_ordering - operator<=>(const basic_stacktrace& x, const basic_stacktrace& y) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -\tcode{x.size() <=> y.size()} if \tcode{x.size() != y.size()}; -\tcode{lexicographical_compare_three_way(x.begin(), x.end(), y.begin(), y.end())} -otherwise. -\end{itemdescr} - -\rSec3[stacktrace.basic.mod]{Modifiers} - -\indexlibrarymember{swap}{basic_stacktrace}% -\begin{itemdecl} -void swap(basic_stacktrace& other) - noexcept(allocator_traits::propagate_on_container_swap::value || - allocator_traits::is_always_equal::value); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Exchanges the contents of \tcode{*this} and \tcode{other}. -\end{itemdescr} - -\rSec3[stacktrace.basic.nonmem]{Non-member functions} - -\indexlibrarymember{swap}{basic_stacktrace}% -\begin{itemdecl} -template -void swap(basic_stacktrace& a, basic_stacktrace& b) - noexcept(noexcept(a.swap(b))); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to \tcode{a.swap(b)}. -\end{itemdescr} - -\indexlibrarymember{to_string}{basic_stacktrace}% -\begin{itemdecl} -string to_string(const stacktrace_entry& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A string with a description of \tcode{f}. - -\recommended -The description should provide information about the contained evaluation, -including information from -\tcode{f.source_file()} and \tcode{f.source_line()}. -\end{itemdescr} - -\indexlibrarymember{to_string}{basic_stacktrace}% -\begin{itemdecl} -template -string to_string(const basic_stacktrace& st); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\returns -A string with a description of \tcode{st}. -\begin{note} -The number of lines is not guaranteed to be equal to \tcode{st.size()}. -\end{note} -\end{itemdescr} - -\indexlibrarymember{operator<<}{stacktrace_entry}% -\begin{itemdecl} -template -basic_ostream& - operator<<(basic_ostream& os, const stacktrace_entry& f); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return os << to_string(f);} -\end{itemdescr} - -\indexlibrarymember{operator<<}{basic_stacktrace}% -\begin{itemdecl} -template -basic_ostream& - operator<<(basic_ostream& os, const basic_stacktrace& st); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: \tcode{return os << to_string(st);} -\end{itemdescr} - -\rSec3[stacktrace.basic.hash]{Hash support} - -\begin{itemdecl} -template<> struct hash; -template struct hash>; -\end{itemdecl} - -\begin{itemdescr} -\pnum -The specializations are enabled\iref{unord.hash}. -\end{itemdescr}