Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Examples

Assertion.hpp

00001 #if !defined (__ASSERTION_HPP) 00002 #define __ASSERTION_HPP 00003 00004 /* 00005 CoreLinux++ 00006 Copyright (C) 1999 CoreLinux Consortium 00007 00008 The CoreLinux++ Library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. 00012 00013 The CoreLinux++ Library Library is distributed in the hope that it will 00014 be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public 00019 License along with the GNU C Library; see the file COPYING.LIB. If not, 00020 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00021 Boston, MA 02111-1307, USA. 00022 */ 00023 00024 00025 /* 00026 Assertion is the exception created when an assertion fails. It contains 00027 type information so that clients may filter the types of assertion 00028 violations that they catch. There are several types of assertion: 00029 00030 ASSERT( bool ) Enabled by #define ALL_ASSERTIONS. It is only used 00031 inside the INVARIANT clause of a class declaration. 00032 00033 REQUIRE( bool ) Enabled by #define ALL_ASSERTIONS or 00034 #define ASSERT_REQUIRE. This macro is used to 00035 check precondtions for a function. If disabled 00036 the macro is compiled away. 00037 00038 ENSURE( bool ) Enabled by #define ALL_ASSERTIONS or 00039 #define ASSERT_ENSURE. This macro is used to check 00040 postconditions. If disabled the macro is compiled 00041 away. 00042 00043 CHECK( bool ) Enabled by #define ALL_ASSERTIONS or 00044 #define ASSERT_CHECK. This macro is used to check 00045 assumptions or to check calls to external functions 00046 in the OS. Unlike REQUIRE and ENSURE when disabled 00047 this macro expands to: if( !( exp )) {;} else 00048 This expansion allows calls such as: 00049 CHECK( DosSubAllocMem( ... ) == 0 ); 00050 to not be compiled away. 00051 00052 CHECK_INVARIANT Enabled by #define ALL_ASSERTIONS. This macro is 00053 used to validate that the class INVARIANT still 00054 holds. The INVARIANT must hold after construction 00055 and at the end of any public member function. In 00056 order to use this assertion the class must have an 00057 INVARIANT ... END_INVARIANT section in the class 00058 definition. If ALL_ASSERTIONS is not defined then 00059 this macro expands to nothing. 00060 00061 NEVER_GET_HERE This macro is always enabled and throws an assertion 00062 if it is ever executed. It should be used to make 00063 explicit to the reader that all cases have been 00064 accounted for in a switch or if ... else if ... else 00065 block. 00066 00067 Typically the programmer defines ALL_ASSERTIONS during development and 00068 reduces assertion levels to ASSERT_REQUIRE at beta and even into release. 00069 00070 In addition to the assertions there are several helper macros that allow 00071 for class INVARIANTs and the logic predicates "for all" and "there exists". 00072 There is also the USES_OLD macro which allows changes in a class to be 00073 checked against the original version of the class. 00074 00075 BASE_INVARIANT( BaseClass ) Can only be used in the INVARIANT clause 00076 of a class definition. This expands to call the 00077 INVARIANT of one of the base classes in the 00078 current class. Expands to: BaseClass::INVARIANT() 00079 00080 INVARIANT Can only be used inside a class definition. This 00081 should be the last thing in the class and should 00082 state the conditions that hold when the class is 00083 correct. The only statements allowed in the 00084 INVARIANT are BASE_INVARIANT and ASSERT. 00085 For example an ordered array class may 00086 look like: 00087 00088 class OrderedArray<T> : public Vector 00089 { 00090 public: 00091 Array( int size ) : 00092 Vector(), 00093 theSize( size ), 00094 theArray( new T[ size ] ); 00095 { 00096 orderTheArray(); 00097 00098 CHECK_INVARIANT; 00099 } 00100 00101 virtual !Array(); 00102 00103 // other operations. 00104 00105 private: 00106 int theSize; 00107 T * theArray; 00108 00109 INVARIANT 00110 BASE_INVARIANT( Vector ); 00111 00112 // Array is sorted in ascending order. 00113 ASSERT( FORALL(( int i = 1; i < theSize; i++ ), 00114 theArray[i-1] <= theArray[i] )); 00115 END_INVARIANT 00116 }; // end class OrderedArray<T> 00117 00118 00119 END_INVARIANT Used to terminate the INVARIANT clause in a class 00120 definition. 00121 00122 USES_OLD( Type ) Creates a copy of the current object called old 00123 which can then be used in assertions to check 00124 those attributes between the new object and old. 00125 Any function which needs old must declare this 00126 at the start of the function. The object must 00127 be able to copy itself deeply for this to work 00128 correctly. Only creates old if ALL_ASSERTIONS or 00129 ASSERT_ENSURE is defined. 00130 WARNING: old should only be used by the ENSURE 00131 macro. 00132 00133 old variable created by the USES_OLD macro. A typical 00134 use would be: 00135 00136 void List::addItem( item ) 00137 { 00138 ... 00139 ENSURE( size() == old.size() + 1 ); 00140 } 00141 00142 bool FORALL(( for-specification ), condition ) 00143 00144 Only expands if ALL_ASSERITONS is defined, and can only 00145 be used in assertions. If ALL_ASSERTIONS is not defined 00146 it becomes the value True. If expanded it becomes 00147 equivalent to: 00148 00149 REQUIRE( FORALL(( int i = 0; i < 10; i++ ), x[i] <= x[0] )); 00150 00151 REQUIRE( tempForAll() ); 00152 00153 bool tempForAll() 00154 { 00155 bool result = True; 00156 for( int i = 0; i < 10; i++ ) 00157 if( !( x[i] <= x[0] )) 00158 { 00159 result = False; 00160 break; 00161 } 00162 return result; 00163 } 00164 00165 Be very carefull using this macro since errors 00166 in the for specification or condition can be very difficult 00167 to find. Also note that the condition can be another 00168 FORALL or an EXISTS. 00169 00170 bool EXISTS((for-specification), condition ) 00171 00172 Only expands if ALL_ASSERTIONS is defined, otherwise 00173 becomes the value True. Returns True as soon as the 00174 condition is met. If all iterations fail then the 00175 macro fails. When expanded it becomes equivalent to: 00176 00177 ENSURE( EXISTS((int i = 0; i<10; i++), x[i] == old.x[i] )); 00178 ENSURE( tempExists() ); 00179 00180 bool tempExists() 00181 { 00182 bool result; 00183 for( int i = 0; i < 10; i++ ) 00184 if( x[i] == old.x[i] ) 00185 { 00186 result = True; 00187 break; 00188 } 00189 return result; 00190 } 00191 00192 00193 The assertion mechanism also supports two functions; assertionFailed() 00194 and assertLoopDebugFunction(). The first is called when an assertion 00195 fails and after the assertion exception has been built. The second 00196 one is called if FORALL or EXISTS fail. These functions are a handy 00197 place to set breakpoints during debugging. They are implemented in 00198 Assertion.cpp 00199 00200 See also: Object Oriented Software Construction 00201 Bertrand Meyer. 00202 Prentice Hall, Englewood Cliffs NJ., 1988. 00203 00204 C/C++ Users Journal October 1994 pages 21 - 37 00205 00206 */ 00207 00208 #if !defined IN_COMMON_HPP 00209 #error Assertion.hpp is included by Common.hpp only. 00210 #endif 00211 00212 namespace corelinux 00213 { 00214 // Standard class Declarations 00215 00216 DECLARE_CLASS( Assertion ); 00217 00218 // These macros are called when an assertion fails or a FORALL or EXISTS 00219 // test fails respectively. They provide a convienent place to set a 00220 // breakpoint during debugging. 00221 // 00222 00223 Long assertionFailed( AssertionCref rAssertion ); 00224 void assertLoopDebugFunction( void ); 00225 00226 // 00227 // Static variables needed by the assertion macros. 00228 // 00229 00230 static Long asstInvert = 0; 00231 static Long asstResult = 0; 00232 static Long asstEval = 0; 00233 static Long asstShortCut = 0; 00234 static Long asstZero = 0; 00235 00236 static struct AssertCt 00237 { 00238 AssertCt( void ) 00239 { 00240 asstInvert = asstResult = asstEval = asstShortCut = asstZero = 0; 00241 } 00242 // empty 00243 } asstCt; 00244 00245 00246 // 00247 // Typedefs and Macros 00248 // 00249 00250 00251 #define paste(a,b) a##b 00252 #define paste3(a,b,c) a##b##c 00253 00254 00255 #if defined ALL_ASSERTIONS || defined ASSERT_REQUIRE 00256 #define REQUIRE( exp ) \ 00257 IGNORE_RETURN ( \ 00258 asstResult = asstZero || exp, \ 00259 asstResult || assertionFailed( Assertion( Assertion::REQUIRE, \ 00260 TEXT( #exp ), \ 00261 LOCATION \ 00262 )) ) 00263 00264 #else 00265 #define REQUIRE( exp ) 00266 #endif // defined ALL_ASSERTIONS || ASSERT_REQUIRE 00267 00268 #if defined ALL_ASSERTIONS || defined ASSERT_ENSURE 00269 #define ENSURE( exp ) \ 00270 IGNORE_RETURN ( \ 00271 asstResult = asstZero || exp, \ 00272 asstResult || assertionFailed( Assertion( Assertion::ENSURE, \ 00273 TEXT( #exp ), \ 00274 LOCATION \ 00275 )) ) 00276 00277 #else 00278 #define ENSURE( exp ) 00279 #endif // defined ALL_ASSERTIONS || ASSERT_ENSURE 00280 00281 #if defined ALL_ASSERTIONS || defined ASSERT_CHECK 00282 #define CHECK( exp ) \ 00283 IGNORE_RETURN ( \ 00284 asstResult = asstZero || exp, \ 00285 asstResult || assertionFailed( Assertion( Assertion::CHECK, \ 00286 paste3( \ 00287 TEXT("CHECK( "), \ 00288 TEXT( #exp ), \ 00289 TEXT(" )") \ 00290 ), \ 00291 LOCATION )) ) 00292 00293 #else 00294 #define CHECK( exp ) 00295 #endif // defined ALL_ASSERTIONS || ASSERT_CHECK 00296 00297 00298 #define NEVER_GET_HERE \ 00299 assertionFailed( Assertion( Assertion::NEVERGETHERE, \ 00300 TEXT("NEVER_GET_HERE"), \ 00301 LOCATION )) 00302 00303 // 00304 // Macros that support class INVARIANTs. 00305 // 00306 00307 #if defined ALL_ASSERTIONS 00308 #define INVARIANT \ 00309 protected: \ 00310 virtual void invariant(void) const { Short executingInvariant = 1; 00311 #define END_INVARIANT } 00312 #define CHECK_INVARIANT invariant() 00313 #else 00314 #define INVARIANT paste(/, *) 00315 #define END_INVARIANT 00316 #define CHECK_INVARIANT 00317 #endif 00318 00319 /* 00320 paste3( \ 00321 TEXT("STDASSERT( "), \ 00322 TEXT( #exp ), \ 00323 TEXT(" )") \ 00324 ), \ 00325 */ 00326 00327 #if defined ALL_ASSERTIONS 00328 #define STDASSERT( exp ) \ 00329 if( executingInvariant ) \ 00330 { \ 00331 asstResult = asstZero || exp, \ 00332 asstResult || \ 00333 assertionFailed( Assertion( Assertion::ASSERT, \ 00334 TEXT( #exp ), \ 00335 LOCATION )); \ 00336 } \ 00337 else \ 00338 { \ 00339 throw Exception( \ 00340 TEXT("STDASSERT used outside of INVARIANT"), LOCATION ); \ 00341 } 00342 #else 00343 #define STDASSERT( exp ) 00344 #endif // defined ALL_ASSERTIONS 00345 00346 #if defined ALL_ASSERTIONS 00347 #define BASE_INVARIANT( ClassType ) \ 00348 if( executingInvariant ) \ 00349 { \ 00350 ClassType::invariant(); \ 00351 } \ 00352 else \ 00353 { \ 00354 throw Exception( \ 00355 TEXT("BASE_INVARIANT used outside of an INVARIANT"), \ 00356 LOCATION, \ 00357 Exception::ProcessTerminate); \ 00358 } 00359 00360 #else 00361 #define BASE_INVARIANT( ClassType ) 00362 #endif 00363 00364 // 00365 // Macro that defines "old". 00366 // 00367 00368 #if defined ALL_ASSERTIONS || defined ASSERT_ENSURE 00369 #define USES_OLD( Type ) Type old( clself ) 00370 #else 00371 #define USES_OLD( Type ) 00372 #endif 00373 00374 // 00375 // Macros for FORALL and EXISTS 00376 // 00377 00378 #define ASSERT_LOOP( asstFor, asstAll, asstCond ) \ 00379 anAssertCt(); \ 00380 { \ 00381 volatile x = 0; \ 00382 Long asstShortCut; \ 00383 if( asstDoEval( asstShortCut )) \ 00384 { \ 00385 Long asstInvert = ::asstInvert; \ 00386 asstResult = asstAll; \ 00387 for asstFor \ 00388 { \ 00389 asstResult = x || asstCond; \ 00390 if( asstResult != asstAll ) break; \ 00391 } \ 00392 if(asstInvert) asstResult = !asstResult; \ 00393 } \ 00394 ::asstShortCut = asstShortCut; \ 00395 if( asstResult == 0 ) assertLoopDebugFunction(); \ 00396 } \ 00397 asstResult = ::asstShortCut ? asstResult : asstResult 00398 00399 #if defined ALL_ASSERTIONS 00400 #define FORALL(asstFor, asstCond ) ASSERT_LOOP( asstFor, 1, asstCond ) 00401 #define EXISTS(asstFor, asstCond ) ASSERT_LOOP( asstFor, 0, asstCond ) 00402 #else 00403 #define FORALL(asstFor, asstCond ) True 00404 #define EXISTS(asstFor, asstCond ) True 00405 #endif 00406 00407 // 00408 // Constants 00409 // 00410 00411 00412 // 00413 // Helper Classes (including exceptions). 00414 // 00415 00423 class Assertion : public Exception 00424 { 00425 // 00426 // Note that a private default constructor is not needed 00427 // beause Exception's default constructor is private. 00428 // 00429 00430 public: 00431 00433 00434 enum Type 00435 { 00436 REQUIRE, 00437 ENSURE, 00438 CHECK, 00439 ASSERT, 00440 NEVERGETHERE 00441 }; 00442 00443 public: 00444 00453 Assertion 00454 ( 00455 Type aType, 00456 CharPtr aReason, 00457 CharPtr aFile, 00458 LineNum aLine 00459 ); 00460 00466 Assertion( AssertionCref rExcept ); 00467 00469 00470 virtual ~Assertion( void ); 00471 00472 // 00473 // Operator overloads 00474 // 00475 00482 AssertionRef operator=( AssertionCref ); 00483 00490 bool operator==( AssertionCref ); 00491 00492 // 00493 // Accessors 00494 // 00495 00501 Assertion::Type getType( void ) const; 00502 00503 private: 00504 00505 Assertion::Type theType; 00506 }; 00507 00508 // 00509 // Inline Functions 00510 // 00511 00512 inline AssertCt & anAssertCt( void ) 00513 { 00514 asstInvert = 0; 00515 asstEval = 1; 00516 return asstCt; 00517 }; 00518 00519 inline Long asstDoEval( Long & asstShortCut ) 00520 { 00521 Long result = asstEval; 00522 00523 asstShortCut = !asstEval && asstResult; 00524 00525 asstEval = 0; 00526 00527 return result; 00528 } 00529 00530 inline const AssertCt & operator !( const AssertCt & a ) 00531 { 00532 asstInvert = !asstInvert; 00533 return a; 00534 } 00535 00536 inline Long operator &&( Long left, const AssertCt & ) 00537 { 00538 asstEval = left; 00539 return left; 00540 } 00541 00542 inline Long operator ||( int left, const AssertCt & ) 00543 { 00544 asstEval = !left; 00545 return left; 00546 } 00547 00548 } 00549 00550 #endif // !defined ASSERT_HPP 00551 00552 /* 00553 Common rcs information do not modify 00554 $Author: prudhomm $ 00555 $Revision: 1.1 $ 00556 $Date: 2000/04/23 20:43:13 $ 00557 $Locker: $ 00558 */ 00559

This is the CoreLinux++ reference manual
Provided by The CoreLinux Consortium