1 #ifndef SimTK_SimTKCOMMON_EXCEPTION_MACROS_H_
2 #define SimTK_SimTKCOMMON_EXCEPTION_MACROS_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                       Simbody(tm): SimTKcommon                             *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2005-12 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors:                                                              *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /** @file
28  * This file contains macros which are convenient to use for
29  * sprinkling error checking around liberally in SimTK programs, a
30  * practice which is highly encouraged. You can think of this as
31  * a generalization of the standard assert() macro. By default,
32  * these macros evaporate completely in a release build, but are
33  * present in any debug build. Macros are also provided which are
34  * always present in cases where the error checking is not a
35  * performance problem, and those should be used in preference
36  * to the disappearing ones when appropriate. Also, you can force
37  * the disappearing macros to remain present on a file-by-file basis,
38  * primarily for use in debugging those annoying problems which only
39  * occur in release builds and won't reproduce in a debug build.
40  *
41  * Most macros have a similar structure, something like this:
42  * <pre>
43  *    SimTK_MACRONAME[nargs][_ALWAYS](cond, printfString [, args...])
44  * for example
45  *    SimTK_ASSERT3(lower<count && count<upper,
46  *                  "expected %d < count < %d but count=%d",
47  *                  lower, upper, count);
48  * or
49  *    SimTK_ASSERT3_ALWAYS(lower<count && count<upper,
50  *                  "expected %d < count < %d but count=%d",
51  *                  lower, upper, count);
52  * </pre>
53  * To override the disappearance of the non-ALWAYS macros, your
54  * compilation should define a preprocessor symbols like
55  * SimTK_KEEP_ASSERT, SimTK_KEEP_ERRCHK, etc.
56  *
57  * These macros will also capture the current file name and line
58  * number for reporting to developers when appropriate, and those
59  * with a condition that failed will include the condition in the
60  * message.
61  *
62  * Note that these are *global* symbols, so we use the reserved
63  * SimTK_ name prefix (since we can't use the SimTK:: namespace
64  * for macros) to attempt to avoid pollution of user programs.
65  *
66  * We distinguish between macros which are used as internal
67  * "bugcatchers" and those which are used to report errors to
68  * API users. The C++ exception mechanism is used in both circumstances
69  * but the meaning and intended audience is quite different. Any
70  * macro with 'ASSERT' in the name represents an internal error
71  * which cannot be attributed to user misbehavior. Other macros
72  * are for communicating with users. Those need to be carefully documented
73  * so that users can selectively catch the exceptions when appropriate.
74  */
75 
76 #include "SimTKcommon/internal/common.h"
77 #include "SimTKcommon/internal/Exception.h"
78 
79 #include <string>
80 #include <iostream>
81 #include <exception>
82 
83 // --------------------------------- RANGECHECK --------------------------------
84 // These exceptions are to be used for situations in which a user of a SimTK
85 // API method screws up by providing bad indices or dimensions. These are special
86 // cases of the more general APIARGCHECK macros, providing "canned" error messages
87 // for several common situations. Although there are several different macro
88 // names here, all are controlled by SimTK_KEEP_RANGECHECK to allow enabling of
89 // these index- and size-validating tests together in Release mode.
90 //
91 //   INDEXCHECK: Note that we allow the index to be equal to the lower
92 //     bound (zero) but it must be strictly less than the upper bound.
93 //   SIZECHECK: A size or size expression must be >= 0 and less than OR EQUAL
94 //     to the maximum size.
95 //   SIZECHECK_NONNEG: A size argument must be >= 0.
96 //   VALUECHECK: A floating point is required to be within a certain range.
97 //   VALUECHECK_NONNEG: A floating point argument must be non-negative.
98 //
99 // TODO: SHAPECHECK, DOMAINCHECK
100 // -----------------------------------------------------------------------------
101 
102 // This is a rangecheck that is always present, even in Release mode. This may be
103 // applied both to signed and unsigned types (the latter are always nonnegative) so
104 // to avoid warnings we use the isIndexInRange() method which doesn't perform
105 // a nonnegativity check on unsigned quantities.
106 #define SimTK_INDEXCHECK_ALWAYS(ix,ub,where) \
107     do{if(!isIndexInRange((ix),(ub)))SimTK_THROW5(SimTK::Exception::IndexOutOfRange,   \
108                     #ix,0,(ix),(ub),(where));}while(false)
109 
110 // This is a rangecheck that is always present, even in Release mode. This may be
111 // applied both to signed and unsigned types (the latter are always nonnegative) so
112 // to avoid warnings we use the isSizeInRange() method which doesn't perform
113 // a nonnegativity check on unsigned quantities.
114 #define SimTK_SIZECHECK_ALWAYS(sz,maxsz,where) \
115     do{if(!isSizeInRange((sz),(maxsz)))SimTK_THROW4(SimTK::Exception::SizeOutOfRange,   \
116                     #sz,(sz),(maxsz),(where));}while(false)
117 
118 // This is a rangecheck that is always present, even in Release mode. Use
119 // isNonnegative() here in case sz is an unsigned type to avoid compiler
120 // warning.
121 #define SimTK_SIZECHECK_NONNEG_ALWAYS(sz,where) \
122     do{if(!isNonnegative(sz))SimTK_THROW3(SimTK::Exception::SizeWasNegative,   \
123                     #sz,(sz),(where));}while(false)
124 
125     // Similar checks for floating point values.
126 
127 #define SimTK_VALUECHECK_ALWAYS(lb,val,ub,valName,where) \
128     do{if(!((lb)<=(val)&&(val)<=(ub)))SimTK_THROW5(SimTK::Exception::ValueOutOfRange,   \
129                     (valName),(lb),(val),(ub),(where));}while(false)
130 
131 
132 #define SimTK_VALUECHECK_NONNEG_ALWAYS(val,valName,where) \
133     do{if((val)<0)SimTK_THROW3(SimTK::Exception::ValueWasNegative,   \
134                     (valName),(val),(where));}while(false)
135 
136 
137 
138 #if defined(NDEBUG) && !defined(SimTK_KEEP_RANGECHECK)
139     #define SimTK_INDEXCHECK(ix,ub,where)
140     #define SimTK_SIZECHECK(sz,maxsz,where)
141     #define SimTK_SIZECHECK_NONNEG(sz,where)
142     #define SimTK_VALUECHECK(lb,val,ub,valName,where)
143     #define SimTK_VALUECHECK_NONNEG(val,valName,where)
144 #else
145     #define SimTK_INDEXCHECK(ix,ub,where) SimTK_INDEXCHECK_ALWAYS(ix,ub,where)
146     #define SimTK_SIZECHECK(sz,maxsz,where)  SimTK_SIZECHECK_ALWAYS(sz,maxsz,where)
147     #define SimTK_SIZECHECK_NONNEG(sz,where) SimTK_SIZECHECK_NONNEG_ALWAYS(sz,where)
148     #define SimTK_VALUECHECK(lb,val,ub,valName,where)  SimTK_VALUECHECK_ALWAYS(lb,val,ub,valName,where)
149     #define SimTK_VALUECHECK_NONNEG(val,valName,where) SimTK_VALUECHECK_NONNEG_ALWAYS(val,valName,where)
150 #endif
151 
152 
153 // --------------------------------- STAGECHECK --------------------------------
154 // These exceptions are to be used for situations in which a
155 // user of an API screws up by attempting to access something in the
156 // state before it has been realized to the appropriate stage.
157 //
158 //   STAGECHECK_TOPOLOGY_REALIZED: Check that realizeTopology() has been done
159 //     since the last topological change.
160 //   STAGECHECK_EQ: Check that the current stage is == a particular stage.
161 //   STAGECHECK_GE: Check that the current stage is >= a particular stage.
162 //   STAGECHECK_LT: Check that the current stage is <  a particular stage.
163 //   STAGECHECK_RANGE: Check that lower <= stage <= upper.
164 // -----------------------------------------------------------------------------
165 
166 // These are stagechecks that is always present, even in Release mode.
167 #define SimTK_STAGECHECK_TOPOLOGY_REALIZED_ALWAYS(cond,objType,objName,methodNm)  \
168     do{if(!(cond)) SimTK_THROW3(SimTK::Exception::RealizeTopologyMustBeCalledFirst, \
169         (objType),(objName),(methodNm));}while(false)
170 #define SimTK_STAGECHECK_TOPOLOGY_VERSION_ALWAYS(sysTopoVersion,            \
171                                 stateTopoVersion,objType,objName,methodNm)  \
172     do{if((stateTopoVersion)!=(sysTopoVersion))                             \
173         SimTK_THROW5(SimTK::Exception::StateAndSystemTopologyVersionsMustMatch, \
174         (objType),(objName),(methodNm),                     \
175         (int)(sysTopoVersion),(int)(stateTopoVersion));}    \
176     while(false)
177 #define SimTK_STAGECHECK_EQ_ALWAYS(currentStage,targetStage,methodNm) \
178     do{if((currentStage)!=(targetStage)) SimTK_THROW3(SimTK::Exception::StageIsWrong,   \
179         (currentStage),(targetStage),(methodNm));}while(false)
180 #define SimTK_STAGECHECK_GE_ALWAYS(currentStage,targetStage,methodNm) \
181     do{if(!((currentStage)>=(targetStage))) SimTK_THROW3(SimTK::Exception::StageTooLow,   \
182         (currentStage),(targetStage),(methodNm));}while(false)
183 #define SimTK_STAGECHECK_LT_ALWAYS(currentStage,targetStage,methodNm) \
184     do{if((currentStage)>=(targetStage)) SimTK_THROW3(SimTK::Exception::StageTooHigh,   \
185         (currentStage),(targetStage),(methodNm));}while(false)
186 #define SimTK_STAGECHECK_RANGE_ALWAYS(lower,current,upper,methodNm) \
187     do{if(!((lower)<=(current)&&(current)<=(upper))) SimTK_THROW4(SimTK::Exception::StageOutOfRange,   \
188         (lower),(current),(upper),(methodNm));}while(false)
189 
190 // This one is present only in Debug mode or if SimTK_KEEP_STAGECHECK is explicitly defined.
191 #if defined(NDEBUG) && !defined(SimTK_KEEP_STAGECHECK)
192     #define SimTK_STAGECHECK_TOPOLOGY_REALIZED(cond,objType,objName,methodName)
193     #define SimTK_STAGECHECK_TOPOLOGY_VERSIONS(sysTopoVersion,stateTopoVersion,\
194                                                objType,objName,methodNm)
195     #define SimTK_STAGECHECK_EQ(currentStage,targetStage,methodNm)
196     #define SimTK_STAGECHECK_GE(currentStage,targetStage,methodNm)
197     #define SimTK_STAGECHECK_LT(currentStage,targetStage,methodNm)
198     #define SimTK_STAGECHECK_RANGE(lower,current,upper,methodNm)
199 #else
200     #define SimTK_STAGECHECK_TOPOLOGY_REALIZED(cond,objType,objName,methodName) \
201         SimTK_STAGECHECK_TOPOLOGY_REALIZED_ALWAYS(cond,objType,objName,methodName)
202     #define SimTK_STAGECHECK_TOPOLOGY_VERSION(sysTopoVersion,stateTopoVersion, \
203                                               objType,objName,methodNm)  \
204         SimTK_STAGECHECK_TOPOLOGY_VERSION_ALWAYS(sysTopoVersion,stateTopoVersion,\
205                                                  objType,objName,methodNm)
206     #define SimTK_STAGECHECK_EQ(currentStage,targetStage,methodNm) \
207         SimTK_STAGECHECK_EQ_ALWAYS(currentStage,targetStage,methodNm)
208     #define SimTK_STAGECHECK_GE(currentStage,targetStage,methodNm) \
209         SimTK_STAGECHECK_GE_ALWAYS(currentStage,targetStage,methodNm)
210     #define SimTK_STAGECHECK_LT(currentStage,targetStage,methodNm) \
211         SimTK_STAGECHECK_LE_ALWAYS(currentStage,targetStage,methodNm)
212     #define SimTK_STAGECHECK_RANGE(lower,current,upper,methodNm) \
213         SimTK_STAGECHECK_RANGE_ALWAYS(lower,current,upper,methodNm)
214 #endif
215 
216 // -------------------------------- APIARGCHECK --------------------------------
217 // These should be used to catch all manner of problems with the arguments passed
218 // in an API user's call to a method that is part of a SimTK API. Note that these
219 // are intended for direct consumption by an application programmer using a SimTK
220 // API, so should be wordy and helpful. These macros accept printf-style format
221 // strings and arguments of whatever are the appropriate types for those formats.
222 // -----------------------------------------------------------------------------
223 
224 #define SimTK_APIARGCHECK_ALWAYS(cond,className,methodName,msg)     \
225     do{if(!(cond))SimTK_THROW4(SimTK::Exception::APIArgcheckFailed, \
226               #cond,(className),(methodName),(msg));                \
227     }while(false)
228 #define SimTK_APIARGCHECK1_ALWAYS(cond,className,methodName,fmt,a1) \
229     do{if(!(cond))SimTK_THROW5(SimTK::Exception::APIArgcheckFailed, \
230               #cond,(className),(methodName),(fmt),(a1));           \
231     }while(false)
232 #define SimTK_APIARGCHECK2_ALWAYS(cond,className,methodName,fmt,a1,a2)      \
233     do{if(!(cond))SimTK_THROW6(SimTK::Exception::APIArgcheckFailed,         \
234               #cond,(className),(methodName),(fmt),(a1),(a2));              \
235     }while(false)
236 #define SimTK_APIARGCHECK3_ALWAYS(cond,className,methodName,fmt,a1,a2,a3)   \
237     do{if(!(cond))SimTK_THROW7(SimTK::Exception::APIArgcheckFailed,         \
238               #cond,(className),(methodName),(fmt),(a1),(a2),(a3));         \
239     }while(false)
240 #define SimTK_APIARGCHECK4_ALWAYS(cond,className,methodName,fmt,a1,a2,a3,a4)    \
241     do{if(!(cond))SimTK_THROW8(SimTK::Exception::APIArgcheckFailed,             \
242               #cond,(className),(methodName),(fmt),(a1),(a2),(a3),(a4));        \
243     }while(false)
244 #define SimTK_APIARGCHECK5_ALWAYS(cond,className,methodName,fmt,a1,a2,a3,a4,a5) \
245     do{if(!(cond))SimTK_THROW9(SimTK::Exception::APIArgcheckFailed,             \
246               #cond,(className),(methodName),(fmt),(a1),(a2),(a3),(a4),(a5));   \
247     }while(false)
248 
249 #if defined(NDEBUG) && !defined(SimTK_KEEP_APIARGCHECK)
250     #define SimTK_APIARGCHECK(cond,className,methodName,msg)
251     #define SimTK_APIARGCHECK1(cond,className,methodName,fmt,a1)
252     #define SimTK_APIARGCHECK2(cond,className,methodName,fmt,a1,a2)
253     #define SimTK_APIARGCHECK3(cond,className,methodName,fmt,a1,a2,a3)
254     #define SimTK_APIARGCHECK4(cond,className,methodName,fmt,a1,a2,a3,a4)
255     #define SimTK_APIARGCHECK5(cond,className,methodName,fmt,a1,a2,a3,a4,a5)
256 #else
257     #define SimTK_APIARGCHECK(cond,className,methodName,msg)                       \
258         SimTK_APIARGCHECK_ALWAYS(cond,className,methodName,msg)
259     #define SimTK_APIARGCHECK1(cond,className,methodName,fmt,a1)                   \
260         SimTK_APIARGCHECK1_ALWAYS(cond,className,methodName,fmt,a1)
261     #define SimTK_APIARGCHECK2(cond,className,methodName,fmt,a1,a2)                \
262         SimTK_APIARGCHECK2_ALWAYS(cond,className,methodName,fmt,a1,a2)
263     #define SimTK_APIARGCHECK3(cond,className,methodName,fmt,a1,a2,a3)             \
264         SimTK_APIARGCHECK3_ALWAYS(cond,className,methodName,fmt,a1,a2,a3)
265     #define SimTK_APIARGCHECK4(cond,className,methodName,fmt,a1,a2,a3,a4)          \
266         SimTK_APIARGCHECK4_ALWAYS(cond,className,methodName,fmt,a1,a2,a3,a4)
267     #define SimTK_APIARGCHECK5(cond,className,methodName,fmt,a1,a2,a3,a4,a5)       \
268         SimTK_APIARGCHECK5_ALWAYS(cond,className,methodName,fmt,a1,a2,a3,a4,a5)
269 #endif
270 
271 
272 // ----------------------------------- ERRCHK ----------------------------------
273 // ERRCHK: these should be used to catch all manner of problems that occur
274 // during execution of an API user's request by a method that is part of
275 // a SimTK API. Note that these are intended for direct consumption by
276 // an application programmer using a SimTK API, so should be wordy and
277 // helpful. These macros accept printf-style format strings and arguments
278 // of whatever are the appropriate types for those formats.
279 // -----------------------------------------------------------------------------
280 
281 #define SimTK_ERRCHK_ALWAYS(cond,whereChecked,msg)              \
282     do{if(!(cond))SimTK_THROW3(SimTK::Exception::ErrorCheck,    \
283               #cond,(whereChecked),(msg));                      \
284     }while(false)
285 #define SimTK_ERRCHK1_ALWAYS(cond,whereChecked,fmt,a1)          \
286     do{if(!(cond))SimTK_THROW4(SimTK::Exception::ErrorCheck,    \
287               #cond,(whereChecked),(fmt),(a1));                 \
288     }while(false)
289 #define SimTK_ERRCHK2_ALWAYS(cond,whereChecked,fmt,a1,a2)       \
290     do{if(!(cond))SimTK_THROW5(SimTK::Exception::ErrorCheck,    \
291               #cond,(whereChecked),(fmt),(a1),(a2));            \
292     }while(false)
293 #define SimTK_ERRCHK3_ALWAYS(cond,whereChecked,fmt,a1,a2,a3)    \
294     do{if(!(cond))SimTK_THROW6(SimTK::Exception::ErrorCheck,    \
295               #cond,(whereChecked),(fmt),(a1),(a2),(a3));       \
296     }while(false)
297 #define SimTK_ERRCHK4_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4) \
298     do{if(!(cond))SimTK_THROW7(SimTK::Exception::ErrorCheck,    \
299               #cond,(whereChecked),(fmt),(a1),(a2),(a3),(a4));  \
300     }while(false)
301 #define SimTK_ERRCHK5_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5)      \
302     do{if(!(cond))SimTK_THROW8(SimTK::Exception::ErrorCheck,            \
303               #cond,(whereChecked),(fmt),(a1),(a2),(a3),(a4),(a5));     \
304     }while(false)
305 #define SimTK_ERRCHK6_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6)       \
306     do{if(!(cond))SimTK_THROW9(SimTK::Exception::ErrorCheck,                \
307               #cond,(whereChecked),(fmt),(a1),(a2),(a3),(a4),(a5),(a6));    \
308     }while(false)
309 #define SimTK_ERRCHK7_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6,a7)        \
310     do{if(!(cond))SimTK_THROW10(SimTK::Exception::ErrorCheck,                   \
311               #cond,(whereChecked),(fmt),(a1),(a2),(a3),(a4),(a5),(a6),(a7));   \
312     }while(false)
313 
314 #if defined(NDEBUG) && !defined(SimTK_KEEP_ERRCHK)
315     #define SimTK_ERRCHK(cond,whereChecked,msg)
316     #define SimTK_ERRCHK1(cond,whereChecked,fmt,a1)
317     #define SimTK_ERRCHK2(cond,whereChecked,fmt,a1,a2)
318     #define SimTK_ERRCHK3(cond,whereChecked,fmt,a1,a2,a3)
319     #define SimTK_ERRCHK4(cond,whereChecked,fmt,a1,a2,a3,a4)
320     #define SimTK_ERRCHK5(cond,whereChecked,fmt,a1,a2,a3,a4,a5)
321     #define SimTK_ERRCHK6(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6)
322     #define SimTK_ERRCHK7(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6)
323 #else
324     #define SimTK_ERRCHK(cond,whereChecked,msg)                       \
325         SimTK_ERRCHK_ALWAYS(cond,whereChecked,msg)
326     #define SimTK_ERRCHK1(cond,whereChecked,fmt,a1)                   \
327         SimTK_ERRCHK1_ALWAYS(cond,whereChecked,fmt,a1)
328     #define SimTK_ERRCHK2(cond,whereChecked,fmt,a1,a2)                \
329         SimTK_ERRCHK2_ALWAYS(cond,whereChecked,fmt,a1,a2)
330     #define SimTK_ERRCHK3(cond,whereChecked,fmt,a1,a2,a3)             \
331         SimTK_ERRCHK3_ALWAYS(cond,whereChecked,fmt,a1,a2,a3)
332     #define SimTK_ERRCHK4(cond,whereChecked,fmt,a1,a2,a3,a4)          \
333         SimTK_ERRCHK4_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4)
334     #define SimTK_ERRCHK5(cond,whereChecked,fmt,a1,a2,a3,a4,a5)       \
335         SimTK_ERRCHK5_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5)
336     #define SimTK_ERRCHK6(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6)    \
337         SimTK_ERRCHK6_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6)
338     #define SimTK_ERRCHK7(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6,a7) \
339         SimTK_ERRCHK7_ALWAYS(cond,whereChecked,fmt,a1,a2,a3,a4,a5,a6,a7)
340 #endif
341 
342 // ----------------------------------- ASSERT ----------------------------------
343 // ASSERT: use this *only* for internal errors, that is, bugs. This must
344 // not be used to catch usage errors by clients; if you want to catch
345 // user errors use different exceptions.
346 // -----------------------------------------------------------------------------
347 
348 // This is an assertion that is always active, even in Release mode.
349 #define SimTK_ASSERT_ALWAYS(cond,msg) \
350     do{if(!(cond))SimTK_THROW2(SimTK::Exception::Assert,#cond,(msg));}while(false)
351 #define SimTK_ASSERT1_ALWAYS(cond,msg,a1) \
352     do{if(!(cond))SimTK_THROW3(SimTK::Exception::Assert,#cond,(msg),(a1));}while(false)
353 #define SimTK_ASSERT2_ALWAYS(cond,msg,a1,a2) \
354     do{if(!(cond))SimTK_THROW4(SimTK::Exception::Assert,#cond,(msg),(a1),(a2));}while(false)
355 #define SimTK_ASSERT3_ALWAYS(cond,msg,a1,a2,a3) \
356     do{if(!(cond))SimTK_THROW5(SimTK::Exception::Assert,#cond,(msg),(a1),(a2),(a3));}while(false)
357 #define SimTK_ASSERT4_ALWAYS(cond,msg,a1,a2,a3,a4) \
358     do{if(!(cond))SimTK_THROW6(SimTK::Exception::Assert,#cond,(msg),(a1),(a2),(a3),(a4));}while(false)
359 #define SimTK_ASSERT5_ALWAYS(cond,msg,a1,a2,a3,a4,a5) \
360     do{if(!(cond))SimTK_THROW7(SimTK::Exception::Assert,#cond,(msg),(a1),(a2),(a3),(a4),(a5));}while(false)
361 
362 // Note: unlike the system assert() we're putting ours within the header guards.
363 // So if you want to override NDEBUG do it at the *beginning* (that is, before
364 // the first #include or #ifdef) of whatever compilation unit you are fiddling with.
365 #if defined(NDEBUG) && !defined(SimTK_KEEP_ASSERT)
366     #define SimTK_ASSERT(cond,msg)
367     #define SimTK_ASSERT1(cond,msg,a1)
368     #define SimTK_ASSERT2(cond,msg,a1,a2)
369     #define SimTK_ASSERT3(cond,msg,a1,a2,a3)
370     #define SimTK_ASSERT4(cond,msg,a1,a2,a3,a4)
371     #define SimTK_ASSERT5(cond,msg,a1,a2,a3,a4,a5)
372 #else
373     #define SimTK_ASSERT(cond,msg) SimTK_ASSERT_ALWAYS(cond,msg)
374     #define SimTK_ASSERT1(cond,msg,a1) SimTK_ASSERT1_ALWAYS(cond,msg,a1)
375     #define SimTK_ASSERT2(cond,msg,a1,a2) SimTK_ASSERT2_ALWAYS(cond,msg,a1,a2)
376     #define SimTK_ASSERT3(cond,msg,a1,a2,a3) SimTK_ASSERT3_ALWAYS(cond,msg,a1,a2,a3)
377     #define SimTK_ASSERT4(cond,msg,a1,a2,a3,a4) SimTK_ASSERT4_ALWAYS(cond,msg,a1,a2,a3,a4)
378     #define SimTK_ASSERT5(cond,msg,a1,a2,a3,a4,a5) SimTK_ASSERT5_ALWAYS(cond,msg,a1,a2,a3,a4,a5)
379 #endif
380 
381 
382 #endif // SimTK_SimTKCOMMON_EXCEPTION_MACROS_H_
383 
384 
385 
386