CoreLinux++  0.4.32
Assertion.hpp
1 #if !defined (__ASSERTION_HPP)
2 #define __ASSERTION_HPP
3 
4 /*
5  CoreLinux++
6  Copyright (C) 1999 CoreLinux Consortium
7 
8  The CoreLinux++ Library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12 
13  The CoreLinux++ Library Library is distributed in the hope that it will
14  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public
19  License along with the GNU C Library; see the file COPYING.LIB. If not,
20  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  Boston, MA 02111-1307, USA.
22 */
23 
24 
25 /*
26 Assertion is the exception created when an assertion fails. It contains
27 type information so that clients may filter the types of assertion
28 violations that they catch. There are several types of assertion:
29 
30  ASSERT( bool ) Enabled by #define ALL_ASSERTIONS. It is only used
31  inside the INVARIANT clause of a class declaration.
32 
33  REQUIRE( bool ) Enabled by #define ALL_ASSERTIONS or
34  #define ASSERT_REQUIRE. This macro is used to
35  check precondtions for a function. If disabled
36  the macro is compiled away.
37 
38  ENSURE( bool ) Enabled by #define ALL_ASSERTIONS or
39  #define ASSERT_ENSURE. This macro is used to check
40  postconditions. If disabled the macro is compiled
41  away.
42 
43  CHECK( bool ) Enabled by #define ALL_ASSERTIONS or
44  #define ASSERT_CHECK. This macro is used to check
45  assumptions or to check calls to external functions
46  in the OS. Unlike REQUIRE and ENSURE when disabled
47  this macro expands to: if( !( exp )) {;} else
48  This expansion allows calls such as:
49  CHECK( DosSubAllocMem( ... ) == 0 );
50  to not be compiled away.
51 
52  CHECK_INVARIANT Enabled by #define ALL_ASSERTIONS. This macro is
53  used to validate that the class INVARIANT still
54  holds. The INVARIANT must hold after construction
55  and at the end of any public member function. In
56  order to use this assertion the class must have an
57  INVARIANT ... END_INVARIANT section in the class
58  definition. If ALL_ASSERTIONS is not defined then
59  this macro expands to nothing.
60 
61  NEVER_GET_HERE This macro is always enabled and throws an assertion
62  if it is ever executed. It should be used to make
63  explicit to the reader that all cases have been
64  accounted for in a switch or if ... else if ... else
65  block.
66 
67 Typically the programmer defines ALL_ASSERTIONS during development and
68 reduces assertion levels to ASSERT_REQUIRE at beta and even into release.
69 
70 In addition to the assertions there are several helper macros that allow
71 for class INVARIANTs and the logic predicates "for all" and "there exists".
72 There is also the USES_OLD macro which allows changes in a class to be
73 checked against the original version of the class.
74 
75 BASE_INVARIANT( BaseClass ) Can only be used in the INVARIANT clause
76  of a class definition. This expands to call the
77  INVARIANT of one of the base classes in the
78  current class. Expands to: BaseClass::INVARIANT()
79 
80 INVARIANT Can only be used inside a class definition. This
81  should be the last thing in the class and should
82  state the conditions that hold when the class is
83  correct. The only statements allowed in the
84  INVARIANT are BASE_INVARIANT and ASSERT.
85  For example an ordered array class may
86  look like:
87 
88  class OrderedArray<T> : public Vector
89  {
90  public:
91  Array( int size ) :
92  Vector(),
93  theSize( size ),
94  theArray( new T[ size ] );
95  {
96  orderTheArray();
97 
98  CHECK_INVARIANT;
99  }
100 
101  virtual !Array();
102 
103  // other operations.
104 
105  private:
106  int theSize;
107  T * theArray;
108 
109  INVARIANT
110  BASE_INVARIANT( Vector );
111 
112  // Array is sorted in ascending order.
113  ASSERT( FORALL(( int i = 1; i < theSize; i++ ),
114  theArray[i-1] <= theArray[i] ));
115  END_INVARIANT
116  }; // end class OrderedArray<T>
117 
118 
119 END_INVARIANT Used to terminate the INVARIANT clause in a class
120  definition.
121 
122 USES_OLD( Type ) Creates a copy of the current object called old
123  which can then be used in assertions to check
124  those attributes between the new object and old.
125  Any function which needs old must declare this
126  at the start of the function. The object must
127  be able to copy itself deeply for this to work
128  correctly. Only creates old if ALL_ASSERTIONS or
129  ASSERT_ENSURE is defined.
130  WARNING: old should only be used by the ENSURE
131  macro.
132 
133  old variable created by the USES_OLD macro. A typical
134  use would be:
135 
136  void List::addItem( item )
137  {
138  ...
139  ENSURE( size() == old.size() + 1 );
140  }
141 
142 bool FORALL(( for-specification ), condition )
143 
144  Only expands if ALL_ASSERITONS is defined, and can only
145  be used in assertions. If ALL_ASSERTIONS is not defined
146  it becomes the value True. If expanded it becomes
147  equivalent to:
148 
149  REQUIRE( FORALL(( int i = 0; i < 10; i++ ), x[i] <= x[0] ));
150 
151  REQUIRE( tempForAll() );
152 
153  bool tempForAll()
154  {
155  bool result = True;
156  for( int i = 0; i < 10; i++ )
157  if( !( x[i] <= x[0] ))
158  {
159  result = False;
160  break;
161  }
162  return result;
163  }
164 
165  Be very carefull using this macro since errors
166  in the for specification or condition can be very difficult
167  to find. Also note that the condition can be another
168  FORALL or an EXISTS.
169 
170 bool EXISTS((for-specification), condition )
171 
172  Only expands if ALL_ASSERTIONS is defined, otherwise
173  becomes the value True. Returns True as soon as the
174  condition is met. If all iterations fail then the
175  macro fails. When expanded it becomes equivalent to:
176 
177  ENSURE( EXISTS((int i = 0; i<10; i++), x[i] == old.x[i] ));
178  ENSURE( tempExists() );
179 
180  bool tempExists()
181  {
182  bool result;
183  for( int i = 0; i < 10; i++ )
184  if( x[i] == old.x[i] )
185  {
186  result = True;
187  break;
188  }
189  return result;
190  }
191 
192 
193 The assertion mechanism also supports two functions; assertionFailed()
194 and assertLoopDebugFunction(). The first is called when an assertion
195 fails and after the assertion exception has been built. The second
196 one is called if FORALL or EXISTS fail. These functions are a handy
197 place to set breakpoints during debugging. They are implemented in
198 Assertion.cpp
199 
200  See also: Object Oriented Software Construction
201  Bertrand Meyer.
202  Prentice Hall, Englewood Cliffs NJ., 1988.
203 
204  C/C++ Users Journal October 1994 pages 21 - 37
205 
206 */
207 
208 #if !defined IN_COMMON_HPP
209  #error Assertion.hpp is included by Common.hpp only.
210 #endif
211 
212 namespace corelinux
213 {
214  // Standard class Declarations
215 
216  DECLARE_CLASS( Assertion );
217 
218  // These macros are called when an assertion fails or a FORALL or EXISTS
219  // test fails respectively. They provide a convienent place to set a
220  // breakpoint during debugging.
221  //
222 
223  Long assertionFailed( AssertionCref rAssertion );
224  void assertLoopDebugFunction( void );
225 
226  //
227  // Static variables needed by the assertion macros.
228  //
229 
230  static Long asstInvert = 0;
231  static Long asstResult = 0;
232  static Long asstEval = 0;
233  static Long asstShortCut = 0;
234  static Long asstZero = 0;
235 
236  static struct AssertCt
237  {
238  AssertCt( void )
239  {
240  asstInvert = asstResult = asstEval = asstShortCut = asstZero = 0;
241  }
242  // empty
243  } asstCt;
244 
245 
246  //
247  // Typedefs and Macros
248  //
249 
250 
251  #define paste(a,b) a##b
252  #define paste3(a,b,c) a##b##c
253 
254 
255  #if defined ALL_ASSERTIONS || defined ASSERT_REQUIRE
256  #define REQUIRE( exp ) \
257  IGNORE_RETURN ( \
258  asstResult = asstZero || exp, \
259  asstResult || assertionFailed( Assertion( Assertion::REQUIRE, \
260  TEXT( #exp ), \
261  LOCATION \
262  )) )
263 
264  #else
265  #define REQUIRE( exp )
266  #endif // defined ALL_ASSERTIONS || ASSERT_REQUIRE
267 
268  #if defined ALL_ASSERTIONS || defined ASSERT_ENSURE
269  #define ENSURE( exp ) \
270  IGNORE_RETURN ( \
271  asstResult = asstZero || exp, \
272  asstResult || assertionFailed( Assertion( Assertion::ENSURE, \
273  TEXT( #exp ), \
274  LOCATION \
275  )) )
276 
277  #else
278  #define ENSURE( exp )
279  #endif // defined ALL_ASSERTIONS || ASSERT_ENSURE
280 
281  #if defined ALL_ASSERTIONS || defined ASSERT_CHECK
282  #define CHECK( exp ) \
283  IGNORE_RETURN ( \
284  asstResult = asstZero || exp, \
285  asstResult || assertionFailed( Assertion( Assertion::CHECK, \
286  paste3( \
287  TEXT("CHECK( "), \
288  TEXT( #exp ), \
289  TEXT(" )") \
290  ), \
291  LOCATION )) )
292 
293  #else
294  #define CHECK( exp )
295  #endif // defined ALL_ASSERTIONS || ASSERT_CHECK
296 
297 
298  #define NEVER_GET_HERE \
299  assertionFailed( Assertion( Assertion::NEVERGETHERE, \
300  TEXT("NEVER_GET_HERE"), \
301  LOCATION ))
302 
303 //
304 // Macros that support class INVARIANTs.
305 //
306 
307  #if defined ALL_ASSERTIONS
308  #define INVARIANT \
309  protected: \
310  virtual void invariant(void) const { Short executingInvariant = 1;
311  #define END_INVARIANT }
312  #define CHECK_INVARIANT invariant()
313  #else
314  #define INVARIANT paste(/, *)
315  #define END_INVARIANT
316  #define CHECK_INVARIANT
317  #endif
318 
319 /*
320  paste3( \
321  TEXT("STDASSERT( "), \
322  TEXT( #exp ), \
323  TEXT(" )") \
324  ), \
325 */
326 
327  #if defined ALL_ASSERTIONS
328  #define STDASSERT( exp ) \
329  if( executingInvariant ) \
330  { \
331  asstResult = asstZero || exp, \
332  asstResult || \
333  assertionFailed( Assertion( Assertion::ASSERT, \
334  TEXT( #exp ), \
335  LOCATION )); \
336  } \
337  else \
338  { \
339  throw Exception( \
340  TEXT("STDASSERT used outside of INVARIANT"), LOCATION ); \
341  }
342  #else
343  #define STDASSERT( exp )
344  #endif // defined ALL_ASSERTIONS
345 
346  #if defined ALL_ASSERTIONS
347  #define BASE_INVARIANT( ClassType ) \
348  if( executingInvariant ) \
349  { \
350  ClassType::invariant(); \
351  } \
352  else \
353  { \
354  throw Exception( \
355  TEXT("BASE_INVARIANT used outside of an INVARIANT"), \
356  LOCATION, \
357  Exception::ProcessTerminate); \
358  }
359 
360  #else
361  #define BASE_INVARIANT( ClassType )
362  #endif
363 
364 //
365 // Macro that defines "old".
366 //
367 
368  #if defined ALL_ASSERTIONS || defined ASSERT_ENSURE
369  #define USES_OLD( Type ) Type old( clself )
370  #else
371  #define USES_OLD( Type )
372  #endif
373 
374 //
375 // Macros for FORALL and EXISTS
376 //
377 
378  #define ASSERT_LOOP( asstFor, asstAll, asstCond ) \
379  anAssertCt(); \
380  { \
381  volatile x = 0; \
382  Long asstShortCut; \
383  if( asstDoEval( asstShortCut )) \
384  { \
385  Long asstInvert = ::asstInvert; \
386  asstResult = asstAll; \
387  for asstFor \
388  { \
389  asstResult = x || asstCond; \
390  if( asstResult != asstAll ) break; \
391  } \
392  if(asstInvert) asstResult = !asstResult; \
393  } \
394  ::asstShortCut = asstShortCut; \
395  if( asstResult == 0 ) assertLoopDebugFunction(); \
396  } \
397  asstResult = ::asstShortCut ? asstResult : asstResult
398 
399  #if defined ALL_ASSERTIONS
400  #define FORALL(asstFor, asstCond ) ASSERT_LOOP( asstFor, 1, asstCond )
401  #define EXISTS(asstFor, asstCond ) ASSERT_LOOP( asstFor, 0, asstCond )
402  #else
403  #define FORALL(asstFor, asstCond ) True
404  #define EXISTS(asstFor, asstCond ) True
405  #endif
406 
407 //
408 // Constants
409 //
410 
411 
412 //
413 // Helper Classes (including exceptions).
414 //
415 
423  class Assertion : public Exception
424  {
425  //
426  // Note that a private default constructor is not needed
427  // beause Exception's default constructor is private.
428  //
429 
430  public:
431 
433 
434  enum Type
435  {
436  REQUIRE,
440  NEVERGETHERE
441  };
442 
443  public:
444 
453  Assertion
454  (
455  Type aType,
456  CharPtr aReason,
457  CharPtr aFile,
458  LineNum aLine
459  );
460 
466  Assertion( AssertionCref rExcept );
467 
469 
470  virtual ~Assertion( void );
471 
472  //
473  // Operator overloads
474  //
475 
482  AssertionRef operator=( AssertionCref );
483 
490  bool operator==( AssertionCref );
491 
492  //
493  // Accessors
494  //
495 
501  Assertion::Type getType( void ) const;
502 
503  private:
504 
505  Assertion::Type theType;
506  };
507 
508 //
509 // Inline Functions
510 //
511 
512  inline AssertCt & anAssertCt( void )
513  {
514  asstInvert = 0;
515  asstEval = 1;
516  return asstCt;
517  };
518 
519  inline Long asstDoEval( Long & asstShortCut )
520  {
521  Long result = asstEval;
522 
523  asstShortCut = !asstEval && asstResult;
524 
525  asstEval = 0;
526 
527  return result;
528  }
529 
530  inline const AssertCt & operator !( const AssertCt & a )
531  {
532  asstInvert = !asstInvert;
533  return a;
534  }
535 
536  inline Long operator &&( Long left, const AssertCt & )
537  {
538  asstEval = left;
539  return left;
540  }
541 
542  inline Long operator ||( int left, const AssertCt & )
543  {
544  asstEval = !left;
545  return left;
546  }
547 
548 }
549 
550 #endif // !defined ASSERT_HPP
551 
552 /*
553  Common rcs information do not modify
554  $Author: prudhomm $
555  $Revision: 1.1 $
556  $Date: 2000/04/23 20:43:13 $
557  $Locker: $
558 */
559 
CHECK invariant state.
Definition: Assertion.hpp:439
Forward reference the various common classes.
Definition: AbstractAllocator.hpp:32
REQUIRE pre-condition state.
Definition: Assertion.hpp:437
Exception is the base exception class used in the CoreLinux++ libraries.
Definition: Exception.hpp:51
Assertion is-a Exception created when an assertion fails.
Definition: Assertion.hpp:423
Type
Assertion Types enum.
Definition: Assertion.hpp:434
ENSURE post-condition state.
Definition: Assertion.hpp:438

This is the CoreLinux++ reference manual
Provided by The CoreLinux Consortium