]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/Checker.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / Checker.h
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // The Loki Library
4 // Copyright (c) 2008 Rich Sposato
5 // The copyright on this file is protected under the terms of the MIT license.
6 //
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 //
12 // The author makes no representations about the suitability of this software
13 // for any purpose. It is provided "as is" without express or implied warranty.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 // $Id$
18
19 /// @file Checker.h This file provides Loki's Checker facility.
20
21
22 // ----------------------------------------------------------------------------
23
24 #ifndef LOKI_CHECKER_H_INCLUDED
25 #define LOKI_CHECKER_H_INCLUDED
26
27 #include <exception>  // needed for calls to uncaught_exception.
28 #include <assert.h>
29
30
31 namespace Loki
32 {
33
34 /** @par ContractChecker and StaticChecker Overview
35  The ContractChecker and StaticChecker classes have two purposes:
36  - provide a mechanism by which programmers can determine which functions
37    violate class/data invariants,
38  - and determine which exception safety a function provides.
39
40  @par Class & Data Invariants
41  The ContractChecker and StaticChecker define invariants as "expressions that
42  are true for particular data".  They uses a function which returns true if all
43  data are valid, and returns false if any datum is invalid.  This is called the
44  validator function, and the host class or function provides a pointer to it.
45  The validator could also assert for any invariant which fails rather than
46  return false.  If the validator is a static member function, you can use it
47  with checkers in any function, but especially standalone functions and class
48  static functions.  If the validator is a non-static member function, you can
49  use it only within non-static member functions.
50
51  @par Exception Safety Levels
52  Years ago, David Abrahams formalized a framework for assessing the exception
53  safety level a function provides.  His framework describes three levels of
54  guarantees.  Any function which does not provide any of these levels is
55  considered unsafe.  ContractChecker and StaticChecker determine a function's
56  safety level through the use of policy classes.  Checker's policy classes can
57  show if a function provides any of these three guarantees.  Since there is no
58  universal way to detect leaks, this facility provides no mechanism for finding
59  leaks, but users may create their own validators which do.  StaticChecker's
60  policy classes only provide direct checking for the no-throw and invariant
61  guarantees.  With some finesse, a programmer can write a validator for
62  StaticChecker that checks for the Strong guarantee.
63
64  - No-throw guarantee: A function will not throw any exceptions.
65  - Strong guarantee: A function will not change data if an exception occurs.
66    (Which I call the no-change guarantee.)
67  - Basic guarantee: A function will not leak resources and data will remain
68    in a valid state if an exception occurs.  (Which I call either the no-leak
69    or no-break guarantee depending on context.)
70  */
71
72 // ----------------------------------------------------------------------------
73
74 /** @class CheckForNoThrow
75
76  @par Exception Safety Level:
77  This exception-checking policy class for ContractChecker asserts if an
78  exception exists.  Host classes can use this to show that a member function
79  provides the no-throw exception safety guarantees.
80
81  @par Requirements For Host Class:
82  This policy imposes no requirements on a host class.
83  */
84 template < class Host >
85 class CheckForNoThrow
86 {
87 public:
88
89         inline explicit CheckForNoThrow( const Host * ) {}
90
91         inline bool Check( const Host * ) const
92         {
93                 const bool okay = ( !::std::uncaught_exception() );
94                 assert( okay );
95                 return okay;
96         }
97 };
98
99 // ----------------------------------------------------------------------------
100
101 /** @class CheckForNoChange
102
103  @par Exception Safety Level:
104  This exception-checking policy class for ContractChecker asserts only if a
105  copy of the host differs from the host object when an exception occurs.  Host
106  classes can use this policy to show which member functions provide the strong
107  exception guarantee.
108
109  @par Requirements:
110  This policy requires hosts to provide both the copy-constructor and the
111  equality operator, and is intended for classes with value semantics.
112  equality operator.
113  */
114
115 template < class Host >
116 class CheckForNoChange
117 {
118 public:
119
120         inline explicit CheckForNoChange( const Host *host ) :
121                 m_compare( *host ) {}
122
123         inline bool Check( const Host *host ) const
124         {
125                 const bool okay = ( !::std::uncaught_exception() )
126                                   || ( m_compare == *host );
127                 assert( okay );
128                 return okay;
129         }
130
131 private:
132         Host m_compare;
133 };
134
135 // ----------------------------------------------------------------------------
136
137 /** @class CheckForNoChangeOrThrow
138
139  @par Exception Safety Level:
140  This exception-checking policy class for ContractChecker asserts either if a
141  copy of the host differs from the original host object, or if an exception
142  occurs. Host classes can use this policy to show which member functions provide
143  the no-throw exception guarantee, and would never change data anyway.
144
145  @par Requirements For Host Class:
146  This policy requires hosts to provide both the copy-constructor and the
147  equality operator, and is intended for classes with value semantics.
148  */
149
150 template < class Host >
151 class CheckForNoChangeOrThrow
152 {
153 public:
154
155         inline explicit CheckForNoChangeOrThrow( const Host *host ) :
156                 m_compare( *host ) {}
157
158         inline bool Check( const Host *host ) const
159         {
160                 bool okay = ( !::std::uncaught_exception() );
161                 assert( okay );
162                 okay = ( m_compare == *host );
163                 assert( okay );
164                 return okay;
165         }
166
167 private:
168         Host m_compare;
169 };
170
171 // ----------------------------------------------------------------------------
172
173 /** @class CheckForEquality
174
175  @par Exception Safety Level:
176  This exception-checking policy class for ContractChecker asserts if a copy of the host differs from the host object regardless of whether an exception occurs.
177  Host classes can use this policy to show which member functions never change
178  data members, and thereby provide the strong exception safety level by default.
179
180  @par Requirements For Host Class:
181  This policy requires hosts to provide both the copy-constructor and the
182  equality operator, and is intended for classes with value semantics.
183  */
184
185 template < class Host >
186 class CheckForEquality
187 {
188 public:
189
190         inline explicit CheckForEquality( const Host *host ) :
191                 m_compare( *host ) {}
192
193         inline bool Check( const Host *host ) const
194         {
195                 const bool okay = ( m_compare == *host );
196                 assert( okay );
197                 return okay;
198         }
199
200 private:
201         Host m_compare;
202 };
203
204 // ----------------------------------------------------------------------------
205
206 /** @class CheckForNothing
207
208  @par Exception Safety Level:
209  This exception-checking policy class for ContractChecker does nothing when
210  called.  Host classes can use this to show which member functions provide
211  neither the strong nor no-throw exception guarantees.  The best guarantee such
212  functions can provide is that nothing gets leaked.
213
214  @par Requirements For Host Class:
215  This policy imposes no requirements on a host class.
216  */
217
218 template < class Host >
219 class CheckForNothing
220 {
221 public:
222         inline explicit CheckForNothing( const Host * ) {}
223         inline bool Check( const Host * ) const
224         {
225                 return true;
226         }
227 };
228
229 // ----------------------------------------------------------------------------
230
231 /** @class ContractChecker
232  This class determines if a function violated any class invariant, but it also
233  determines if a function fulfills its contract with client code.  In the
234  "Design by Contract" paradigm, each function has certain pre-conditions and
235  post-conditions which may differ from the class invariants.  This asserts if a
236  check for an invariant fails as well as if any pre- or post-condition fails.
237  It also demonstrate which exception safety level a function provides.
238
239  @par Usage
240  -# Implement a function that checks each class invariant.  The function must
241     have the signature similar to the Validator type.  Something like:
242     "bool Host::IsValid( void ) const;"
243     - The function should return true if everything is okay, but false if
244       something is wrong.
245     - Or it could assert if anything is wrong.
246     - Ideally, it should be private.
247  -# Implement similar functions to check for pre-conditions and post-conditions.
248     Functions which verify pre-conditions and post-conditions do not need to
249     check all class invariants, just conditions specific to certain public
250     functions in the host class.
251  -# Declare some typedef's inside the class declaration like these.  Make one
252     typedef for each exception policy you use.  I typedef'ed the CheckForNothing
253     policy as CheckInvariants because even if a function can't provide either the
254     no-throw nor the no-change policies, it should still make sure the object
255     remains in a valid state.
256     - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoThrow  > CheckForNoThrow;
257     - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoChange > CheckForNoChange;
258     - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForEquality > CheckForEquality;
259     - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNothing  > CheckInvariants;
260  -# Construct a checker near the top of each member function - except in the
261     validator member function.  Pass the this pointer and the address of your
262     validator function into the checker's constructor.  You may also pass in pointers
263     to function which check pre- and post-conditions.
264     - If the function never throws, then use the CheckForNoThrow policy.
265     - If the function never changes any data members, then use CheckForEquality
266       policy.
267     - If the function's normal execution flow changes data, but must make sure
268       data remains unchanged when any exceptions occur, then use the
269       CheckForNoChange policy.
270     - Otherwise use the CheckInvariants policy.
271  -# Recompile a debug version of your program, run the program and all the unit
272     tests, and look for which assertions failed.
273  */
274
275 template
276 <
277 class Host,
278       template < class > class ExceptionPolicy
279       >
280 class ContractChecker : public ExceptionPolicy< Host >
281 {
282         /// Shorthand for the ExceptionPolicy class.
283         typedef ExceptionPolicy< Host > Ep;
284
285 public:
286
287         /// Signature for the validation function.
288         typedef bool ( Host:: * Validator )( void ) const;
289
290         /** The constructor makes sure the host is valid at the time the checker
291          was created, thus insuring the host object was not corrupt from the start.
292          @par host Pointer to host object.
293          @par validator Pointer to function that checks class invariants.
294          @par pre Optional pointer to function that checks pre-conditions.
295          @par post Optional pointer to function that checks post-conditions.
296          */
297         inline ContractChecker( const Host *host, Validator validator,
298                                 Validator pre = 0, Validator post = 0 ) :
299                 Ep( host ),
300                 m_host( host ),
301                 m_validator( validator ),
302                 m_pre( pre ),
303                 m_post( post )
304         {
305                 assert( Check() );
306                 if ( 0 != m_pre )
307                         assert( ( m_host->*( m_pre ) )() );
308         }
309
310         /** The destructor checks if any Host invariants failed, and then calls the
311          ExceptionPolicy's Check function to determine what to do in case of an
312          exception.
313          */
314         inline ~ContractChecker( void )
315         {
316                 assert( Check() );
317                 if ( 0 != m_post )
318                         assert( ( m_host->*( m_post ) )() );
319                 assert( Ep::Check( m_host ) );
320         }
321
322         /** This first checks the invariants for ContractChecker, and then calls the
323          validator function for the host to make sure no class invariants were
324          broken by the host within the Host's member function body.  The host
325          member function can call Check directly to verify the object remains valid
326          at any time.  This does not care if the pre- and post-condition validator
327          pointers are null since a host class may pass in NULL pointers for either
328          to indicate the pre-conditions or post-conditions are the same as the
329          overall class invariants.
330          */
331         inline bool Check( void ) const
332         {
333                 assert( 0 != this );
334                 assert( 0 != m_host );
335                 assert( 0 != m_validator );
336                 // Now that this confirms the pointers to the host and validation
337                 // functions are not null, go ahead and validate the host object.
338                 const bool okay = ( m_host->*( m_validator ) )();
339                 assert( okay );
340                 return okay;
341         }
342
343 private:
344
345         /// Default constructor is not implemented.
346         ContractChecker( void );
347         /// Copy constructor is not implemented.
348         ContractChecker( const ContractChecker & );
349         /// Copy-assignment operator is not implemented.
350         ContractChecker &operator = ( const ContractChecker & );
351
352         /// Pointer to the host object.
353         const Host *m_host;
354
355         /// Pointer to member function that checks Host object's invariants.
356         Validator m_validator;
357
358         /// Pointer to member function that checks Host object's pre-conditions.
359         Validator m_pre;
360
361         /// Pointer to member function that checks Host object's post-conditions.
362         Validator m_post;
363
364 };
365
366 // ----------------------------------------------------------------------------
367
368 /** @class CheckStaticForNoThrow
369
370  @par Exception Safety Level:
371  This exception-checking policy class for StaticChecker asserts if an exception
372  exists.  Functions can use this to show they provide the no-throw exception
373  safety guarantee.
374  */
375 class CheckStaticForNoThrow
376 {
377 public:
378         inline bool Check( void )
379         {
380                 const bool okay = !::std::uncaught_exception();
381                 assert( okay );
382                 return okay;
383         }
384 };
385
386 // ----------------------------------------------------------------------------
387
388 /** @class CheckStaticForNothing
389
390  @par Exception Safety Level:
391  This exception-checking policy class for StaticChecker does nothing when called.
392  Functions can use this to show they might provide the weak exception guarantee.
393  The best guarantee such functions can provide is that nothing gets leaked.
394  */
395 class CheckStaticForNothing
396 {
397 public:
398         inline bool Check( void )
399         {
400                 return true;
401         }
402 };
403
404 // ----------------------------------------------------------------------------
405
406 /** @class StaticChecker
407  This class checks if a function provides the no-throw exception safety level
408  and if the function violated any invariants.  Invariants for stand-alone and
409  static functions act as pre-conditions and post-conditions.
410
411  @par Usage
412  -# Implement a function that checks the invariants associated with a function,
413     or with the static data for a class.  The function must
414     have the signature similar to the Validator type.  Something like:
415     "static bool Host::StaticIsValid( void );" or "bool IsOkay( void );"
416     - The function should return true if everything is okay, but false if
417       something is wrong.
418     - Or it could assert if anything is wrong.
419  -# If the checker is for static functions within a class, declare typedef's
420     inside the class declaration like these.  Make one typedef for each policy
421     you use.  I typedef'ed the CheckForNothing policy as CheckInvariants because
422     even if a function can't provide the no-throw guarantee, it should still
423     make sure that static data remains in a valid state.
424     - typedef ::Loki::StaticChecker< ::Loki::CheckForNoThrow > CheckStaticForNoThrow;
425     - typedef ::Loki::StaticChecker< ::Loki::CheckForNothing > CheckStaticInvariants;
426  -# Construct a checker near the top of each member function - except in the
427     validator member function.  Pass the address of your validator function into
428     the checker's constructor.
429     - If the function never throws, then use the CheckForNoThrow policy.
430     - Otherwise use the CheckInvariants policy.
431  -# Recompile a debug version of your program, run it, and see if an assertion
432     fails.
433  */
434
435 template
436 <
437 class ExceptionPolicy
438 >
439 class StaticChecker : public ExceptionPolicy
440 {
441         /// Shorthand for the ExceptionPolicy class.
442         typedef ExceptionPolicy Ep;
443
444 public:
445
446         /// Signature for the validation function.
447         typedef bool ( * Validator )( void );
448
449         /** The constructor makes sure the host is valid at the time the checker
450          was created, thus insuring the host object was not corrupt from the start.
451          @par validator Pointer to function that checks class invariants.
452          @par pre Optional pointer to function that checks pre-conditions.
453          @par post Optional pointer to function that checks post-conditions.
454          */
455         inline explicit StaticChecker( Validator validator,
456                                        Validator pre = 0, Validator post = 0 ) :
457                 Ep(),
458                 m_validator( validator ),
459                 m_pre( pre ),
460                 m_post( post )
461         {
462                 assert( Check() );
463                 if ( 0 != m_pre )
464                         assert( m_pre() );
465         }
466
467         /** The destructor checks if any Host invariants failed, and then calls the
468          ExceptionPolicy's Check function to determine what to do in case of an
469          exception.
470          */
471         inline ~StaticChecker( void )
472         {
473                 assert( Check() );
474                 if ( 0 != m_post )
475                         assert( m_post() );
476                 assert( Ep::Check() );
477         }
478
479         /** This first checks its own invariants, and then calls the validator
480          function to make sure no invariants were broken by the function which
481          created this checker.  That function can call Check directly to verify the
482          data remains valid at any time.  This does not care if the pre- and post-
483          condition validator pointers are null since a host class may pass in NULL
484          pointers for either to indicate the pre-conditions or post-conditions are
485          the same as the overall class invariants.
486          */
487         inline bool Check( void ) const
488         {
489                 assert( 0 != this );
490                 assert( 0 != m_validator );
491                 // Now that this confirms the pointers to the host and validation
492                 // functions are not null, go ahead and validate the host object.
493                 const bool okay = m_validator();
494                 assert( okay );
495                 return okay;
496         }
497
498 private:
499
500         /// Default constructor is not implemented.
501         StaticChecker( void );
502         /// Copy constructor is not implemented.
503         StaticChecker( const StaticChecker & );
504         /// Copy-assignment operator is not implemented.
505         StaticChecker &operator = ( const StaticChecker & );
506
507         /// Pointer to member function that checks Host object's invariants.
508         Validator m_validator;
509
510         /// Pointer to member function that checks Host object's pre-conditions.
511         Validator m_pre;
512
513         /// Pointer to member function that checks Host object's post-conditions.
514         Validator m_post;
515
516 };
517
518 // ----------------------------------------------------------------------------
519
520 }; // end namespace Loki
521
522 #endif