//# Assert.h: Throw exceptions when Assertions fail. //# Copyright (C) 1993,1994,1995,1999,2000,2002 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #ifndef CASA_ASSERT_H #define CASA_ASSERT_H #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN // Utility class for Assert macros. // // // // //
  • module Exceptions // // // Templated class assert_ is the basis for the macros // DebugAssertExit, DebugAssert, // AlwaysAssertExit, and AlwaysAssert which // form the "public interface" to the Assertion mechanism. // // // The present Assertion mechanism uses the exception // handling mechanism to throw the errors when an Assertion // fails. It can be used in two ways: //
    //
    DebugAssertExit(expr) //
    AlwaysAssertExit(expr) //
    cause the program to abort if expr evaluates to a // null value. This form is intended for the end users // because presumabily at their level there is no way to recover // from errors. //
    DebugAssert(expr, exception) //
    AlwaysAssert(expr, exception) //
    throw the specified exception if the expr is // null. This form is designed to be used by library // elements because it actually raises an exception which // can be later caught in the regular way. //
    // // DebugAssertExit and // DebugAssert are only invoked in // debug mode (i.e. when AIPS_DEBUG is defined); otherwise // they preprocess to null statements. AlwaysAssertExit // and AlwaysAssert are always invoked. // // // Class assert_ is internal to the // Assertion mechanism and should be undocumented. However, // documenting the class is the only way to document this mechanism, // which for the rest consists of preprocessor macros. // // //
    // // The implementation of the Array classes // contains many examples of the Assertion mechanism. The following // application of the Assertion mechanism is taken from the archive of // the aips2-workers@nrao.edu mail group (Brian Glendenning, 1994/03/23): // // I thought I'd readvertise a technique I use that helps me find // problems in the classes I write. I have found this to be an // EXTREMELY useful way of discovering bugs automatically (so the users // of your class don't have to manually). // // In your class, write an ok() member function that // returns a Bool. Allow for inheritance and make it a // virtual function (in fact, the derived class's ok() would // probably call the ok() from its parent, as well as doing // specific stuff for the derived class). // // Then in every member function, place a call to ok() in // an Assertion. Like this: // // DebugAssert(ok(), AipsError); // include aips/Assert.h in your .cc file // // // The second argument is the exception you want to throw. // AipsError will always do, although you can throw a // more particular one if you want to. This Assertion will not be in // production code -- i.e. if AIPS_DEBUG is not defined, the // above line will be a null statement. I place these lines at the entry // to all member functions (except I place them at the end of a // constructor!). (I normally don't put an Assertion in an inline // function). // // In the ok() function you should Assert a class's // invariants. This is more or less the same as Asserting that an // object's private and protected data are consistent. For // example, one of the simple tests I do in the array classes is Assert // that the number of elements (which I cache) is indeed equal to the // product of its shape (I do ~15 tests in the ok() for the // new Array class). // template class assert_ { public: // assert_(int expr, const char *msg) { if (! expr) throw(t(msg)); } assert_(const void *ptr, const char *msg) { if (! ptr) throw(t(msg)); } assert_(int expr, const char *msg, const char* file, Int line); assert_(const void *ptr, const char *msg, const char* file, Int line); // // A no-op, but it keeps g++ from complaining about "variable not used" // errors void null() {} }; // These marcos are provided for use instead of simply using the // constructors of assert_ to allow addition of line // numbers and file name in the future. // // DebugAssert and AlwaysAssert are designed to // be used by library elements because they actually raise an exception // which can later be later caught. // DebugAssertExit and AlwaysAssertExit are // intended to be used by the applications writer, because they cause an // exit(0). #define AlwaysAssert(expr, exception) \ {casacore::assert_ dummy_(expr, "Failed AlwaysAssert " #expr,__FILE__,(casacore::Int)__LINE__); dummy_.null(); } #define AlwaysAssertExit(expr) \ {casacore::assert_ dummy_(expr, "Unrecoverable AlwaysAssertExit: " #expr,__FILE__,(casacore::Int)__LINE__); dummy_.null();} #if defined(AIPS_DEBUG) //# The backslashes below have spaces after them to make the egcs // compiler happy # (otherwise it thinks they are multiline // // comments). If ever uncommented # the spaces should be removed. // #define DebugAssert(expr, exception) // (assert_ (expr, "Failed Assertion: " #expr)) // #define Assert(expr) // (assert_ (expr, "Unrecoverable Assertion: " #expr)) // #define DebugAssert(expr, exception) // (assert_ (expr, "Failed Assertion: " #expr,__FILE__,(Int)__LINE__)) // #define Assert(expr) // (assert_ (expr, "Unrecoverable Assertion: " #expr,__FILE__,(Int)__LINE__)) #define DebugAssert(expr, exception) \ {casacore::assert_ dummy_(expr, "Failed Assertion: " #expr,__FILE__,(casacore::Int)__LINE__); dummy_.null();} #define DebugAssertExit(expr) \ {casacore::assert_ dummy_(expr, "Unrecoverable Assertion: " #expr,__FILE__,(casacore::Int)__LINE__); dummy_.null();} #else #define DebugAssert(expr, exception) #define DebugAssertExit(expr) #endif } //# NAMESPACE CASACORE - END #ifndef CASACORE_NO_AUTO_TEMPLATES #include #endif //# CASACORE_NO_AUTO_TEMPLATES #endif