Line data Source code
1 : // *****************************************************************************
2 : /*!
3 : \file src/Base/Exception.hpp
4 : \copyright 2012-2015 J. Bakosi,
5 : 2016-2018 Los Alamos National Security, LLC.,
6 : 2019-2021 Triad National Security, LLC.,
7 : 2022-2025 J. Bakosi
8 : All rights reserved. See the LICENSE file for details.
9 : \brief Exception class declaration
10 : \details Exception class declaration. The basic functionality provided by
11 : the Exception class is to facilitate printing out a message, together with
12 : the location of the exception (file, line, function name), as well as a call
13 : trace if available, when an exception is thrown. This file also defines
14 : three macros, Throw, Assert, and ErrChk, that help simplifying client code
15 : throwing exceptions.
16 : */
17 : // *****************************************************************************
18 : #ifndef Exception_h
19 : #define Exception_h
20 :
21 : #include <exception>
22 : #include <string>
23 :
24 : //! Toolkit declarations and definitions for general purpose utilities
25 : namespace tk {
26 :
27 : #ifdef NDEBUG // asserts disabled
28 : static constexpr bool ndebug = true;
29 : #else // asserts enabled
30 : static constexpr bool ndebug = false;
31 : #endif
32 :
33 : //! \brief Throw macro that always throws an exception
34 : //! \details Throw Exception with arguments passed in. Add source filename,
35 : //! function name, and line number where exception occurred. This macro
36 : //! facilitates a throw of Exception that is somewhat cleaner at the point
37 : //! of invocation than a direct throw of Exception, as it hides the
38 : //! file:func:line arguments. Whenever is possible, it should be used via the
39 : //! Assert and ErrChk macros defined below.
40 : #define Throw(...) \
41 : throw tk::Exception(__VA_ARGS__, __FILE__, __PRETTY_FUNCTION__, __LINE__)
42 :
43 : //! \brief Assert macro that only throws an exception if expr fails.
44 : //! \details If NDEBUG is defined (e.g. cmake's RELEASE or OPTIMIZED mode), do
45 : //! nothing, expr is not evaluated. If NDEBUG is not defined, evaluate expr.
46 : //! If expr is true, do nothing. If expr is false, throw Exception with
47 : //! arguments passed in. The behavior is similar to libc's assert macro, but
48 : //! throwing an Exception instead will also generate a nice call-trace and
49 : //! will attempt to free memory. This macro should be used to detect
50 : //! programmer errors.
51 : #ifdef NDEBUG
52 : # define Assert(expr, ...) (static_cast<void>(0))
53 : #else // NDEBUG
54 : # define Assert(expr, ...) \
55 : ((expr) ? static_cast<void>(0) : Throw(__VA_ARGS__))
56 : #endif // NDEBUG
57 :
58 : //! \brief ErrChk macro that only throws an exception if expr fails.
59 : //! \details The behavior of this macro is the same whether NDEBUG is defined or
60 : //! not: expr is always evaluated. If expr is true, do nothing. If expr is
61 : //! false, throw Exception with arguments passed in. This macro should be
62 : //! used to detect user or runtime errors.
63 : #define ErrChk(expr, ...) \
64 : ((expr) ? static_cast<void>(0) : Throw(__VA_ARGS__))
65 :
66 : //! Error codes for the OS (or whatever calls us)
67 : enum ErrCode { SUCCESS = EXIT_SUCCESS, //!< Everything went fine
68 : FAILURE = EXIT_FAILURE //!< Exceptions occurred
69 : };
70 :
71 : //! \brief Basic exception class for producing file:func:line info + call trace
72 : //! \details The basic functionality provided by the Exception class is to
73 : //! facilitate printing out a message, together with the location of the
74 : //! exception (file, line, function name), as well as a call trace if
75 : //! available, when an exception is thrown.
76 : class Exception : public std::exception {
77 :
78 : public:
79 : //! Constructor
80 : explicit Exception( std::string&& message,
81 : std::string&& file = "",
82 : std::string&& function = "",
83 : unsigned int line = 0 ) noexcept;
84 :
85 : //! Destructor
86 : virtual ~Exception() noexcept override;
87 :
88 : //! Force move constructor for throws
89 : Exception(Exception&&) = default;
90 :
91 : //! Redefine std::exception's what()
92 : //! \return C-style string to exception message
93 17 : virtual const char* what() const noexcept override {
94 17 : return m_message.c_str();
95 : }
96 :
97 : //! Handle Exception
98 : virtual ErrCode handleException() noexcept;
99 :
100 : //! Accessor to function name
101 : //! \return Reference to function name in which the exception occurred
102 : const std::string& func() const noexcept { return m_func; }
103 :
104 : private:
105 : // Use move constructor by default
106 : //! Don't permit copy constructor
107 : Exception(const Exception&) = delete;
108 : //! Don't permit copy assignment
109 : Exception& operator=(const Exception&) = delete;
110 : //! Don't permit move assignment
111 : Exception& operator=(Exception&&) = delete;
112 :
113 : //! Save call trace
114 : void saveTrace() noexcept;
115 :
116 : //! Demangle and Echo call trace
117 : void echoTrace() noexcept;
118 :
119 : const std::string m_file; //!< Source file where exception is occurred
120 : const std::string m_func; //!< Function name where exception is occurred
121 : const unsigned int m_line; //!< Source line where exception is occurred
122 :
123 : std::string m_message; //!< Error message
124 : void* m_addrList[128]; //!< Call-stack before exception
125 : int m_addrLength; //!< Number of stack frames
126 : char** m_symbolList; //!< Symbol list of stack entries
127 : };
128 :
129 : } // tk::
130 :
131 : #endif // Exception_h
|