149 lines
3.8 KiB
C++
149 lines
3.8 KiB
C++
|
|
/*
|
|
*
|
|
*
|
|
* _INVAR.H
|
|
*
|
|
* Purpose:
|
|
* Template class designed to call parameterized object's Invariant().
|
|
*
|
|
* Overview (see also, usage):
|
|
* 1) declare and define a public const function BOOL Invariant( void ) in your class, with #ifdef DEBUG.
|
|
* 2) in the source: #define DEBUG_CLASSNAME to be the name of the class you're debugging.
|
|
* 3) followed by #include "_invar.h"
|
|
* 4) For every method you wish to check Invariants,
|
|
* insert the _TEST_INVARIANT_ macro once, usually at the beginning of a routine.
|
|
* OPTIONAL: You may optionally use the _TEST_INVARIANT_ON (x) to call x's Invariant directly.
|
|
*
|
|
* Notes:
|
|
* Invariants are designed to be called at the beginning and upon exit of a routine,
|
|
* testing the consistent properties of an object which remain invariant--always the same.
|
|
*
|
|
* Functions may temporarily make an object inconsistent during their execution.
|
|
* A generalized invariant test should not be called during these inconsistent times;
|
|
* if there is a need for a function, which checks invariants, to be called during
|
|
* an inconsistent object state, a solution will need to be designed--the current design
|
|
* does not facilitate this.
|
|
*
|
|
* Because it is entirely possible for an Invariant() function to recurse on itself
|
|
* causing a stack overflow, the template explicitly prevents this from happening.
|
|
* The template also prevents invariant-checking during the processing of Assert(),
|
|
* preventing another type of recursion.
|
|
*
|
|
* Currently Invariant() returns a BOOL, as I think this allows for it to be called
|
|
* from the QuickWatch window under VC++2.0. TRUE indicates that the invariant executed
|
|
* normally.
|
|
*
|
|
* Usage:
|
|
* -the _invariant.h header should only be included in source files. An error will occur
|
|
* if included in another header file. This is to prevent multiple #define DEBUG_CLASSNAME.
|
|
* -Typical #include into a source file looks like this:
|
|
#define DEBUG_CLASSNAME ClassName
|
|
#include "_invar.h"
|
|
* -Typical definition of a class' Invariant() method looks like this:
|
|
#ifdef DEBUG
|
|
public:
|
|
BOOL Invariant( void ) const;
|
|
protected:
|
|
#endif // DEBUG
|
|
* -Typical declaration of Invariant() looks like this:
|
|
#ifdef DEBUG
|
|
|
|
BOOL
|
|
ClassName::Invariant( void ) const
|
|
{
|
|
static LONG numTests = 0;
|
|
numTests++; // how many times we've been called.
|
|
|
|
// do mega-assert checking here.
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif // DEBUG
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* Author:
|
|
* Jon Matousek (jonmat) 5/04/1995
|
|
*
|
|
* Any problems? Please let me know.
|
|
*/
|
|
|
|
#ifndef _INVARIANT_H
|
|
|
|
#define _INVARIANT_H
|
|
|
|
#ifndef DEBUG_CLASSNAME
|
|
prior to including _invariant.h file, you must define DEBUG_CLASSNAME
|
|
to be the name of the class for which you are making Invariant() calls.
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
template < class T >
|
|
class InvariantDebug
|
|
{
|
|
public:
|
|
InvariantDebug ( const T & t) : _t(t)
|
|
{
|
|
static volatile BOOL fRecurse = FALSE;
|
|
|
|
if ( fRecurse ) return; /* Don't allow recursion.*/
|
|
|
|
fRecurse = TRUE;
|
|
|
|
_t.Invariant();
|
|
|
|
fRecurse = FALSE;
|
|
}
|
|
|
|
~InvariantDebug ()
|
|
{
|
|
static volatile BOOL fRecurse = FALSE;
|
|
|
|
if ( fRecurse ) return; /* Don't allow recursion.*/
|
|
|
|
fRecurse = TRUE;
|
|
|
|
_t.Invariant();
|
|
|
|
fRecurse = FALSE;
|
|
}
|
|
|
|
private:
|
|
const T &_t;
|
|
};
|
|
|
|
typedef InvariantDebug<DEBUG_CLASSNAME> DoInvariant;
|
|
|
|
#define _TEST_INVARIANT_ DoInvariant __invariant_tester( *this );
|
|
#define _TEST_INVARIANT_ON(x) \
|
|
{\
|
|
static volatile BOOL fRecurse = FALSE;\
|
|
if (FALSE == fRecurse )\
|
|
{\
|
|
fRecurse = TRUE;\
|
|
(x).Invariant();\
|
|
fRecurse = FALSE;\
|
|
}\
|
|
}
|
|
|
|
#else // DEBUG
|
|
|
|
#define _TEST_INVARIANT_
|
|
#define _TEST_INVARIANT_ON(x)
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
// code that should be at the start and end of all Invariant() methods.
|
|
|
|
#else // INVARIANT_H
|
|
|
|
This file should only be included once per source file. jonmat
|
|
|
|
#endif // INVARIANT_H
|