1 /**
2  * UGENE - Integrated Bioinformatics Tools.
3  * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4  * http://ugene.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 
22 /**
23     A framework to check, trace and recover from error situation in release mode.
24     The logic is similar to usual assertions in debug mode but in
25     release mode the check is performed and if not passed - the error message
26     is dumped to log. This log can be analyzed and sent as a part of crash handler report
27 
28     NOTE: all checks below work in release mode. Be careful not to make code slow!
29 */
30 #ifndef _U2_SAFE_POINTS_
31 #define _U2_SAFE_POINTS_
32 
33 #include <assert.h>
34 
35 #include <U2Core/Log.h>
36 
37 /**
38     Recover utility. Must be used when code tries to recover from invalid internal state
39     by returning from the method some default value.
40     Traces the message to log. Asserts in debug mode.
41 
42     Warning: never use this function as a simple check since it stops application execution in debug mode
43             use CHECK_OP instead
44 */
45 #define SAFE_POINT(condition, message, result) \
46     if (Q_UNLIKELY(!(condition))) { \
47         U2::coreLog.error(QString("Trying to recover from error: %1 at %2:%3").arg(message).arg(__FILE__).arg(__LINE__)); \
48         assert(condition); \
49         return result; \
50     }
51 
52 /**
53     Recover utility. Must be used when code tries to recover from invalid internal state
54     by returning from the method some default value.
55     Dumps the message to the error-level log. Asserts in debug mode.
56 
57     Warning: never use this function as a simple check since it stops application execution in debug mode
58     use CHECK_OP instead
59 
60 */
61 #define SAFE_POINT_OP(os, result) \
62     if (Q_UNLIKELY(os.hasError())) { \
63         U2::coreLog.error(QString("Trying to recover from error: %1 at %2:%3").arg(os.getError()).arg(__FILE__).arg(__LINE__)); \
64         assert(0); \
65         return result; \
66     }
67 
68 /**
69     Recover utility. Must be used when code tries to recover from invalid internal state
70     by returning from the method some default value.
71     Asserts in debug mode. Performs extra recovery op in release
72 
73     Warning: never use this function as a simple check since it stops application execution in debug mode
74             use CHECK_OP instead
75 */
76 #define SAFE_POINT_EXT(condition, extraOp, result) \
77     if (Q_UNLIKELY(!(condition))) { \
78         assert(condition); \
79         extraOp; \
80         return result; \
81     }
82 
83 /**
84     FAIL utility. Same as SAFE_POINT but uses unconditional fail.
85     Can be used in code that must be unreachable
86 */
87 #define FAIL(message, result) \
88     U2::coreLog.error(QString("Trying to recover from error: %1 at %2:%3").arg(message).arg(__FILE__).arg(__LINE__)); \
89     assert(0); \
90     return result;
91 
92 /**
93     Checks condition is false and returns the result if it is
94 
95     Code style hint: use CHECK macro only to make error processing more compact but not all if {return;} patterns !
96 */
97 #define CHECK(condition, result) \
98     if (!(condition)) { \
99         return result; \
100     }
101 
102 /**
103     Checks condition is false and performs a sequence of operations if it is.
104 
105     Code style hint: use CHECK macro only to make error processing more compact but not all if {operation1; operation2;} patterns !
106 */
107 #define CHECK_OPERATIONS(condition, extraOp1, extraOp2) \
108     if (!(condition)) { \
109         extraOp1; \
110         extraOp2; \
111     }
112 
113 /**
114     Checks condition is false and performs an operation if it is.
115 
116     Code style hint: use CHECK macro only to make error processing more compact but not all if {operation;} patterns !
117 */
118 #define CHECK_OPERATION(condition, extraOp) CHECK_OPERATIONS(condition, extraOp, )
119 
120 /**
121     Checks condition is false and breaks if it is.
122 
123     Code style hint: use CHECK macro only to make error processing more compact but not all if {break;} patterns !
124 */
125 #define CHECK_BREAK(condition) CHECK_OPERATION(condition, break)
126 
127 /**
128     Checks condition is false and continue the cycle if it is.
129 */
130 #define CHECK_CONTINUE(condition) CHECK_OPERATION(condition, continue)
131 
132 /**
133     Checks condition is false and breaks if it is.
134     Before breaking the 'extraOp' operation is performed (for example logging)
135 
136     Code style hint: use CHECK macro only to make error processing more compact but not all if {operation; break;} patterns !
137 */
138 #define CHECK_EXT_BREAK(condition, extraOp) CHECK_OPERATIONS(condition, extraOp, break)
139 
140 /**
141     Checks condition is false and returns the result if it is.
142     Before the result is returned the 'extraOp' operation is performed (for example logging)
143 
144     Code style hint: use CHECK macro only to make error processing more compact but not all if {return;} patterns !
145 */
146 #define CHECK_EXT(condition, extraOp, result) \
147     if (!(condition)) { \
148         extraOp; \
149         return result; \
150     }
151 
152 /**
153     Checks that operation is neither not failed nor canceled and returns the result if it does
154 */
155 #define CHECK_OP(os, result) CHECK(!os.isCoR(), result)
156 
157 /**
158     Checks that operation is neither not failed nor canceled and breaks if it does
159 */
160 #define CHECK_OP_BREAK(os) CHECK_BREAK(!os.isCoR())
161 
162 /**
163     Checks that operation is neither failed nor canceled and returns the result if it does.
164     Before the result is returned the 'extraOp' operation is performed (for example logging)
165 */
166 #define CHECK_OP_EXT(os, extraOp, result) CHECK_EXT(!(os.isCoR()), extraOp, result)
167 
168 #endif
169