1 #ifndef NCBIEXPT__HPP
2 #define NCBIEXPT__HPP
3
4 /* $Id: ncbiexpt.hpp 605495 2020-04-11 04:31:07Z lavr $
5 * ===========================================================================
6 *
7 * PUBLIC DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Denis Vakatov
30 *
31 *
32 */
33
34 /// @file ncbiexpt.hpp
35 /// Defines NCBI C++ exception handling.
36 ///
37 /// Contains support for the NCBI C++ exception handling mechanisms and
38 /// auxiliary ad hoc macros to "catch" certain types of errors, and macros for
39 /// the C++ exception specification.
40
41
42 #include <corelib/ncbimisc.hpp>
43 #include <errno.h>
44 #include <string.h>
45 #include <typeinfo>
46
47 #ifdef NCBI_OS_MSWIN
48 # include <corelib/ncbi_os_mswin.hpp>
49 #endif
50
51 /** @addtogroup Exception
52 *
53 * @{
54 */
55
56
57 BEGIN_NCBI_SCOPE
58
59
60 /// Do not use 'throw' dynamic exception specification for C++11 compilers
61 #if defined(NCBI_USE_THROW_SPEC) && defined(NCBI_HAVE_CXX11)
62 # undef NCBI_USE_THROW_SPEC
63 #endif
64
65 /// Define THROWS macros for C++ exception specification.
66 ///
67 /// Define use of C++ exception specification mechanism:
68 /// "f(void) throw();" <== "f(void) THROWS_NONE;"
69 /// "g(void) throw(e1,e2);" <== "f(void) THROWS((e1,e2));"
70 #ifdef NCBI_USE_THROW_SPEC
71 # define THROWS_NONE throw()
72 # define THROWS(x) throw x
73 #else
74 # define THROWS_NONE
75 # define THROWS(x)
76 #endif
77
78
79 /// ABORT_ON_THROW controls if program should be aborted.
80 #define ABORT_ON_THROW "ABORT_ON_THROW"
81
82 /// Specify whether to call "abort()" inside the DoThrowTraceAbort().
83 ///
84 /// By default, this feature is not activated unless
85 /// - environment variable $ABORT_ON_THROW is set (to any value), or
86 /// - registry value of ABORT_ON_THROW, section DEBUG is set (to any value)
87 NCBI_XNCBI_EXPORT
88 extern void SetThrowTraceAbort(bool abort_on_throw_trace);
89
90 /// "abort()" the program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
91 NCBI_XNCBI_EXPORT
92 extern void DoThrowTraceAbort(void);
93
94 /// Print the specified debug message.
95 NCBI_XNCBI_EXPORT
96 extern void DoDbgPrint(const CDiagCompileInfo& info, const char* message);
97
98 /// Print the specified debug message.
99 NCBI_XNCBI_EXPORT
100 extern void DoDbgPrint(const CDiagCompileInfo& info, const string& message);
101
102 /// Print the specified debug messages.
103 NCBI_XNCBI_EXPORT
104 extern void DoDbgPrint(const CDiagCompileInfo& info,
105 const char* msg1, const char* msg2);
106
107 #if defined(_DEBUG)
108
109 /// Rethrow trace.
110 ///
111 /// Reason for do {...} while in macro definition is to permit a natural
112 /// syntax usage when a user wants to write something like:
113 ///
114 /// if (expression)
115 /// RETHROW_TRACE;
116 /// else do_something_else;
117 ///
118 /// Example:
119 /// - RETHROW_TRACE;
120 # define RETHROW_TRACE \
121 do { \
122 _TRACE("EXCEPTION: re-throw"); \
123 NCBI_NS_NCBI::DoThrowTraceAbort(); \
124 throw; \
125 } while(0)
126
127
128 /////////////////////////////////
129 // New style throw-trace macros.
130 //
131
132 BEGIN_NAMESPACE(ncbi_throw_trace);
133
134 // Helper class for detecting exceptions with what() method defined.
135 template<class T, class = T>
136 struct is_exception : false_type {};
137 template<class T>
138 struct is_exception<T, typename enable_if<
139 is_member_function_pointer<decltype(&T::what)>::value,
140 T>::type> : true_type {};
141
142 // Helper class for detecting classes with output operator defined.
143 template<class T>
144 struct has_no_output_operator_impl {
145 template<class V> static auto check(const V&) -> decltype(declval<ostream&>() << declval<V>());
146 template<typename> static bool check(...);
147 using type = typename is_same<bool, decltype(check<T>(declval<T>()))>::type;
148 };
149 template<class T>
150 struct has_no_output_operator : has_no_output_operator_impl<T>::type {};
151 template<class T, class = T>
152 struct has_output_operator : false_type {};
153 template<class T>
154 struct has_output_operator<T, typename enable_if<
155 !has_no_output_operator_impl<T>::type::value,
156 T>::type> : true_type {};
157
158 // Helper class for detecting printable non-exception classes.
159 template<class T, class = T>
160 struct is_printable : false_type {};
161 template<class T>
162 struct is_printable<T, typename enable_if<
163 !is_exception<T>::value &&
164 has_output_operator<T>::value,
165 T>::type> : true_type {};
166
167 // Helper class for detecting non-printable classes (no what() or output operator).
168 template<class T, class = T>
169 struct is_non_printable : false_type {};
170 template<class T>
171 struct is_non_printable<T, typename enable_if<
172 !is_exception<T>::value && !is_printable<T>::value,
173 T>::type> : true_type {};
174
175 END_NAMESPACE(ncbi_throw_trace);
176
177
178 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)179 typename enable_if<ncbi_throw_trace::is_exception<T>::value, const T&>::type DbgPrintEx(
180 const CDiagCompileInfo& info, const T& t, const char* str)
181 {
182 CNcbiDiag(info, eDiag_Trace) << str << ": " << t.what();
183 DoThrowTraceAbort();
184 return t;
185 }
186
187 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)188 typename enable_if<ncbi_throw_trace::is_printable<T>::value, const T&>::type DbgPrintEx(
189 const CDiagCompileInfo& info, const T& t, const char* str)
190 {
191 CNcbiDiag(info, eDiag_Trace) << str << ": " << t;
192 DoThrowTraceAbort();
193 return t;
194 }
195
196 template<class T>
DbgPrintEx(const CDiagCompileInfo & info,const T & t,const char * str)197 typename enable_if<ncbi_throw_trace::is_non_printable<T>::value, const T&>::type DbgPrintEx(
198 const CDiagCompileInfo& info, const T& t, const char* str)
199 {
200 CNcbiDiag(info, eDiag_Trace) << str;
201 DoThrowTraceAbort();
202 return t;
203 }
204
205 // Need overload for non-const char*? See old style DbgPrint() definitions.
206 inline
DbgPrintEx(const CDiagCompileInfo & info,char * str,const char *)207 char* DbgPrintEx(const CDiagCompileInfo& info, char* str, const char*)
208 {
209 CNcbiDiag(info, eDiag_Trace) << str;
210 DoThrowTraceAbort();
211 return str;
212 }
213
214 inline
DbgPrintEx(const CDiagCompileInfo & info,const char * str,const char *)215 const char* DbgPrintEx(const CDiagCompileInfo& info, const char* str, const char*)
216 {
217 CNcbiDiag(info, eDiag_Trace) << str;
218 DoThrowTraceAbort();
219 return str;
220 }
221
222 inline
DbgPrintEx(const CDiagCompileInfo & info,const string & str,const char *)223 const string& DbgPrintEx(const CDiagCompileInfo& info, const string& str, const char*)
224 {
225 CNcbiDiag(info, eDiag_Trace) << str;
226 DoThrowTraceAbort();
227 return str;
228 }
229
230
231 /// Throw trace.
232 ///
233 /// Combines diagnostic message trace and exception throwing. First the
234 /// diagnostic message is printed, and then exception is thrown.
235 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
236 ///
237 /// - If the argument has what() method defined (is an exception), the
238 /// method is used for output.
239 /// - If the argument has output operator defined, it's printed using the
240 /// operator.
241 /// - If the argument is non-printable, it's name is printed.
242 ///
243 /// Example:
244 /// - THROW_TRACE_SIMPLE("Throw just a string");
245 /// - THROW_TRACE_SIMPLE(runtime_error("message"));
246 # define THROW_TRACE_SIMPLE(exception_object) \
247 throw NCBI_NS_NCBI::DbgPrintEx(DIAG_COMPILE_INFO, \
248 exception_object, #exception_object)
249
250 /// Throw trace.
251 ///
252 /// Combines diagnostic message trace and exception throwing. First the
253 /// diagnostic message is printed, and then exception is thrown.
254 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
255 ///
256 /// Arguments can be any class with the specified initialization arguments.
257 ///
258 /// - If the argument has what() method defined (is an exception), the
259 /// method is used for output.
260 /// - If the argument has output operator defined, it's printed using the
261 /// operator.
262 /// - If the argument is non-printable, it's name is printed.
263 ///
264 /// Example:
265 /// - THROW_TRACE_ARGS(runtime_error, "Something is weird...");
266 /// - THROW_TRACE_ARGS(CParseException, ("Some parse error", 123));
267 /// @sa
268 /// THROW_TRACE_SIMPLE
269 # define THROW_TRACE_ARGS(exception_class, ...) \
270 throw NCBI_NS_NCBI::DbgPrintEx(DIAG_COMPILE_INFO, \
271 exception_class(__VA_ARGS__), #exception_class)
272
273
274 /////////////////////////////////
275 // Old style throw-trace macros.
276 //
277
278 /// Templated function for printing debug message.
279 ///
280 /// Print debug message for the specified exception type and "abort()" the
281 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
282 template<typename T>
283 inline
DbgPrint(const CDiagCompileInfo & info,const T & e,const char * e_str)284 const T& DbgPrint(const CDiagCompileInfo& info,
285 const T& e, const char* e_str)
286 {
287 DoDbgPrint(info, e_str, e.what());
288 return e;
289 }
290
291 /// Print debug message for "const char*" object and "abort()" the
292 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
293 inline
DbgPrint(const CDiagCompileInfo & info,const char * e,const char *)294 const char* DbgPrint(const CDiagCompileInfo& info,
295 const char* e, const char*)
296 {
297 DoDbgPrint(info, e);
298 return e;
299 }
300
301 /// Print debug message for "char*" object and "abort()" the
302 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
303 inline
DbgPrint(const CDiagCompileInfo & info,char * e,const char *)304 char* DbgPrint(const CDiagCompileInfo& info,
305 char* e, const char*)
306 {
307 DoDbgPrint(info, e);
308 return e;
309 }
310
311 /// Print debug message for "std::string" object and "abort()" the
312 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
313 inline
DbgPrint(const CDiagCompileInfo & info,const string & e,const char *)314 const string& DbgPrint(const CDiagCompileInfo& info,
315 const string& e, const char*)
316 {
317 DoDbgPrint(info, e);
318 return e;
319 }
320
321 /// Print the specified printable object and "abort()" the program if set by
322 /// SetThrowTraceAbort() or $ABORT_ON_THROW.
323 /// The object must have stream output operator defined.
324 ///
325 /// @sa
326 /// SetThrowTraceAbort(), DoThrowTraceAbort()
327 template<typename T>
328 inline
DbgPrintP(const CDiagCompileInfo & info,const T & e,const char * e_str)329 const T& DbgPrintP(const CDiagCompileInfo& info, const T& e, const char* e_str)
330 {
331 CNcbiDiag(info, eDiag_Trace) << e_str << ": " << e;
332 DoThrowTraceAbort();
333 return e;
334 }
335
336 /// Create diagnostic stream for printing specified message and "abort()" the
337 /// program if set by SetThrowTraceAbort() or $ABORT_ON_THROW.
338 ///
339 /// @sa
340 /// DbgPrintP()
341 template<typename T>
342 inline
DbgPrintNP(const CDiagCompileInfo & info,const T & e,const char * e_str)343 const T& DbgPrintNP(const CDiagCompileInfo& info,
344 const T& e,
345 const char* e_str)
346 {
347 DoDbgPrint(info, e_str);
348 return e;
349 }
350
351 /// Throw trace.
352 ///
353 /// Combines diagnostic message trace and exception throwing. First the
354 /// diagnostic message is printed, and then exception is thrown.
355 ///
356 /// Argument can be a simple string, or an exception object printed using
357 /// what() method.
358 ///
359 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
360 ///
361 /// Example:
362 /// - THROW0_TRACE("Throw just a string");
363 /// - THROW0_TRACE(runtime_error("message"));
364 # define THROW0_TRACE(exception_object) \
365 throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO, \
366 exception_object, #exception_object)
367
368 /// Throw trace.
369 ///
370 /// Combines diagnostic message trace and exception throwing. First the
371 /// diagnostic message is printed, and then exception is thrown.
372 ///
373 /// Argument can be any printable object; that is, any object with a defined
374 /// output operator.
375 ///
376 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
377 ///
378 /// Example:
379 /// - THROW0p_TRACE(123);
380 /// - THROW0p_TRACE(complex(1,2));
381 /// @sa
382 /// THROW0np_TRACE
383 # define THROW0p_TRACE(exception_object) \
384 throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO, \
385 exception_object, #exception_object)
386
387 /// Throw trace.
388 ///
389 /// Combines diagnostic message trace and exception throwing. First the
390 /// diagnostic message is printed, and then exception is thrown.
391 ///
392 /// Argument can be any object; its name is printed.
393 ///
394 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
395 ///
396 /// Example:
397 /// - THROW0np_TRACE(vector<char>());
398 /// @sa
399 /// THROW0p_TRACE
400 # define THROW0np_TRACE(exception_object) \
401 throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO, \
402 exception_object, #exception_object)
403
404 /// Throw trace.
405 ///
406 /// Combines diagnostic message trace and exception throwing. First the
407 /// diagnostic message is printed, and then exception is thrown.
408 ///
409 /// Arguments can be any exception class with the specified initialization
410 /// argument. The class argument need not be derived from std::exception
411 /// but must have what() method used for output.
412 ///
413 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
414 ///
415 /// Example:
416 /// - THROW1_TRACE(runtime_error, "Something is weird...");
417 # define THROW1_TRACE(exception_class, exception_arg) \
418 throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO, \
419 exception_class(exception_arg), #exception_class)
420
421 /// Throw trace.
422 ///
423 /// Combines diagnostic message trace and exception throwing. First the
424 /// diagnostic message is printed, and then exception is thrown.
425 ///
426 /// Arguments can be any exception class with the specified initialization
427 /// argument. The class argument need not be derived from std::exception but
428 /// must have stream output operator defined.
429 ///
430 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
431 ///
432 /// Example:
433 /// - THROW1p_TRACE(int, 32);
434 /// @sa
435 /// THROW1np_TRACE
436 # define THROW1p_TRACE(exception_class, exception_arg) \
437 throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO, \
438 exception_class(exception_arg), #exception_class)
439
440 /// Throw trace.
441 ///
442 /// Combines diagnostic message trace and exception throwing. First the
443 /// diagnostic message is printed, and then exception is thrown.
444 ///
445 /// Arguments can be any exception class with the specified initialization
446 /// argument. The class argument need not be derived from std::exception,
447 /// class name is printed.
448 ///
449 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
450 ///
451 /// Example:
452 /// - THROW1np_TRACE(CUserClass, "argument");
453 # define THROW1np_TRACE(exception_class, exception_arg) \
454 throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO, \
455 exception_class(exception_arg), #exception_class)
456
457 /// Throw trace.
458 ///
459 /// Combines diagnostic message trace and exception throwing. First the
460 /// diagnostic message is printed, and then exception is thrown.
461 ///
462 /// Arguments can be any exception class with the specified initialization
463 /// argument. The class argument need not be derived from std::exception
464 /// but must have what() method used for output.
465 ///
466 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
467 ///
468 /// Similar to THROW1_TRACE except that the exception class can have multiple
469 /// initialization arguments instead of just one.
470 ///
471 /// Example:
472 /// - THROW_TRACE(bad_alloc, ());
473 /// - THROW_TRACE(runtime_error, ("Something is weird..."));
474 /// - THROW_TRACE(CParseException, ("Some parse error", 123));
475 /// @sa
476 /// THROW1_TRACE
477 # define THROW_TRACE(exception_class, exception_args) \
478 throw NCBI_NS_NCBI::DbgPrint(DIAG_COMPILE_INFO, \
479 exception_class exception_args, #exception_class)
480
481 /// Throw trace.
482 ///
483 /// Combines diagnostic message trace and exception throwing. First the
484 /// diagnostic message is printed, and then exception is thrown.
485 ///
486 /// Arguments can be any exception class with the specified initialization
487 /// argument. The class argument need not be derived from std::exception but
488 /// must have stream output operator defined.
489 ///
490 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
491 ///
492 /// Similar to THROW1p_TRACE except that the exception class can have multiple
493 /// initialization arguments instead of just one.
494 ///
495 /// Example:
496 /// - THROWp_TRACE(complex, (2, 3));
497 /// @sa
498 /// THROW1p_TRACE
499 # define THROWp_TRACE(exception_class, exception_args) \
500 throw NCBI_NS_NCBI::DbgPrintP(DIAG_COMPILE_INFO, \
501 exception_class exception_args, #exception_class)
502
503 /// Throw trace.
504 ///
505 /// Combines diagnostic message trace and exception throwing. First the
506 /// diagnostic message is printed, and then exception is thrown.
507 ///
508 /// Arguments can be any exception class with the specified initialization
509 /// argument. The class argument need not be derived from std::exception,
510 /// class name is printed.
511 ///
512 /// Program may abort if so set by SetThrowTraceAbort() or $ABORT_ON_THROW.
513 ///
514 /// Similar to THROW1np_TRACE except that the exception class can have multiple
515 /// initialization arguments instead of just one.
516 ///
517 /// Example:
518 /// - THROWnp_TRACE(CUserClass, (arg1, arg2));
519 # define THROWnp_TRACE(exception_class, exception_args) \
520 throw NCBI_NS_NCBI::DbgPrintNP(DIAG_COMPILE_INFO, \
521 exception_class exception_args, #exception_class)
522
523
524 #else /* _DEBUG */
525
526 // Release-mode versions of the above macros: no trace logging, and no abort().
527
528 # define RETHROW_TRACE \
529 throw
530
531 # define THROW_TRACE_SIMPLE(exception_object) \
532 throw exception_object
533 # define THROW_TRACE_ARGS(exception_class, ...) \
534 throw exception_class(__VA_ARGS__)
535
536 # define THROW0_TRACE(exception_object) \
537 throw exception_object
538 # define THROW0p_TRACE(exception_object) \
539 throw exception_object
540 # define THROW0np_TRACE(exception_object) \
541 throw exception_object
542 # define THROW1_TRACE(exception_class, exception_arg) \
543 throw exception_class(exception_arg)
544 # define THROW1p_TRACE(exception_class, exception_arg) \
545 throw exception_class(exception_arg)
546 # define THROW1np_TRACE(exception_class, exception_arg) \
547 throw exception_class(exception_arg)
548 # define THROW_TRACE(exception_class, exception_args) \
549 throw exception_class exception_args
550 # define THROWp_TRACE(exception_class, exception_args) \
551 throw exception_class exception_args
552 # define THROWnp_TRACE(exception_class, exception_args) \
553 throw exception_class exception_args
554
555 #endif /* else!_DEBUG */
556
557
558 /// Standard handling of "exception"-derived exceptions.
559 /// This macro is deprecated - use *_X or *_XX variant instead of it.
560 #define STD_CATCH(message) \
561 catch (NCBI_NS_STD::exception& e) { \
562 NCBI_NS_NCBI::CNcbiDiag() \
563 << NCBI_NS_NCBI::Error \
564 << "[" << message << "] Exception: " << e.what(); \
565 }
566
567 /// Standard handling of "exception"-derived exceptions; catches non-standard
568 /// exceptions and generates "unknown exception" for all other exceptions.
569 /// This macro is deprecated - use *_X or *_XX variant instead of it.
570 #define STD_CATCH_ALL(message) \
571 STD_CATCH(message) \
572 catch (...) { \
573 NCBI_NS_NCBI::CNcbiDiag() \
574 << NCBI_NS_NCBI::Error \
575 << "[" << message << "] Unknown exception"; \
576 }
577
578 /// Catch CExceptions as well
579 /// This macro is deprecated - use *_X or *_XX variant instead of it.
580 #define NCBI_CATCH(message) \
581 catch (NCBI_NS_NCBI::CException& e) { \
582 NCBI_REPORT_EXCEPTION(message, e); \
583 } \
584 STD_CATCH(message)
585
586 /// This macro is deprecated - use *_X or *_XX variant instead of it.
587 #define NCBI_CATCH_ALL(message) \
588 catch (NCBI_NS_NCBI::CException& e) { \
589 NCBI_REPORT_EXCEPTION(message, e); \
590 } \
591 STD_CATCH_ALL(message)
592
593
594 /// Standard handling of "exception"-derived exceptions
595 /// with default error code and given error subcode placed in diagnostics.
596 /// Default error code is used and error subcode checking for correctness
597 /// is made in same way as in ERR_POST_X macro.
598 ///
599 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_X
600 #define STD_CATCH_X(err_subcode, message) \
601 STD_CATCH_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
602
603 /// Standard handling of "exception"-derived exceptions; catches non-standard
604 /// exceptions and generates "unknown exception" for all other exceptions.
605 /// With default error code and given error subcode placed in diagnostics
606 ///
607 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
608 #define STD_CATCH_ALL_X(err_subcode, message) \
609 STD_CATCH_ALL_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
610
611 /// Catch CExceptions as well
612 /// with default error code and given error subcode placed in diagnostics
613 ///
614 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
615 #define NCBI_CATCH_X(err_subcode, message) \
616 NCBI_CATCH_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
617
618 /// @sa STD_CATCH_ALL_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_X
619 #define NCBI_CATCH_ALL_X(err_subcode, message) \
620 NCBI_CATCH_ALL_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
621
622 /// Standard handling of "exception"-derived exceptions
623 /// with given error code name and given error subcode placed in diagnostics
624 ///
625 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
626 #define STD_CATCH_XX(err_name, err_subcode, message) \
627 catch (NCBI_NS_STD::exception& e) { \
628 NCBI_CHECK_ERR_SUBCODE_X_NAME(err_name, err_subcode); \
629 NCBI_NS_NCBI::CNcbiDiag() \
630 << ErrCode(NCBI_ERRCODE_X_NAME(err_name), err_subcode) \
631 << NCBI_NS_NCBI::Error \
632 << "[" << message << "] Exception: " << e.what(); \
633 }
634
635 /// Standard handling of "exception"-derived exceptions; catches non-standard
636 /// exceptions and generates "unknown exception" for all other exceptions.
637 /// With given error code name and given error subcode placed in diagnostics
638 ///
639 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
640 #define STD_CATCH_ALL_XX(err_name, err_subcode, message) \
641 STD_CATCH_XX(err_name, err_subcode, message) \
642 catch (...) { \
643 NCBI_NS_NCBI::CNcbiDiag() \
644 << ErrCode(NCBI_ERRCODE_X_NAME(err_name), err_subcode) \
645 << NCBI_NS_NCBI::Error \
646 << "[" << message << "] Unknown exception"; \
647 }
648
649 /// Catch CExceptions as well
650 /// with given error code name and given error subcode placed in diagnostics
651 ///
652 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
653 #define NCBI_CATCH_XX(err_name, err_subcode, message) \
654 catch (NCBI_NS_NCBI::CException& e) { \
655 NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, message, e); \
656 } \
657 STD_CATCH_XX(err_name, err_subcode, message)
658
659 /// @sa STD_CATCH_X, NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
660 #define NCBI_CATCH_ALL_XX(err_name, err_subcode, message) \
661 catch (NCBI_NS_NCBI::CException& e) { \
662 NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, message, e); \
663 } \
664 STD_CATCH_ALL_XX(err_name, err_subcode, message)
665
666
667 /////////////////////////////////////////////////////////////////////////////
668 // CException: useful macros
669
670 /// Format message using iostreams library.
671 /// This macro returns an object convertible to std::string.
672 #define FORMAT(message) \
673 NCBI_NS_NCBI::CNcbiOstrstreamToString(static_cast<NCBI_NS_NCBI::CNcbiOstrstream&>(NCBI_NS_NCBI::CNcbiOstrstream().flush() << message))
674
675
676 /// Create an exception instance to be thrown later, given the exception
677 /// class, previous exception pointer, error code and message string.
678 #define NCBI_EXCEPTION_VAR_EX(name, prev_exception_ptr, \
679 exception_class, err_code, message) \
680 exception_class name(DIAG_COMPILE_INFO, \
681 prev_exception_ptr, exception_class::err_code, (message))
682
683 /// Create an instance of the exception to be thrown later.
684 #define NCBI_EXCEPTION_VAR(name, exception_class, err_code, message) \
685 NCBI_EXCEPTION_VAR_EX(name, 0, exception_class, err_code, message)
686
687 /// Throw an existing exception object
688 #define NCBI_EXCEPTION_THROW(exception_var) \
689 throw (exception_var)
690
691 #define NCBI_EXCEPTION_EMPTY_NAME
692
693 /// Generic macro to make an exception, given the exception class,
694 /// error code and message string.
695 #define NCBI_EXCEPTION(exception_class, err_code, message) \
696 NCBI_EXCEPTION_VAR(NCBI_EXCEPTION_EMPTY_NAME, \
697 exception_class, err_code, message)
698
699 /// Generic macro to throw an exception, given the exception class,
700 /// error code and message string.
701 /// The err_code argument may include manipulators to set additional
702 /// options, e.g. eMyErrCode | Console | Severity(eDiag_Info). In any
703 /// case the error code value must be the first in the combination.
704 #define NCBI_THROW(exception_class, err_code, message) \
705 do { \
706 USING_SCOPE(NCBI_NS_NCBI::ncbi_ex_manip); \
707 NCBI_EXCEPTION_THROW(NCBI_EXCEPTION(exception_class, err_code, \
708 message)); \
709 } while (0)
710
711 /// Throw a quick-and-dirty runtime exception of type 'CException' with
712 /// the given error message and error code 'eUnknown'.
713 /// This macro is intended for use only in stand-alone applications.
714 /// Library APIs should properly declare their specific exception types.
715 #define NCBI_USER_THROW(message) \
716 NCBI_THROW(NCBI_NS_NCBI::CException, eUnknown, message)
717
718 /// The same as NCBI_THROW but with message processed as output to ostream.
719 #define NCBI_THROW_FMT(exception_class, err_code, message) \
720 NCBI_THROW(exception_class, err_code, FORMAT(message))
721
722 /// Throw a "user exception" with message processed as output to ostream.
723 /// See NCBI_USER_THROW for details.
724 #define NCBI_USER_THROW_FMT(message) \
725 NCBI_THROW_FMT(NCBI_NS_NCBI::CException, eUnknown, message)
726
727 /// Generic macro to make an exception, given the exception class,
728 /// previous exception, error code and message string.
729 #define NCBI_EXCEPTION_EX(prev_exception, exception_class, err_code, message) \
730 NCBI_EXCEPTION_VAR_EX(NCBI_EXCEPTION_EMPTY_NAME, &(prev_exception), \
731 exception_class, err_code, message)
732
733 /// Generic macro to re-throw an exception.
734 /// The err_code argument may include manipulators to set additional
735 /// options, e.g. eMyErrCode | Console | Severity(eDiag_Info). In any
736 /// case the error code value must be the first in the combination.
737 #define NCBI_RETHROW(prev_exception, exception_class, err_code, message) \
738 do { \
739 USING_SCOPE(NCBI_NS_NCBI::ncbi_ex_manip); \
740 throw NCBI_EXCEPTION_EX(prev_exception, exception_class, \
741 err_code, message); \
742 } while (0)
743
744 /// The same as NCBI_RETHROW but with message processed as output to ostream.
745 #define NCBI_RETHROW_FMT(prev_exception, exception_class, err_code, message) \
746 NCBI_RETHROW(prev_exception, exception_class, err_code, FORMAT(message))
747
748 /// Generic macro to re-throw the same exception.
749 #define NCBI_RETHROW_SAME(prev_exception, message) \
750 do { prev_exception.AddBacklog(DIAG_COMPILE_INFO, message, \
751 prev_exception.GetSeverity()); \
752 throw; } while (0)
753
754 /// Generate a report on the exception.
755 #define NCBI_REPORT_EXCEPTION(title, ex) \
756 NCBI_NS_NCBI::CExceptionReporter::ReportDefault \
757 (DIAG_COMPILE_INFO, title, ex, NCBI_NS_NCBI::eDPF_Default)
758
759 /// Generate a report on the exception with default error code and
760 /// given subcode.
761 #define NCBI_REPORT_EXCEPTION_X(err_subcode, title, ex) \
762 NCBI_REPORT_EXCEPTION_XX(NCBI_USE_ERRCODE_X, err_subcode, title, ex)
763
764 /// Generate a report on the exception with default error code and
765 /// given subcode.
766 #define NCBI_REPORT_EXCEPTION_XX(err_name, err_subcode, title, ex) \
767 NCBI_CHECK_ERR_SUBCODE_X_NAME(err_name, err_subcode); \
768 NCBI_NS_NCBI::CExceptionReporter::ReportDefaultEx \
769 (NCBI_ERRCODE_X_NAME(err_name), err_subcode, \
770 DIAG_COMPILE_INFO, title, ex, NCBI_NS_NCBI::eDPF_Default)
771
772
773 /////////////////////////////////////////////////////////////////////////////
774 // CException
775
776 // Forward declaration of CExceptionReporter.
777 class CExceptionReporter;
778
779
780 // Base helper class for passing options to exceptions.
781 class CExceptionArgs_Base
782 {
783 public:
784 typedef int TErrCodeVal;
785 typedef int TFlags;
786 typedef EDiagSev TSeverity;
787
CExceptionArgs_Base(void)788 CExceptionArgs_Base(void) :
789 m_ErrCode(0), m_Flags(0),
790 m_Severity(eDiag_Error), m_Retriable(eRetriable_Unknown)
791 {}
792
SetErrCodeVal(TErrCodeVal err_code)793 void SetErrCodeVal(TErrCodeVal err_code) { m_ErrCode = err_code; }
GetErrCodeVal(void) const794 TErrCodeVal GetErrCodeVal(void) const { return m_ErrCode; }
795
SetFlags(TFlags flags)796 void SetFlags(TFlags flags) { m_Flags = flags; }
GetFlags(void) const797 TFlags GetFlags(void) const { return m_Flags; }
798
SetSeverity(TSeverity severity)799 void SetSeverity(TSeverity severity) { m_Severity = severity; }
GetSeverity(void) const800 TSeverity GetSeverity(void) const { return m_Severity; }
801
SetModule(const string & module)802 void SetModule(const string& module) { m_Module = module; }
GetModule(void) const803 const string& GetModule(void) const { return m_Module; }
IsSetModule(void) const804 bool IsSetModule(void) const { return !m_Module.empty(); }
805
SetRetriable(ERetriable retriable)806 void SetRetriable(ERetriable retriable) { m_Retriable = retriable; }
GetRetriable(void) const807 ERetriable GetRetriable(void) const { return m_Retriable; }
808
809 private:
810 TErrCodeVal m_ErrCode;
811 TFlags m_Flags;
812 TSeverity m_Severity;
813 string m_Module;
814 ERetriable m_Retriable;
815 };
816
817
818 class CExceptionArgsManip
819 {
820 public:
~CExceptionArgsManip(void)821 virtual ~CExceptionArgsManip(void) {}
822
823 virtual void operator()(CExceptionArgs_Base& args) const = 0;
824 };
825
826 typedef void (*FExceptionArgsManip)(CExceptionArgs_Base&);
827
828 /// Manipulator function wrapper.
829 class CExceptionArgsManip_Wrapper : public CExceptionArgsManip
830 {
831 public:
CExceptionArgsManip_Wrapper(FExceptionArgsManip f)832 CExceptionArgsManip_Wrapper(FExceptionArgsManip f) : m_Func(f) { }
833
operator ()(CExceptionArgs_Base & args) const834 void operator()(CExceptionArgs_Base& args) const { (*m_Func)(args); }
835
836 private:
837 FExceptionArgsManip m_Func;
838 };
839
840
841 template<class TErrCode>
842 class CExceptionArgs : public CExceptionArgs_Base
843 {
844 public:
CExceptionArgs(TErrCode err_code)845 CExceptionArgs(TErrCode err_code) { SetErrCodeVal(err_code); }
846
GetErrCode(void) const847 TErrCode GetErrCode(void) const { return TErrCode(GetErrCodeVal()); }
848
operator |(const CExceptionArgsManip & manip)849 CExceptionArgs<TErrCode>& operator|(const CExceptionArgsManip& manip)
850 {
851 manip(*this);
852 return *this;
853 }
854
operator |(const CExceptionArgsManip_Wrapper & manip)855 CExceptionArgs<TErrCode>& operator|(const CExceptionArgsManip_Wrapper& manip)
856 {
857 manip(*this);
858 return *this;
859 }
860 };
861
862
863 /////////////////////////////////////////////////////////////////////////////
864 ///
865 /// CException --
866 ///
867 /// Define an extended exception class based on the C+++ std::exception.
868 ///
869 /// CException inherits its basic functionality from std::exception and
870 /// defines additional generic error codes for applications, and error
871 /// reporting capabilities.
872
873 class CRequestContextRef;
874 class CRequestContext;
875
876 class NCBI_XNCBI_EXPORT CException : public std::exception
877 {
878 public:
879 /// Error types that an application can generate.
880 ///
881 /// Each derived class has its own error codes and their interpretations.
882 /// Define two generic error codes "eInvalid" and "eUnknown" to be used
883 /// by all NCBI applications.
884 enum EErrCode {
885 eInvalid = -1, ///< To be used ONLY as a return value;
886 ///< please, NEVER throw an exception with this code.
887 eUnknown = 0 ///< Unknown exception.
888 };
889 typedef int TErrCode;
890
891 /// Miscellaneous generic hints, flags and attributes
892 enum EFlags {
893 /// Mark the exception with this flag if the exception is supposed
894 /// to be extra-visible, such as to go to a console or a dialog
895 /// that's looked at by the end user. Naturally, the message should be
896 /// clear and informative enough to be actually helpful for the user.
897 /// If such "console" exception is passed to the diagnostic (e.g.
898 /// "ERR_POST(ex);", then the posting will be automatically marked as
899 /// "console" too (so it'll work as "ERR_POST(Console << ex);").
900 fConsole = (1 << 0)
901 };
902 typedef int TFlags; //< Bit-wise OR of "EFlags"
903
904 /// Constructor.
905 ///
906 /// When throwing an exception initially, "prev_exception" must be 0.
907 CException(const CDiagCompileInfo& info,
908 const CException* prev_exception,
909 EErrCode err_code,
910 const string& message,
911 EDiagSev severity = eDiag_Error,
912 TFlags flags = 0);
913
914 CException(const CDiagCompileInfo& info,
915 const CException* prev_exception,
916 const CExceptionArgs<EErrCode>& args,
917 const string& message);
918
919 /// Copy constructor.
920 CException(const CException& other);
921
922 /// Add a message to backlog (to re-throw the same exception then).
923 void AddBacklog(const CDiagCompileInfo& info,
924 const string& message,
925 EDiagSev severity = eDiag_Error);
926
927 void AddPrevious(const CException* prev_exception);
928 void AddToMessage(const string& add_msg);
929
930 /// Polymorphically (re)throw an exception whose exact type is
931 /// uncertain.
932 ///
933 /// NB: for best results, *EVERY* concrete derived class in the
934 /// hierarchy must implement its *OWN* version of Throw(). (Using
935 /// NCBI_EXCEPTION_DEFAULT or a related macro will take care of
936 /// this for you.)
937 ///
938 /// Simply invoking the throw keyword with no arguments is a
939 /// better option when available (within a catch block), but there
940 /// are circumstances in which it is not.
941 NCBI_NORETURN virtual void Throw(void) const;
942
943 // ---- Reporting --------------
944
945 /// Standard report (includes full backlog).
946 virtual const char* what(void) const throw();
947
948 /// Report the exception.
949 ///
950 /// Report the exception using "reporter" exception reporter.
951 /// If "reporter" is not specified (value 0), then use the default
952 /// reporter as set with CExceptionReporter::SetDefault.
953 void Report(const CDiagCompileInfo& info,
954 const string& title, CExceptionReporter* reporter = 0,
955 TDiagPostFlags flags = eDPF_Exception) const;
956
957 /// Report this exception only.
958 ///
959 /// Report as a string this exception only. No backlog is attached.
960 string ReportThis(TDiagPostFlags flags = eDPF_Exception) const;
961
962 /// Report all exceptions.
963 ///
964 /// Report as a string all exceptions. Include full backlog.
965 string ReportAll (TDiagPostFlags flags = eDPF_Exception) const;
966
967 /// Report "standard" attributes.
968 ///
969 /// Report "standard" attributes (file, line, type, err.code, user message)
970 /// into the "out" stream (this exception only, no backlog).
971 void ReportStd(ostream& out, TDiagPostFlags flags = eDPF_Exception) const;
972
973 /// Report "non-standard" attributes.
974 ///
975 /// Report "non-standard" attributes (those of derived class) into the
976 /// "out" stream.
977 virtual void ReportExtra(ostream& out) const;
978
979 /// Get the saved stack trace if available or NULL.
980 const CStackTrace* GetStackTrace(void) const;
981
982 /// Enable background reporting.
983 ///
984 /// If background reporting is enabled, then calling what() or ReportAll()
985 /// would also report exception to the default exception reporter.
986 /// @return
987 /// The previous state of the flag.
988 static bool EnableBackgroundReporting(bool enable);
989
990 /// Set severity level for saving and printing stack trace
991 static void SetStackTraceLevel(EDiagSev level);
992
993 /// Get current severity level for saving and printing stack trace
994 static EDiagSev GetStackTraceLevel(void);
995
996 // ---- Attributes ---------
997
998 /// Get exception severity.
GetSeverity(void) const999 EDiagSev GetSeverity(void) const { return m_Severity; }
1000
1001 /// Set exception severity.
1002 CException& SetSeverity(EDiagSev severity);
1003
1004 /// Get class name as a string.
1005 virtual const char* GetType(void) const;
1006
1007 /// Get error code interpreted as text.
1008 virtual const char* GetErrCodeString(void) const;
1009
1010 /// Get file name used for reporting.
GetFile(void) const1011 const string& GetFile(void) const { return m_File; }
1012
1013 /// Set module name used for reporting.
SetModule(const string & module)1014 void SetModule(const string& module) { m_Module = module; }
1015
1016 /// Get module name used for reporting.
GetModule(void) const1017 const string& GetModule(void) const { return m_Module; }
1018
1019 /// Set class name used for reporting.
SetClass(const string & nclass)1020 void SetClass(const string& nclass) { m_Class = nclass; }
1021
1022 /// Get class name used for reporting.
GetClass(void) const1023 const string& GetClass(void) const { return m_Class; }
1024
1025 /// Set function name used for reporting.
SetFunction(const string & function)1026 void SetFunction(const string& function) { m_Function = function; }
1027
1028 /// Get function name used for reporting.
GetFunction(void) const1029 const string& GetFunction(void) const { return m_Function; }
1030
1031 /// Get line number where error occurred.
GetLine(void) const1032 int GetLine(void) const { return m_Line; }
1033
1034 /// Get error code.
1035 TErrCode GetErrCode(void) const;
1036
1037 /// Get message string.
1038 const string& GetMsg(void) const;
1039
1040 /// Get "previous" exception from the backlog.
GetPredecessor(void) const1041 const CException* GetPredecessor(void) const { return m_Predecessor; }
1042
1043 /// Check if exception has main text in the chain
HasMainText(void) const1044 bool HasMainText(void) const { return m_MainText; }
1045
1046 /// Destructor.
1047 virtual ~CException(void) throw();
1048
1049 /// Check if the flag is set
IsSetFlag(EFlags flag) const1050 bool IsSetFlag(EFlags flag) const { return (m_Flags & flag) != 0; }
1051
1052 /// Set flag (add to other flags)
SetFlag(EFlags flag)1053 CException& SetFlag(EFlags flag) { m_Flags |= flag; return *this; }
1054
1055 /// Unset flag (other flags are left as is)
UnsetFlag(EFlags flag)1056 CException& UnsetFlag(EFlags flag) { m_Flags &= ~flag; return *this; }
1057
1058 /// Get the request context in which the exception was thrown.
1059 CRequestContext& GetRequestContext(void) const;
1060
1061 /// Set the info about ability to retry an action caused the exception
SetRetriable(ERetriable retriable)1062 void SetRetriable(ERetriable retriable) { m_Retriable = retriable; }
1063
1064 /// Retrieve info about ability to retry an action caused the exception
GetRetriable(void) const1065 virtual ERetriable GetRetriable(void) const { return m_Retriable; }
1066
1067 protected:
1068 /// Constructor for derived classes
1069 CException(const CDiagCompileInfo& info,
1070 const CException* prev_exception,
1071 const string& message,
1072 EDiagSev severity = eDiag_Error,
1073 TFlags flags = 0);
1074 /// Constructor with no arguments.
1075 ///
1076 /// Required in case of multiple inheritance.
1077 CException(void);
1078
1079 /// Helper method for reporting to the system debugger.
1080 virtual void x_ReportToDebugger(void) const;
1081
1082 /// Helper method for cloning the exception.
1083 virtual const CException* x_Clone(void) const;
1084
1085 /// Helper method for initializing exception data.
1086 virtual void x_Init(const CDiagCompileInfo& info,
1087 const string& message,
1088 const CException* prev_exception,
1089 EDiagSev severity);
1090
1091 /// Process additional arguments. Derived classes may need
1092 /// to cast args to CExceptionArgs<CDerivedException::EErrCode>.
1093 virtual void x_InitArgs(const CExceptionArgs_Base& args);
1094
1095 /// Helper method for copying exception data.
1096 virtual void x_Assign(const CException& src);
1097
1098 /// Helper method for assigning error code.
1099 virtual void x_AssignErrCode(const CException& src);
1100
1101 /// Helper method for initializing error code.
1102 virtual void x_InitErrCode(CException::EErrCode err_code);
1103
1104 /// Helper method for getting error code.
x_GetErrCode(void) const1105 virtual int x_GetErrCode(void) const { return m_ErrCode; }
1106
1107 /// Get and store current stack trace.
1108 void x_GetStackTrace(void);
1109
1110 /// Warn if Throw() will end up slicing its invocant.
1111 void x_ThrowSanityCheck(const type_info& expected_type,
1112 const char* human_name) const;
1113
1114 private:
1115 EDiagSev m_Severity; ///< Severity level for the exception
1116 string m_File; ///< File to report on
1117 int m_Line; ///< Line number
1118 int m_ErrCode; ///< Error code
1119 string m_Msg; ///< Message string
1120 string m_Module; ///< Module to report on
1121 string m_Class; ///< Class to report on
1122 string m_Function; ///< Function to report on
1123
1124 mutable string m_What; ///< What type of exception
1125 typedef const CException* TExceptionPtr;
1126 mutable TExceptionPtr m_Predecessor; ///< Previous exception
1127
1128 mutable bool m_InReporter; ///< Reporter flag
1129 mutable bool m_MainText; ///< Exception has main text
1130 static bool sm_BkgrEnabled; ///< Background reporting enabled flag
1131
1132 unique_ptr<CStackTrace> m_StackTrace; ///< Saved stack trace
1133
1134 TFlags m_Flags; ///< Flags, hints, attributes
1135
1136 ERetriable m_Retriable; ///< In some cases it is known for sure if
1137 ///< an action caused the exception can be
1138 ///< tried again or not. This member holds
1139 ///< this information.
1140
1141 unique_ptr<CRequestContextRef> m_RequestContext;
1142
1143 /// Private assignment operator to prohibit assignment.
1144 CException& operator= (const CException&);
1145 };
1146
1147
1148 /// Exception manipulators. Can be combined with error code using operator|().
1149
1150 BEGIN_SCOPE(ncbi_ex_manip)
1151
1152 template<class TErrCode>
1153 CExceptionArgs<TErrCode> operator|(TErrCode err_code,
1154 const CExceptionArgsManip& manip)
1155 {
1156 CExceptionArgs<TErrCode> args(err_code);
1157 manip(args);
1158 return args;
1159 }
1160
1161
1162 template<class TErrCode>
operator |(TErrCode err_code,const CExceptionArgsManip_Wrapper & manip)1163 CExceptionArgs<TErrCode> operator|(TErrCode err_code,
1164 const CExceptionArgsManip_Wrapper& manip)
1165 {
1166 CExceptionArgs<TErrCode> args(err_code);
1167 manip(args);
1168 return args;
1169 }
1170
1171
1172 inline
Console(CExceptionArgs_Base & args)1173 void Console(CExceptionArgs_Base& args)
1174 {
1175 args.SetFlags(args.GetFlags() | CException::fConsole);
1176 }
1177
1178 inline
Trace(CExceptionArgs_Base & args)1179 void Trace(CExceptionArgs_Base& args)
1180 {
1181 args.SetSeverity(eDiag_Trace);
1182 }
1183
1184 inline
Info(CExceptionArgs_Base & args)1185 void Info(CExceptionArgs_Base& args)
1186 {
1187 args.SetSeverity(eDiag_Info);
1188 }
1189
1190 inline
Warning(CExceptionArgs_Base & args)1191 void Warning(CExceptionArgs_Base& args)
1192 {
1193 args.SetSeverity(eDiag_Warning);
1194 }
1195
1196 inline
Error(CExceptionArgs_Base & args)1197 void Error(CExceptionArgs_Base& args)
1198 {
1199 args.SetSeverity(eDiag_Error);
1200 }
1201
1202 inline
Critical(CExceptionArgs_Base & args)1203 void Critical(CExceptionArgs_Base& args)
1204 {
1205 args.SetSeverity(eDiag_Critical);
1206 }
1207
1208 inline
Fatal(CExceptionArgs_Base & args)1209 void Fatal(CExceptionArgs_Base& args)
1210 {
1211 args.SetSeverity(eDiag_Fatal);
1212 }
1213
1214
1215 /// Module manipulator
1216
1217 class Module : public CExceptionArgsManip
1218 {
1219 public:
Module(const string & module)1220 Module(const string& module) : m_Module(module) {}
Module(const char * module)1221 Module(const char* module) : m_Module(module) {}
~Module(void)1222 virtual ~Module(void) {}
1223
operator ()(CExceptionArgs_Base & args) const1224 virtual void operator()(CExceptionArgs_Base& args) const
1225 {
1226 args.SetModule(m_Module);
1227 }
1228
1229 private:
1230 string m_Module;
1231 };
1232
1233
1234 /// Retriable manipulator
1235
1236 class Retriable : public CExceptionArgsManip
1237 {
1238 public:
Retriable(ERetriable retriable)1239 Retriable(ERetriable retriable) : m_Retriable(retriable) {}
~Retriable(void)1240 virtual ~Retriable(void) {}
1241
operator ()(CExceptionArgs_Base & args) const1242 virtual void operator()(CExceptionArgs_Base& args) const
1243 {
1244 args.SetRetriable(m_Retriable);
1245 }
1246
1247 private:
1248 ERetriable m_Retriable;
1249 };
1250
1251
END_SCOPE(ncbi_ex_manip) const1252 END_SCOPE(ncbi_ex_manip)
1253
1254
1255 /// Return valid pointer to uppermost derived class only if "from" is _really_
1256 /// the object of the desired type.
1257 ///
1258 /// Do not cast to intermediate types (return NULL if such cast is attempted).
1259 template <class TTo, class TFrom>
1260 const TTo* UppermostCast(const TFrom& from)
1261 {
1262 return typeid(from) == typeid(TTo) ? dynamic_cast<const TTo*>(&from) : 0;
1263 }
1264
1265 #define NCBI_EXCEPTION_DEFAULT_THROW(exception_class) \
1266 NCBI_NORETURN virtual void Throw(void) const override \
1267 { \
1268 this->x_ThrowSanityCheck(typeid(exception_class), #exception_class); \
1269 throw *this; \
1270 }
1271
1272 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1273 exception_class(const exception_class& other) \
1274 : base_class(other) \
1275 { \
1276 this->x_Assign(other); \
1277 } \
1278 public: \
1279 virtual ~exception_class(void) throw() {} \
1280 virtual const char* GetType(void) const override {return #exception_class;} \
1281 typedef int TErrCode; \
1282 TErrCode GetErrCode(void) const \
1283 { \
1284 return typeid(*this) == typeid(exception_class) ? \
1285 (TErrCode) this->x_GetErrCode() : \
1286 (TErrCode) CException::eInvalid; \
1287 } \
1288 NCBI_EXCEPTION_DEFAULT_THROW(exception_class) \
1289 protected: \
1290 exception_class(void) {} \
1291 virtual const CException* x_Clone(void) const override \
1292 { \
1293 return new exception_class(*this); \
1294 } \
1295
1296
1297 /// Helper macro for default exception implementation.
1298 /// @sa
1299 /// NCBI_EXCEPTION_DEFAULT
1300 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(exception_class, base_class) \
1301 { \
1302 x_Init(info, message, prev_exception, severity); \
1303 x_InitErrCode((CException::EErrCode) err_code); \
1304 } \
1305 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1306 private: \
1307 /* for the sake of semicolon at the end of macro...*/ \
1308 static void xx_unused_##exception_class(void)
1309
1310
1311 /// To help declare new exception class.
1312 ///
1313 /// This can be used ONLY if the derived class does not have any additional
1314 /// (non-standard) data members.
1315 #define NCBI_EXCEPTION_DEFAULT(exception_class, base_class) \
1316 public: \
1317 exception_class(const CDiagCompileInfo& info, \
1318 const CException* prev_exception, EErrCode err_code, \
1319 const string& message, EDiagSev severity = eDiag_Error) \
1320 : base_class(info, prev_exception, (message), severity, 0) \
1321 { \
1322 x_Init(info, message, prev_exception, severity); \
1323 x_InitErrCode((CException::EErrCode) err_code); \
1324 } \
1325 exception_class(const CDiagCompileInfo& info, \
1326 const CException* prev_exception, \
1327 const CExceptionArgs<EErrCode>& args, \
1328 const string& message) \
1329 : base_class(info, prev_exception, (message), \
1330 args.GetSeverity(), 0) \
1331 { \
1332 x_Init(info, message, prev_exception, args.GetSeverity()); \
1333 x_InitArgs(args); \
1334 x_InitErrCode((CException::EErrCode) args.GetErrCode()); \
1335 } \
1336 protected: \
1337 exception_class(const CDiagCompileInfo& info, \
1338 const CException* prev_exception, \
1339 const string& message, \
1340 EDiagSev severity, CException::TFlags flags) \
1341 : base_class(info, prev_exception, (message), severity, flags) \
1342 { \
1343 } \
1344 public: \
1345 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, \
1346 base_class) \
1347 private: \
1348 /* for the sake of semicolon at the end of macro...*/ \
1349 static void xx_unused_##exception_class(void)
1350
1351
1352 /// Helper macro added to support templatized exceptions.
1353 ///
1354 /// GCC starting from 3.2.2 warns about implicit typenames - this macro fixes
1355 /// the warning.
1356 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL(exception_class, base_class) \
1357 { \
1358 this->x_Init(info, message, prev_exception, severity); \
1359 this->x_InitErrCode((typename CException::EErrCode) err_code); \
1360 } \
1361 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class)
1362
1363
1364 /// Helper macro added to support errno based templatized exceptions.
1365 #define NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(exception_class, base_class) \
1366 { \
1367 this->x_Init(info, message, prev_exception, severity); \
1368 this->x_InitErrCode((typename CException::EErrCode) err_code); \
1369 } \
1370 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_COMMON(exception_class, base_class) \
1371 public: \
1372 virtual const char* GetErrCodeString(void) const override \
1373 { \
1374 switch (GetErrCode()) { \
1375 case CParent::eErrno: return "eErrno"; \
1376 default: return CException::GetErrCodeString(); \
1377 } \
1378 }
1379
1380
1381
1382 /// Do not use virtual base classes in exception declaration at all,
1383 /// because in this case derived class should initialize all base
1384 /// classes directly, that is not convenient and hard to control.
1385 ///
1386 /// @deprecated
1387 ///
1388 #define EXCEPTION_VIRTUAL_BASE
1389
1390
1391
1392 /////////////////////////////////////////////////////////////////////////////
1393 ///
1394 /// CExceptionReporter --
1395 ///
1396 /// Define exception reporter.
1397
1398 class NCBI_XNCBI_EXPORT CExceptionReporter
1399 {
1400 public:
1401 /// Constructor.
1402 CExceptionReporter(void);
1403
1404 /// Destructor.
1405 virtual ~CExceptionReporter(void);
1406
1407 /// Set default reporter.
1408 static void SetDefault(const CExceptionReporter* handler);
1409
1410 /// Get default reporter.
1411 static const CExceptionReporter* GetDefault(void);
1412
1413 /// Enable/disable using default reporter.
1414 ///
1415 /// @return
1416 /// Previous state of this flag.
1417 static bool EnableDefault(bool enable);
1418
1419 /// Report exception using default reporter.
1420 static void ReportDefault(const CDiagCompileInfo& info,
1421 const string& title, const std::exception& ex,
1422 TDiagPostFlags flags = eDPF_Exception);
1423
1424 /// Report exception using default reporter and particular error code and
1425 /// subcode when writing to diagnostics.
1426 static void ReportDefaultEx(int err_code, int err_subcode,
1427 const CDiagCompileInfo& info,
1428 const string& title, const std::exception& ex,
1429 TDiagPostFlags flags = eDPF_Exception);
1430
1431 /// Report CException with _this_ reporter
1432 virtual void Report(const char* file, int line,
1433 const string& title, const CException& ex,
1434 TDiagPostFlags flags = eDPF_Exception) const = 0;
1435 private:
1436 static const CExceptionReporter* sm_DefHandler; ///< Default handler
1437 static bool sm_DefEnabled; ///< Default enable flag
1438 };
1439
1440
1441
1442 /////////////////////////////////////////////////////////////////////////////
1443 ///
1444 /// CExceptionReporterStream --
1445 ///
1446 /// Define exception reporter stream.
1447
1448 class NCBI_XNCBI_EXPORT CExceptionReporterStream : public CExceptionReporter
1449 {
1450 public:
1451 /// Constructor.
1452 CExceptionReporterStream(ostream& out);
1453
1454 /// Destructor.
1455 virtual ~CExceptionReporterStream(void);
1456
1457 /// Report specified exception on output stream.
1458 virtual void Report(const char* file, int line,
1459 const string& title, const CException& ex,
1460 TDiagPostFlags flags = eDPF_Exception) const;
1461 private:
1462 ostream& m_Out; ///< Output stream
1463 };
1464
1465
1466
1467 /////////////////////////////////////////////////////////////////////////////
1468 ///
1469 /// CCoreException --
1470 ///
1471 /// Define corelib exception. CCoreException inherits its basic
1472 /// functionality from CException and defines additional error codes for
1473 /// applications.
1474
1475 class NCBI_XNCBI_EXPORT CCoreException : EXCEPTION_VIRTUAL_BASE public CException
1476 {
1477 public:
1478 /// Error types that corelib can generate.
1479 ///
1480 /// These generic error conditions can occur for corelib applications.
1481 enum EErrCode {
1482 eCore, ///< Generic corelib error
1483 eNullPtr, ///< Null pointer error
1484 eDll, ///< Dll error
1485 eDiagFilter, ///< Illegal syntax of the diagnostics filter string
1486 eInvalidArg ///< Invalid argument error
1487 };
1488
1489 /// Translate from the error code value to its string representation.
1490 virtual const char* GetErrCodeString(void) const override;
1491
1492 // Standard exception boilerplate code.
1493 NCBI_EXCEPTION_DEFAULT(CCoreException, CException);
1494 };
1495
1496
1497 /////////////////////////////////////////////////////////////////////////////
1498 ///
1499 /// CInvalidParamException --
1500 ///
1501 /// Exception to report configuration or command line parameter errors
1502 /// (external error sources as opposed to CCoreException::eInvalidArg).
1503
1504 class NCBI_XNCBI_EXPORT CInvalidParamException : public CException
1505 {
1506 public:
1507 enum EErrCode {
1508 eUndefined = 1, ///< Parameter is missing/undefined
1509 eInvalidCharacter ///< Parameter value contains invalid character
1510 };
1511
1512 /// Translate from an error code value to its string representation.
1513 virtual const char* GetErrCodeString(void) const override;
1514
1515 // Standard exception boilerplate code.
1516 NCBI_EXCEPTION_DEFAULT(CInvalidParamException, CException);
1517 };
1518
1519
1520 // Some implementations return char*, so strict compilers may refuse
1521 // to let them satisfy TErrorStr without a wrapper. However, they
1522 // don't all agree on what form the wrapper should take. :-/
1523 NCBI_XNCBI_EXPORT
1524 extern const char* Ncbi_strerror(int errnum);
1525
1526 #ifdef NCBI_COMPILER_GCC
NcbiErrnoCode(void)1527 inline int NcbiErrnoCode(void) { return errno; }
NcbiErrnoStr(int errnum)1528 inline const char* NcbiErrnoStr(int errnum) { return ::strerror(errnum); }
1529 # define NCBI_ERRNO_CODE_WRAPPER NCBI_NS_NCBI::NcbiErrnoCode
1530 # define NCBI_ERRNO_STR_WRAPPER NCBI_NS_NCBI::NcbiErrnoStr
1531 #else
1532 class CErrnoAdapt
1533 {
1534 public:
GetErrCode(void)1535 static int GetErrCode(void)
1536 { return errno; }
GetErrCodeString(int errnum)1537 static const char* GetErrCodeString(int errnum)
1538 {
1539 return Ncbi_strerror(errnum);
1540 }
1541 };
1542 # define NCBI_ERRNO_CODE_WRAPPER NCBI_NS_NCBI::CErrnoAdapt::GetErrCode
1543 # define NCBI_ERRNO_STR_WRAPPER NCBI_NS_NCBI::CErrnoAdapt::GetErrCodeString
1544 #endif
1545
1546 // MS Windows API errors
1547 #ifdef NCBI_OS_MSWIN
1548 class NCBI_XNCBI_EXPORT CLastErrorAdapt
1549 {
1550 public:
GetErrCode(void)1551 static int GetErrCode(void)
1552 { return GetLastError(); }
1553 static const char* GetErrCodeString(int errnum);
1554 };
1555 # define NCBI_LASTERROR_CODE_WRAPPER \
1556 NCBI_NS_NCBI::CLastErrorAdapt::GetErrCode
1557 # define NCBI_LASTERROR_STR_WRAPPER \
1558 NCBI_NS_NCBI::CLastErrorAdapt::GetErrCodeString
1559 #endif
1560
1561
1562 /////////////////////////////////////////////////////////////////////////////
1563 // Auxiliary exception classes:
1564 // CErrnoException
1565 // CErrnoException_Win
1566 // CParseException
1567 //
1568
1569 /// Define function type for "error code" function.
1570 typedef int (*TErrorCode)(void);
1571
1572 /// Define function type for "error str" function.
1573 typedef const char* (*TErrorStr)(int errnum);
1574
1575
1576 /////////////////////////////////////////////////////////////////////////////
1577 ///
1578 /// CErrnoTemplExceptionEx --
1579 ///
1580 /// Define template class for easy generation of Errno-like exception classes.
1581
1582 template <class TBase,
1583 TErrorCode PErrCode=NCBI_ERRNO_CODE_WRAPPER,
1584 TErrorStr PErrStr=NCBI_ERRNO_STR_WRAPPER >
1585 class CErrnoTemplExceptionEx : EXCEPTION_VIRTUAL_BASE public TBase
1586 {
1587 public:
1588 /// Error type that an application can generate.
1589 enum EErrCode {
1590 eErrno ///< Error code
1591 };
1592
1593 /// Translate from the error code value to its string representation.
GetErrCodeString(void) const1594 virtual const char* GetErrCodeString(void) const override
1595 {
1596 switch (GetErrCode()) {
1597 case eErrno: return "eErrno";
1598 default: return CException::GetErrCodeString();
1599 }
1600 }
1601
1602 public:
1603 /// Copy constructor.
CErrnoTemplExceptionEx(const CErrnoTemplExceptionEx<TBase,PErrCode,PErrStr> & other)1604 CErrnoTemplExceptionEx(
1605 const CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>& other)
1606 : TBase(other)
1607 {
1608 m_Errno = other.m_Errno;
1609 this->x_Assign(other);
1610 }
1611
1612 /// Destructor.
~CErrnoTemplExceptionEx(void)1613 virtual ~CErrnoTemplExceptionEx(void) throw() {}
1614
1615 /// Report error number on stream.
ReportExtra(ostream & out) const1616 virtual void ReportExtra(ostream& out) const override
1617 {
1618 out << "errno = " << m_Errno << ": " << PErrStr(m_Errno);
1619 }
1620
1621 // Attributes.
1622
1623 /// Get type of class.
GetType(void) const1624 virtual const char* GetType(void) const override
1625 { return "CErrnoTemplException"; }
1626
1627 typedef int TErrCode;
1628 /// Get error code.
1629
GetErrCode(void) const1630 TErrCode GetErrCode(void) const
1631 {
1632 return typeid(*this) ==
1633 typeid(CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>) ?
1634 (TErrCode) this->x_GetErrCode() :
1635 (TErrCode) CException::eInvalid;
1636 }
1637
1638 /// Get error number.
GetErrno(void) const1639 int GetErrno(void) const throw() { return m_Errno; }
1640
1641 protected:
1642 /// Constructor (with errno only).
1643 /// It is unable to get correct error code after all base constructors initialization,
1644 /// that can reset it, so error code should be provided as parameter.
CErrnoTemplExceptionEx(const CDiagCompileInfo & info,const CException * prev_exception,const string & message,int errnum,EDiagSev severity=eDiag_Error,CException::TFlags flags=0)1645 CErrnoTemplExceptionEx(const CDiagCompileInfo& info,
1646 const CException* prev_exception,
1647 const string& message,
1648 int errnum, EDiagSev severity = eDiag_Error,
1649 CException::TFlags flags = 0)
1650 : TBase(info, prev_exception, message, severity, flags),
1651 m_Errno(errnum)
1652 {
1653 this->x_Init(info, message, prev_exception, severity);
1654 }
1655 /// Default constructor.
CErrnoTemplExceptionEx(void)1656 CErrnoTemplExceptionEx(void) { m_Errno = PErrCode(); }
1657
1658
1659 /// Helper clone method.
x_Clone(void) const1660 virtual const CException* x_Clone(void) const override
1661 {
1662 return new CErrnoTemplExceptionEx<TBase, PErrCode, PErrStr>(*this);
1663 }
1664
1665 private:
1666 int m_Errno; ///< Error number
1667 };
1668
1669
1670
1671 /////////////////////////////////////////////////////////////////////////////
1672 ///
1673 /// CErrnoTemplException --
1674 ///
1675 /// Define template class for easy generation of Errno-like exception classes.
1676
1677 template<class TBase> class CErrnoTemplException :
1678 public CErrnoTemplExceptionEx<TBase,
1679 NCBI_ERRNO_CODE_WRAPPER,
1680 NCBI_ERRNO_STR_WRAPPER>
1681 {
1682 public:
1683 /// Parent class type.
1684 typedef CErrnoTemplExceptionEx<TBase, NCBI_ERRNO_CODE_WRAPPER, NCBI_ERRNO_STR_WRAPPER> CParent;
1685
1686 /// Constructor.
1687 CErrnoTemplException<TBase>(const CDiagCompileInfo& info,
1688 const CException* prev_exception,
1689 typename CParent::EErrCode err_code,
1690 const string& message,
1691 EDiagSev severity = eDiag_Error)
1692 : CParent(info, prev_exception, message, NCBI_ERRNO_CODE_WRAPPER(), severity, 0)
1693 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(CErrnoTemplException<TBase>, CParent)
1694
1695 protected:
1696 CErrnoTemplException<TBase>(const CDiagCompileInfo& info,
1697 const CException* prev_exception,
1698 const string& message,
1699 EDiagSev severity,
1700 CException::TFlags flags)
1701 : CParent(info, prev_exception, message, NCBI_ERRNO_CODE_WRAPPER(), severity, flags) {
1702 }
1703 };
1704
1705
1706 #ifdef NCBI_OS_MSWIN
1707 template<class TBase> class CErrnoTemplException_Win :
1708 public CErrnoTemplExceptionEx<TBase,
1709 NCBI_LASTERROR_CODE_WRAPPER,
1710 NCBI_LASTERROR_STR_WRAPPER>
1711 {
1712 public:
1713 /// Parent class type.
1714 typedef CErrnoTemplExceptionEx<TBase, NCBI_LASTERROR_CODE_WRAPPER, NCBI_LASTERROR_STR_WRAPPER> CParent;
1715
1716 /// Constructor.
1717 CErrnoTemplException_Win<TBase>(const CDiagCompileInfo& info,
1718 const CException* prev_exception,
1719 typename CParent::EErrCode err_code,
1720 const string& message,
1721 EDiagSev severity = eDiag_Error)
1722 : CParent(info, prev_exception, message, NCBI_LASTERROR_CODE_WRAPPER(), severity, 0)
1723 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION_TEMPL_ERRNO(CErrnoTemplException_Win<TBase>, CParent)
1724
1725 protected:
1726 CErrnoTemplException_Win<TBase>(const CDiagCompileInfo& info,
1727 const CException* prev_exception,
1728 const string& message,
1729 EDiagSev severity,
1730 CException::TFlags flags)
1731 : CParent(info, prev_exception, message, NCBI_LASTERROR_CODE_WRAPPER(), severity, flags) {
1732 }
1733 };
1734 #endif
1735
1736 /////////////////////////////////////////////////////////////////////////////
1737
1738
1739 /// Create an instance of the exception with one additional parameter.
1740 #define NCBI_EXCEPTION2_VAR(name, exception_class, err_code, message, extra) \
1741 exception_class name(DIAG_COMPILE_INFO, 0, \
1742 exception_class::err_code, (message), (extra) )
1743
1744 /// Generic macro to make an exception with one additional parameter,
1745 /// given the exception class, error code and message string.
1746 #define NCBI_EXCEPTION2(exception_class, err_code, message, extra) \
1747 NCBI_EXCEPTION2_VAR(NCBI_EXCEPTION_EMPTY_NAME, \
1748 exception_class, err_code, message, extra)
1749
1750 /// Throw exception with extra parameter.
1751 ///
1752 /// Required to throw exceptions with one additional parameter
1753 /// (e.g. positional information for CParseException).
1754 #define NCBI_THROW2(exception_class, err_code, message, extra) \
1755 throw NCBI_EXCEPTION2(exception_class, err_code, message, extra)
1756
1757 /// Re-throw exception with extra parameter.
1758 ///
1759 /// Required to re-throw exceptions with one additional parameter
1760 /// (e.g. positional information for CParseException).
1761 #define NCBI_RETHROW2(prev_exception,exception_class,err_code,message,extra) \
1762 throw exception_class(DIAG_COMPILE_INFO, \
1763 &(prev_exception), exception_class::err_code, (message), (extra))
1764
1765
1766 /// Define exception default with one additional parameter.
1767 ///
1768 /// Required to define exception default with one additional parameter
1769 /// (e.g. derived from CParseException).
1770 #define NCBI_EXCEPTION_DEFAULT2(exception_class, base_class, extra_type) \
1771 public: \
1772 exception_class(const CDiagCompileInfo &info, \
1773 const CException* prev_exception, \
1774 EErrCode err_code,const string& message, \
1775 extra_type extra_param, EDiagSev severity = eDiag_Error) \
1776 : base_class(info, prev_exception, \
1777 (message), extra_param, severity, 0) \
1778 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(exception_class, base_class)
1779
1780 END_NCBI_SCOPE
1781
1782
1783 /* @} */
1784
1785 #endif /* NCBIEXPT__HPP */
1786