PVData C++  8.0.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
epicsException.h
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 /*
6  * epicsException.h
7  *
8  * Created on: Oct 20, 2010
9  * Author: Matej Sekoranja
10  */
11 
12 /*
13  * Throwing exceptions w/ file+line# and, when possibly, a stack trace
14  *
15  * THROW_EXCEPTION1( std::bad_alloc );
16  *
17  * THROW_EXCEPTION2( std::logic_error, "my message" );
18  *
19  * THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
20  *
21  * Catching exceptions
22  *
23  * catch(std::logic_error& e) {
24  * fprintf(stderr, "%s happened\n", e.what());
25  * PRINT_EXCEPTION2(e, stderr);
26  * cout<<SHOW_EXCEPTION(e);
27  * }
28  *
29  * If the exception was not thrown with the above THROW_EXCEPTION*
30  * the nothing will be printed.
31  */
32 
33 #ifndef EPICSEXCEPTION_H_
34 #define EPICSEXCEPTION_H_
35 
36 #include <stdexcept>
37 #include <string>
38 #include <cstdio>
39 
40 #include <shareLib.h>
41 
42 // Users may redefine this for a large size if desired
43 #ifndef EXCEPT_DEPTH
44 # define EXCEPT_DEPTH 20
45 #endif
46 
47 #if defined(__GLIBC__) || (defined(__APPLE__) && defined(__MACH__)) /* and possibly some BSDs */
48 # include <execinfo.h>
49 # include <cxxabi.h>
50 # define EXCEPT_USE_BACKTRACE
51 #elif defined(_WIN32) && !defined(_MINGW) && !defined(SKIP_DBGHELP)
52 # define _WINSOCKAPI_
53 # include <windows.h>
54 # include <dbghelp.h>
55 # define EXCEPT_USE_CAPTURE
56 #else
57 # define EXCEPT_USE_NONE
58 #endif
59 
60 #if defined(_WIN32) && !defined(_MINGW)
61 #pragma warning( push )
62 #pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class (std::logic_error)
63 #pragma warning(disable: 4251) // class std::string needs to have dll-interface to be used by clients
64 #endif
65 
66 namespace epics { namespace pvData {
67 
68 
69 /* Stores file and line number given, and when possible the call stack
70  * at the point where it was constructed
71  */
72 class epicsShareClass ExceptionMixin {
73  const char *m_file;
74  int m_line;
75 #ifndef EXCEPT_USE_NONE
76  void *m_stack[EXCEPT_DEPTH];
77  int m_depth; // always <= EXCEPT_DEPTH
78 #endif
79 public:
80  // allow the ctor to be inlined if possible
81  ExceptionMixin(const char* file, int line)
82  :m_file(file)
83  ,m_line(line)
84 #if defined(EXCEPT_USE_BACKTRACE)
85  {
86  m_depth=backtrace(m_stack,EXCEPT_DEPTH);
87  }
88 #elif defined(EXCEPT_USE_CAPTURE)
89  {
90  m_depth=CaptureStackBackTrace(0,EXCEPT_DEPTH,m_stack,0);
91  }
92 #else
93  {}
94 #endif
95 
96  void print(FILE *fp=stderr) const;
97 
98  std::string show() const;
99 };
100 
101 #ifndef THROW_EXCEPTION_COMPAT
102 
103 namespace detail {
104  /* Combines user exception type with Mixin
105  *
106  * Takes advantage of the requirement that all exception classes
107  * must be copy constructable. Of course this also requires
108  * that an extra copy be constructed...
109  */
110  template<typename E>
111  class ExceptionMixed : public E, public ExceptionMixin {
112  public:
113  // construct from copy of E
114  ExceptionMixed(const E& self,const char* file, int line)
115  :E(self), ExceptionMixin(file,line)
116  {}
117  // construct for E w/o arguments
118  ExceptionMixed(const char* file, int line)
119  :E(), ExceptionMixin(file,line)
120  {}
121  // construct for E one argument
122  template<typename A1>
123  ExceptionMixed(A1 arg1,const char* file, int line)
124  :E(arg1), ExceptionMixin(file,line)
125  {}
126  // construct for E two arguments
127  template<typename A1, typename A2>
128  ExceptionMixed(A1 arg1, A2 arg2,const char* file, int line)
129  :E(arg1,arg2), ExceptionMixin(file,line)
130  {}
131  };
132 
133  // function template to deduce E from argument
134  template<typename E>
135  static inline
137  makeException(const E& self,const char* file, int line)
138  {
139  return ExceptionMixed<E>(self,file,line);
140  }
141 
142  template<typename E>
143  static inline
145  showException(const E& ex)
146  {
147  const ExceptionMixin *mx=dynamic_cast<const ExceptionMixin*>(&ex);
148  if(!mx) return std::string();
149  return mx->show();
150  }
151 }
152 
153 // Throw an exception of a mixed sub-class of the type of E
154 // The instance E is copied and discarded
155 #define THROW_EXCEPTION(E) \
156 do { \
157  throw ::epics::pvData::detail::makeException(E, __FILE__, __LINE__); \
158 } while(0)
159 
160 // Throw an exception of a mixed sub-class of E, passing MSG as an argument
161 #define THROW_EXCEPTION1(TYPE) \
162 do { \
163  throw ::epics::pvData::detail::ExceptionMixed<TYPE>(__FILE__, __LINE__); \
164  }while(0)
165 
166 // Throw an exception of a mixed sub-class of E, passing MSG as an argument
167 #define THROW_EXCEPTION2(TYPE,MSG) \
168 do { \
169  throw ::epics::pvData::detail::ExceptionMixed<TYPE>(MSG, __FILE__, __LINE__); \
170 }while(0)
171 
172 #define PRINT_EXCEPTION2(EI, FP) \
173 do { \
174  ::epics::pvData::ExceptionMixin *_em_p=dynamic_cast< ::epics::pvData::ExceptionMixin*>(&EI); \
175  if (_em_p) {_em_p->print(FP);} \
176 }while(0)
177 
178 #define PRINT_EXCEPTION(EI) PRINT_EXCEPTION2(EI,stderr)
179 
180 #if !defined(__GNUC__) || __GNUC__ < 4
181 # define SHOW_EXCEPTION(EI) ::epics::pvData::detail::showException(EI)
182 #else
183 # define SHOW_EXCEPTION(EI) \
184  ({ ::epics::pvData::ExceptionMixin *_mx=dynamic_cast< ::epics::pvData::ExceptionMixin*>(&(EI)); \
185  _mx ? _mx->show() : std::string(); \
186  })
187 #endif
188 
189 #else // THROW_EXCEPTION_COMPAT
190 /* For older compilers which have a problem with the above */
191 
192 #define PRINT_EXCEPTION(EI) do{}while(0)
193 #define PRINT_EXCEPTION2(EI,FP) do{}while(0)
194 #define SHOW_EXCEPTION(EI) std::string()
195 
196 #define THROW_EXCEPTION(E) do{throw (E);}while(0)
197 #define THROW_EXCEPTION1(E) do{throw (E)();}while(0)
198 #define THROW_EXCEPTION2(E,A) do{throw (E)(A);}while(0)
199 
200 #endif // THROW_EXCEPTION_COMPAT
201 
205 class epicsShareClass BaseException : public std::logic_error {
206 public:
210  explicit BaseException(const std::string& msg) : std::logic_error(msg) {}
211 
215  virtual ~BaseException() throw(){};
216 
221  virtual const char* what() const throw();
222 
223 private:
224  mutable std::string base_msg;
225 };
226 
227 #if defined(_WIN32) && !defined(_MINGW)
228 #pragma warning( pop )
229 #endif
230 
231 #define THROW_BASE_EXCEPTION(msg) THROW_EXCEPTION2(::epics::pvData::BaseException, msg)
232 
233  }
234 }
235 
236 
237 #endif /* EPICSEXCEPTION_H_ */
Base for pvData exceptions.
basic_string< char > string
BaseException(const std::string &msg)