Simbody 3.7
Loading...
Searching...
No Matches
ExceptionMacros.h
Go to the documentation of this file.
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
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
Mandatory first inclusion for any Simbody source or header file.