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