Line data Source code
1 : /** \file exception.hpp
2 : * \brief The mxlib exception class.
3 : * \ingroup error_handling_files
4 : *
5 : */
6 :
7 : //***********************************************************************//
8 : // Copyright 2025 Jared R. Males (jaredmales@gmail.com)
9 : //
10 : // This file is part of mxlib.
11 : //
12 : // mxlib is free software: you can redistribute it and/or modify
13 : // it under the terms of the GNU General Public License as published by
14 : // the Free Software Foundation, either version 3 of the License, or
15 : // (at your option) any later version.
16 : //
17 : // mxlib is distributed in the hope that it will be useful,
18 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : // GNU General Public License for more details.
21 : //
22 : // You should have received a copy of the GNU General Public License
23 : // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
24 : //***********************************************************************//
25 :
26 : #ifndef error_exception_hpp
27 : #define error_exception_hpp
28 :
29 : #include <vector>
30 :
31 : #include "error.hpp"
32 :
33 : namespace mx
34 : {
35 :
36 : /// Augments an exception with the source file and line
37 : /**
38 : * \tparam baseexcept is the base class exception which takes a string as constructor argument
39 : */
40 : template <class verboseT = verbose::d>
41 : class exception : public std::exception
42 : {
43 : protected:
44 : std::string m_what; ///< The full what message (message + file information).
45 :
46 : error_t m_code{ error_t::exception }; ///< The error_t code
47 :
48 : std::string m_message; ///< The explanatory message
49 :
50 : std::source_location m_location;
51 :
52 : public:
53 : /// Constructor with location only.
54 : /**
55 : */
56 0 : explicit exception( const std::source_location loc = /**< [in] [opt] the location where this was thrown*/
57 : std::source_location::current() )
58 0 : : m_location{ loc }
59 : {
60 0 : m_what = error_message<verboseT>( m_code, m_location );
61 0 : }
62 :
63 : /// Constructor with message.
64 : /**
65 : */
66 : explicit exception( const std::string &msg, /**< [in] the error description message) */
67 : const std::source_location loc = /**< [in] [opt] the location where this was thrown*/
68 : std::source_location::current() )
69 : : m_message{ msg }, m_location{ loc }
70 : {
71 : m_what = error_message<verboseT>( m_code, m_message, m_location );
72 : }
73 :
74 : /// Constructor with message and cod
75 : /**
76 : */
77 0 : exception( error_t code, /**< [in] a descriptive error code */
78 : const std::string &msg, /**< [in] the error description (what message) */
79 : const std::source_location loc = /**< [in] [opt] the location where this was thrown*/
80 : std::source_location::current() )
81 0 : : m_code{ code }, m_message{ msg }, m_location{ loc }
82 : {
83 0 : m_what = error_message<verboseT>( m_code, m_message, m_location );
84 0 : }
85 :
86 : /// Constructor with code
87 : /** The message is filled in using \ref errorMessage.
88 : *
89 : * The what() message becomes "code_message (code) [file line]".
90 : */
91 0 : exception( error_t code, /**< [in] a descriptive error code */
92 : const std::source_location loc = /**< [in] [opt] the location where this was thrown*/
93 : std::source_location::current() )
94 0 : : m_code{ code }, m_location{ loc }
95 : {
96 0 : m_what = error_message<verboseT>( m_code, m_location );
97 0 : }
98 :
99 : /// Get the what string
100 : /** \returns the value of m_what.c_str()
101 : *
102 : */
103 0 : virtual const char *what() const noexcept
104 : {
105 0 : return m_what.c_str();
106 : }
107 :
108 : /// Get the message
109 : /** \returns the value of m_message
110 : *
111 : */
112 : const std::string &message() const
113 : {
114 : return m_message;
115 : }
116 :
117 : /// Get the source file
118 : /** \returns the value of m_location.file_name()
119 : *
120 : */
121 : const std::string file_name() const
122 : {
123 : return m_location.file_name();
124 : }
125 :
126 : /// Get the source line
127 : /** \returns the value of m_location.line()
128 : *
129 : */
130 : int line() const
131 : {
132 : return m_location.line();
133 : }
134 :
135 : /// Get the error code
136 : /** \returns the value of m_code
137 : *
138 : */
139 0 : error_t code() const
140 : {
141 0 : return m_code;
142 : }
143 : };
144 :
145 : /// Extract the explanatory string of nested exceptions, placing them in a vector.
146 : /** If the exception is nested, this recurses to extract the explanatory string of the
147 : * next exception it holds.
148 : */
149 : inline
150 : void unwind_exceptions( std::vector<std::string> &whats, /**< [out] the vector of what messages*/
151 : const std::exception &e /**< [in] the exception */
152 : )
153 : {
154 : whats.push_back( e.what() );
155 :
156 : try
157 : {
158 : std::rethrow_if_nested( e );
159 : }
160 : catch( const std::exception &nestedException )
161 : {
162 : unwind_exceptions( whats, nestedException );
163 : }
164 : catch( ... )
165 : {
166 : }
167 : }
168 :
169 : /// Print nested exceptions to stderr, from the earliest to latest
170 : /** Formats in a ladder
171 : *
172 : */
173 : inline
174 : void print_exceptions( std::vector<std::string> &whats, /**< [out] a vector of what messages*/
175 : const std::string &message = /**< [in] [optional] the top message to print */
176 : "exception(s) thrown" )
177 : {
178 : std::cerr << message << ":\n";
179 : std::cerr << " " << whats.back() << '\n';
180 : for( size_t n = 1; n < whats.size(); ++n )
181 : {
182 : std::cerr << std::string( 2, ' ' ) << std::string( ( n - 1 ) * 4, ' ' ) << "|-->" << whats[whats.size() - 1 - n]
183 : << '\n';
184 : }
185 : }
186 :
187 : } // namespace mx
188 :
189 : #endif // error_exception_hpp
|