Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound 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