Added ability to compare host to memento.
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1017 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
fa3743d524
commit
76aeea2390
1 changed files with 207 additions and 38 deletions
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// The Loki Library
|
// The Loki Library
|
||||||
// Copyright (c) 2008 Rich Sposato
|
// Copyright (c) 2008, 2009 Rich Sposato
|
||||||
// The copyright on this file is protected under the terms of the MIT license.
|
// The copyright on this file is protected under the terms of the MIT license.
|
||||||
//
|
//
|
||||||
// Permission to use, copy, modify, distribute and sell this software for any
|
// Permission to use, copy, modify, distribute and sell this software for any
|
||||||
|
@ -32,15 +32,25 @@ namespace Loki
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @par ContractChecker and StaticChecker Overview
|
/** @par ContractChecker and StaticChecker Overview
|
||||||
The ContractChecker and StaticChecker classes have two purposes:
|
ContractChecker and StaticChecker classes provide a mechanism to enforce
|
||||||
- provide a mechanism by which programmers can determine which functions
|
"Design by Contract" programming practices. According to Design by Contract,
|
||||||
|
each function and class provides a contract with client code. Each contract
|
||||||
|
says:
|
||||||
|
- what operations the class or function performs,
|
||||||
|
- what input it needs,
|
||||||
|
- what output it provides,
|
||||||
|
- what exception safety level it guarantees, and
|
||||||
|
- what constraints it enforces on its data.
|
||||||
|
|
||||||
|
ContractChecker and StaticChecker encourage Design by Contract by:
|
||||||
|
- providing a mechanism by which programmers can determine if functions
|
||||||
violate class/data invariants,
|
violate class/data invariants,
|
||||||
- and determine which exception safety a function provides.
|
- and determining which exception safety level a function provides.
|
||||||
|
|
||||||
@par Class & Data Invariants
|
@par Class & Data Invariants
|
||||||
The ContractChecker and StaticChecker define invariants as "expressions that
|
ContractChecker and StaticChecker define invariants as "expressions that are
|
||||||
are true for particular data". They call a function which returns true if all
|
true for particular data". They call a function which returns true if all data
|
||||||
data are valid, and returns false if any datum is invalid. This is called the
|
are valid, and returns false if any datum is invalid. This is called the
|
||||||
validator function, and the host class or function provides a pointer to it.
|
validator function, and the host class or function provides a pointer to it.
|
||||||
The validator could also assert for any invariant which fails rather than
|
The validator could also assert for any invariant which fails rather than
|
||||||
return false. If the validator is a static member function, you can use it
|
return false. If the validator is a static member function, you can use it
|
||||||
|
@ -68,25 +78,76 @@ namespace Loki
|
||||||
in a valid state if an exception occurs. (Which I call either the no-leak
|
in a valid state if an exception occurs. (Which I call either the no-leak
|
||||||
or no-break guarantee depending on context.)
|
or no-break guarantee depending on context.)
|
||||||
|
|
||||||
@par Writing Your Own Policies
|
@par Provided Exception Policies
|
||||||
|
Loki provides several exception policies for use with ContractChecker.
|
||||||
|
- CheckForNoChangeOrThrow
|
||||||
|
- CheckForNoThrow
|
||||||
|
- CheckForNoChange
|
||||||
|
- CheckForEquality
|
||||||
|
- CheckForNothing
|
||||||
|
Loki also provides these two policies for StaticChecker.
|
||||||
|
- CheckStaticForNoThrow
|
||||||
|
- CheckStaticForNothing
|
||||||
|
|
||||||
|
@par Writing Your Own Policies for ContractChecker
|
||||||
Loki provides several exception policies for ContractChecker. These policies
|
Loki provides several exception policies for ContractChecker. These policies
|
||||||
assert if an object changed or a function threw an exception. If you prefer
|
assert if an object changed or a function threw an exception. If you prefer
|
||||||
policies that log failures to a file, pop-up a message box, notify your unit-
|
policies that log failures to a file, send an email, file a bug report, pop-up
|
||||||
test framework, or whatever else, you can easily write your own policies.
|
a message box, notify your unit-test framework, or whatever else, you can
|
||||||
Your policy class should have two functions, a constructor and a Check
|
easily write your own policies. Please follow these guidelines when writing
|
||||||
function, both of which accept a pointer to const instance of the host class.
|
your own policies:
|
||||||
Your policy class will become a base class of ContractChecker. Check should
|
- Each policy class must provide three public functions, a constructor, a destructor, and a Check function.
|
||||||
return true if all is okay, and false if any failure was detected. Check
|
- The destructor could be implied. (Not actually written, and provided by the compiler.)
|
||||||
should never throw any exceptions since it is called from ContractChecker's
|
- The constructor and Check functions accept a pointer to const instance of the host class.
|
||||||
destructor. You may add other functions to the policy class. This code
|
- Your policy class will become a base class of ContractChecker.
|
||||||
snippet shows the signatures for the two required functions.
|
- Check should return true if all is okay, and false for any failures.
|
||||||
|
- Check should never throw any exceptions since it is called by a destructor.
|
||||||
|
- You may add other functions or features to your policy class.
|
||||||
|
|
||||||
|
@par Using a Memento
|
||||||
|
Sometimes copying or comparing the host object is very expensive. If you do
|
||||||
|
not want ContractChecker to copy the host object, you can provide an optional
|
||||||
|
template parameter called Memento. The memento stores a little information on
|
||||||
|
the host object's state so that when the Host's function ends, ContractChecker
|
||||||
|
will use the memento to determine if the host object changed. A Host class can
|
||||||
|
declare a Memento class as an internal class. These guidelines will help you
|
||||||
|
design a memento class:
|
||||||
|
- Your exception policy's constructor should not copy the host object but use a memento to store info about the host.
|
||||||
|
- The memento should provide a constructor, an equality operator, and a destructor.
|
||||||
|
- The memento's destructor could be implied. (Not actually written, and provided by the compiler.)
|
||||||
|
- The memento's constructor and equality operator must accept a reference to a const Host object.
|
||||||
|
- The memento's equality operator should return false if the memento differs from the host.
|
||||||
|
|
||||||
|
This code snippet shows the template parameters for an exception policy that
|
||||||
|
uses a Memento and the signatures for the three required functions for a
|
||||||
|
ContractChecker policy.
|
||||||
@code
|
@code
|
||||||
|
template < class Host, class Memento >
|
||||||
class YourPolicy
|
class YourPolicy
|
||||||
{ public:
|
{
|
||||||
|
public:
|
||||||
explicit YourPolicy( const Host * );
|
explicit YourPolicy( const Host * );
|
||||||
bool Check( const Host * ) const;
|
bool Check( const Host * ) const;
|
||||||
|
~YourPolicy();
|
||||||
|
private:
|
||||||
|
Memento m_compare;
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
The following code snippet shows the template parameters and function
|
||||||
|
declarations for an exception policy that does not use a Memento.
|
||||||
|
@code
|
||||||
|
template < class Host >
|
||||||
|
class YourPolicy< Host, void >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit YourPolicy( const Host * );
|
||||||
|
bool Check( const Host * ) const;
|
||||||
|
~YourPolicy();
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@par Writing Your Own Policies for StaticChecker
|
||||||
Loki provides two exception policies for StaticChecker - one that asserts if
|
Loki provides two exception policies for StaticChecker - one that asserts if
|
||||||
an exception occurred, and one that does not care about exceptions. You can
|
an exception occurred, and one that does not care about exceptions. You can
|
||||||
make your own policy to log failures, send an email, file a bug report, or do
|
make your own policy to log failures, send an email, file a bug report, or do
|
||||||
|
@ -101,8 +162,37 @@ namespace Loki
|
||||||
bool Check() const;
|
bool Check() const;
|
||||||
}
|
}
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
@par Requirements for Host Object
|
||||||
|
CheckForNoThrow and CheckForNothing impose no restrictions on the host class.
|
||||||
|
The policies for StaticChecker impose no restrictions either. All other
|
||||||
|
policies require the Host class to either provide a Memento class or have a
|
||||||
|
public copy-constructor, destructor, and equality operator. If the Host class
|
||||||
|
provides a Memento class, then follow the guidelines listed above in the
|
||||||
|
section called "Using a Memento".
|
||||||
|
|
||||||
|
@par Writing Your Own Policies for StaticChecker
|
||||||
|
Loki provides two exception policies for StaticChecker - one that asserts if
|
||||||
|
an exception occurred, and one that does not care about exceptions. Please
|
||||||
|
follow these guidelines when writing policies:
|
||||||
|
- Each policy needs a default constructor, a destructor, and a function named Check.
|
||||||
|
- The constructor and destructor may be implied.
|
||||||
|
- Make sure your Check function never throws any exceptions.
|
||||||
|
- Any additional functions or features of the policy are up to you.
|
||||||
|
|
||||||
|
This code snippet shows the signatures for the three required functions for a
|
||||||
|
StaticChecker policy.
|
||||||
|
@code
|
||||||
|
class YourPolicy
|
||||||
|
{ public:
|
||||||
|
YourPolicy();
|
||||||
|
bool Check() const;
|
||||||
|
~YourPolicy();
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/** @class CheckForNoThrow
|
/** @class CheckForNoThrow
|
||||||
|
@ -110,13 +200,16 @@ namespace Loki
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
This exception-checking policy class for ContractChecker asserts if an
|
This exception-checking policy class for ContractChecker asserts if an
|
||||||
exception exists. Host classes can use this to show that a member function
|
exception exists. Host classes can use this to show that a member function
|
||||||
provides the no-throw exception safety guarantees.
|
provides the no-throw exception safety guarantees. Since this policy does not
|
||||||
|
care if the host object changed, use this policy for operations which change
|
||||||
|
the host object but never throw.
|
||||||
|
|
||||||
@par Requirements For Host Class:
|
@par Requirements For Host Class:
|
||||||
This policy imposes no requirements on a host class.
|
This policy imposes no requirements on a host class. This ignores the Memento
|
||||||
|
template parameter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host, class Memento >
|
||||||
class CheckForNoThrow
|
class CheckForNoThrow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -133,6 +226,8 @@ public:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template < class Host, class Memento > class CheckForNoChange;
|
||||||
|
|
||||||
/** @class CheckForNoChange
|
/** @class CheckForNoChange
|
||||||
|
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
|
@ -144,11 +239,10 @@ public:
|
||||||
@par Requirements:
|
@par Requirements:
|
||||||
This policy requires hosts to provide both the copy-constructor and the
|
This policy requires hosts to provide both the copy-constructor and the
|
||||||
equality operator, and is intended for classes with value semantics.
|
equality operator, and is intended for classes with value semantics.
|
||||||
equality operator.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host >
|
||||||
class CheckForNoChange
|
class CheckForNoChange< Host, void >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -167,22 +261,48 @@ private:
|
||||||
Host m_compare;
|
Host m_compare;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template < class Host, class Memento >
|
||||||
|
class CheckForNoChange
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline explicit CheckForNoChange( const Host * host ) :
|
||||||
|
m_compare( *host ) {}
|
||||||
|
|
||||||
|
inline bool Check( const Host * host ) const
|
||||||
|
{
|
||||||
|
const bool okay = ( !::std::uncaught_exception() )
|
||||||
|
|| ( m_compare == *host );
|
||||||
|
assert( okay );
|
||||||
|
return okay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Memento m_compare;
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template < class Host, class Memento > class CheckForNoChangeOrThrow;
|
||||||
|
|
||||||
/** @class CheckForNoChangeOrThrow
|
/** @class CheckForNoChangeOrThrow
|
||||||
|
This policy comes in two forms - one uses a memento, and one does not. The
|
||||||
|
memento form does not copy the host object, but stores info about the host in
|
||||||
|
a memento for later comparison with the host. The other form copies the host
|
||||||
|
object to a temporary and then compares that to the original.
|
||||||
|
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
This exception-checking policy class for ContractChecker asserts either if a
|
This exception-checking policy class for ContractChecker asserts either if a
|
||||||
copy of the host differs from the original host object, or if an exception
|
copy of the host differs from the original host object, or if an exception
|
||||||
occurs. Host classes can use this policy to show which member functions provide
|
occurs. Host classes can use this policy to show which member functions provide
|
||||||
the no-throw exception guarantee, and would never change data anyway.
|
the no-throw exception guarantee and never change data anyway.
|
||||||
|
|
||||||
@par Requirements For Host Class:
|
@par Requirements For Host Class:
|
||||||
This policy requires hosts to provide both the copy-constructor and the
|
This policy requires hosts to provide both the copy-constructor and the
|
||||||
equality operator, and is intended for classes with value semantics.
|
equality operator, and is intended for classes with value semantics.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host, class Memento >
|
||||||
class CheckForNoChangeOrThrow
|
class CheckForNoChangeOrThrow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -199,12 +319,35 @@ public:
|
||||||
return okay;
|
return okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Memento m_compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < class Host >
|
||||||
|
class CheckForNoChangeOrThrow< Host, void >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline explicit CheckForNoChangeOrThrow( const Host * host ) :
|
||||||
|
m_compare( *host ) {}
|
||||||
|
|
||||||
|
inline bool Check( const Host * host ) const
|
||||||
|
{
|
||||||
|
bool okay = ( !::std::uncaught_exception() );
|
||||||
|
assert( okay );
|
||||||
|
okay = ( m_compare == *host );
|
||||||
|
assert( okay );
|
||||||
|
return okay;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Host m_compare;
|
Host m_compare;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template < class Host, class Memento > class CheckForEquality;
|
||||||
|
|
||||||
/** @class CheckForEquality
|
/** @class CheckForEquality
|
||||||
|
|
||||||
@par Exception Safety Level:
|
@par Exception Safety Level:
|
||||||
|
@ -216,9 +359,13 @@ private:
|
||||||
@par Requirements For Host Class:
|
@par Requirements For Host Class:
|
||||||
This policy requires hosts to provide both the copy-constructor and the
|
This policy requires hosts to provide both the copy-constructor and the
|
||||||
equality operator, and is intended for classes with value semantics.
|
equality operator, and is intended for classes with value semantics.
|
||||||
|
|
||||||
|
@par Requirements For Memento Class:
|
||||||
|
This policy requires Memento to provide a constructor and an equality operator
|
||||||
|
that accept a reference to a const host.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host, class Memento >
|
||||||
class CheckForEquality
|
class CheckForEquality
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -233,6 +380,25 @@ public:
|
||||||
return okay;
|
return okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Memento m_compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < class Host >
|
||||||
|
class CheckForEquality< Host, void >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline explicit CheckForEquality( const Host * host ) :
|
||||||
|
m_compare( *host ) {}
|
||||||
|
|
||||||
|
inline bool Check( const Host * host ) const
|
||||||
|
{
|
||||||
|
const bool okay = ( m_compare == *host );
|
||||||
|
assert( okay );
|
||||||
|
return okay;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Host m_compare;
|
Host m_compare;
|
||||||
};
|
};
|
||||||
|
@ -245,13 +411,15 @@ private:
|
||||||
This exception-checking policy class for ContractChecker does nothing when
|
This exception-checking policy class for ContractChecker does nothing when
|
||||||
called. Host classes can use this to show which member functions provide
|
called. Host classes can use this to show which member functions provide
|
||||||
neither the strong nor no-throw exception guarantees. The best guarantee such
|
neither the strong nor no-throw exception guarantees. The best guarantee such
|
||||||
functions can provide is that nothing gets leaked.
|
functions can provide is that nothing gets leaked. Use this policy for any
|
||||||
|
function that may throw exceptions and will change the host object.
|
||||||
|
|
||||||
@par Requirements For Host Class:
|
@par Requirements For Host Class:
|
||||||
This policy imposes no requirements on a host class.
|
This policy imposes no requirements on a host class. This ignores the Memento
|
||||||
|
template parameter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template < class Host >
|
template < class Host, class Memento >
|
||||||
class CheckForNothing
|
class CheckForNothing
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -308,12 +476,13 @@ public:
|
||||||
template
|
template
|
||||||
<
|
<
|
||||||
class Host,
|
class Host,
|
||||||
template < class > class ExceptionPolicy
|
template < class, class > class ExceptionPolicy,
|
||||||
|
class Memento = void
|
||||||
>
|
>
|
||||||
class ContractChecker : public ExceptionPolicy< Host >
|
class ContractChecker : public ExceptionPolicy< Host, Memento >
|
||||||
{
|
{
|
||||||
/// Shorthand for the ExceptionPolicy class.
|
/// Shorthand for the ExceptionPolicy class.
|
||||||
typedef ExceptionPolicy< Host > Ep;
|
typedef ExceptionPolicy< Host, Memento > Ep;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -405,15 +574,15 @@ private:
|
||||||
exception policies for ContractChecker, you might want to also write a struct
|
exception policies for ContractChecker, you might want to also write a struct
|
||||||
similiar to CheckFor to conveniently declare all your policies.
|
similiar to CheckFor to conveniently declare all your policies.
|
||||||
*/
|
*/
|
||||||
template < class Host >
|
template < class Host, class Memento = void >
|
||||||
struct CheckFor
|
struct CheckFor
|
||||||
{
|
{
|
||||||
// These lines declare checkers for non-static functions in a host class.
|
// These lines declare checkers for non-static functions in a host class.
|
||||||
typedef ContractChecker< Host, CheckForNoChangeOrThrow > NoChangeOrThrow;
|
typedef ContractChecker< Host, CheckForNoChangeOrThrow, Memento > NoChangeOrThrow;
|
||||||
typedef ContractChecker< Host, CheckForNoThrow > NoThrow;
|
typedef ContractChecker< Host, CheckForNoThrow, Memento > NoThrow;
|
||||||
typedef ContractChecker< Host, CheckForNoChange > NoChange;
|
typedef ContractChecker< Host, CheckForNoChange, Memento > NoChange;
|
||||||
typedef ContractChecker< Host, CheckForEquality > Equality;
|
typedef ContractChecker< Host, CheckForEquality, Memento > Equality;
|
||||||
typedef ContractChecker< Host, CheckForNothing > Invariants;
|
typedef ContractChecker< Host, CheckForNothing, Memento > Invariants;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue