1 /*
2  * Copyright © 2004 Ondra Kamenik
3  * Copyright © 2019 Dynare Team
4  *
5  * This file is part of Dynare.
6  *
7  * Dynare is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dynare is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 // Exception.
22 
23 /* Within the code we often check some state of variables, typically
24    preconditions or postconditions. If the state is not as required, it
25    is worthless to continue, since this means some fatal error in
26    algorithms. In this case we raise an exception which can be caught at
27    some higher level. This header file defines a simple infrastructure
28    for this. */
29 
30 #ifndef TL_EXCEPTION_H
31 #define TL_EXCEPTION_H
32 
33 #include <iostream>
34 #include <utility>
35 #include <string>
36 
37 /* The basic idea of raising an exception if some condition fails is that the
38    conditions is checked only if required. We define global TL_DEBUG macro
39    which is integer and says, how many debug messages the programm has to emit.
40    We also define TL_DEBUG_EXCEPTION which says, for what values of TL_DEBUG we
41    will check for conditions of the exceptions. If the TL_DEBUG is equal or
42    higher than TL_DEBUG_EXCEPTION, the exception conditions are checked.
43 
44    We define TL_RAISE, and TL_RAISE_IF macros which throw an instance of
45    TLException (only if TL_DEBUG >= TL_DEBUG_EXCEPTION for the latter). The
46    first is unconditional throw, the second is conditioned by a given
47    expression. Note that if TL_DEBUG < TL_DEBUG_EXCEPTION then the code is
48    compiled but evaluation of the condition is passed. If code is optimized,
49    the optimizer also passes evaluation of TL_DEBUG and TL_DEBUG_EXCEPTION
50    comparison (I hope).
51 
52    We provide default values for TL_DEBUG and TL_DEBUG_EXCEPTION. */
53 
54 #ifndef TL_DEBUG_EXCEPTION
55 # define TL_DEBUG_EXCEPTION 1
56 #endif
57 
58 #ifndef TL_DEBUG
59 # define TL_DEBUG 0
60 #endif
61 
62 #define TL_RAISE(mes)                           \
63   throw TLException(__FILE__, __LINE__, mes)
64 
65 #define TL_RAISE_IF(expr, mes)                                          \
66   if (TL_DEBUG >= TL_DEBUG_EXCEPTION && (expr)) throw TLException(__FILE__, __LINE__, mes);
67 
68 /* Primitive exception class containing file name, line number and message. */
69 
70 class TLException
71 {
72   const std::string fname;
73   int lnum;
74 public:
75   const std::string message;
TLException(std::string fname_arg,int lnum_arg,std::string message_arg)76   TLException(std::string fname_arg, int lnum_arg, std::string message_arg)
77     : fname{std::move(fname_arg)},
78       lnum{lnum_arg},
79       message{std::move(message_arg)}
80   {
81   }
82   virtual ~TLException() = default;
83   virtual void
print() const84   print() const
85   {
86     std::cout << "At " << fname << ':' << lnum << ':' << message << std::endl;
87   }
88 };
89 
90 #endif
91