2007-08-14 08:14:21 +02:00
/*
2013-01-07 05:43:01 +01:00
ERROR . hpp - Lumiera Exception Interface ( C + + )
2010-12-17 23:28:49 +01:00
2008-03-10 04:25:03 +01:00
Copyright ( C ) Lumiera . org
2011-02-05 20:56:51 +01:00
2008 , 2010 Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2007-08-14 08:14:21 +02:00
This program 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 General Public License for more details .
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
*/
2013-01-07 05:43:01 +01:00
/** @file error.hpp
* * Lumiera error handling ( C + + interface ) .
* * This header declares the Lumiera exception hierarchy ,
* * plus some of the most commonly used error flag values .
* * Within Lumiera , C - style error states and C + + - style exceptions
* * are tightly integrated . Creating an exception sets the error flag ,
* * and there are helpers available to throw an exception automatically
* * when a non - cleare error state is detected .
* *
* * @ see error - state . c
* * @ see error . hpp
* *
*/
2008-03-10 06:09:44 +01:00
# ifndef LUMIERA_ERROR_HPP_
# define LUMIERA_ERROR_HPP_
2007-08-14 08:14:21 +02:00
2007-08-26 19:14:39 +02:00
# include <string>
2009-01-25 00:24:42 +01:00
# include "include/logging.h"
2008-11-30 06:43:51 +01:00
# include "include/lifecycle.h"
2007-08-26 19:14:39 +02:00
# include "lib/error.h"
2007-08-14 08:14:21 +02:00
2008-11-26 05:19:59 +01:00
namespace lumiera {
2007-08-26 19:14:39 +02:00
using std : : string ;
2010-02-13 20:56:41 +01:00
2007-08-26 19:14:39 +02:00
/** error-ID for unspecified exceptions */
2008-03-10 06:09:44 +01:00
LUMIERA_ERROR_DECLARE ( EXCEPTION ) ;
2007-08-14 08:14:21 +02:00
/**
2010-02-13 20:56:41 +01:00
* Interface and Base class of all Exceptions thrown
2008-03-10 06:09:44 +01:00
* from within Lumiera ( C + + ) code . Common operations
2007-08-14 08:14:21 +02:00
* for getting an diagnostic message and for obtaining
2007-08-26 19:14:39 +02:00
* the root cause , i . e . the first exception encountered
2010-02-13 20:56:41 +01:00
* in a chain of exceptions .
2007-08-14 08:14:21 +02:00
*/
class Error : public std : : exception
{
public :
2010-02-13 20:56:41 +01:00
Error ( string description = " " , const char * const id = LUMIERA_ERROR_EXCEPTION ) throw ( ) ;
2009-08-02 18:00:03 +02:00
Error ( std : : exception const & cause ,
2010-02-13 20:56:41 +01:00
string description = " " , const char * const id = LUMIERA_ERROR_EXCEPTION ) throw ( ) ;
2007-08-26 19:14:39 +02:00
Error ( const Error & ) throw ( ) ;
2007-08-17 00:36:07 +02:00
virtual ~ Error ( ) throw ( ) { } ;
2008-12-24 03:30:34 +01:00
/** yield a diagnostic message characterising the problem */
2007-08-14 08:14:21 +02:00
virtual const char * what ( ) const throw ( ) ;
2010-02-13 20:56:41 +01:00
2008-03-10 06:09:44 +01:00
/** the internal Lumiera-error-ID (was set as C-errorstate in ctor) */
2007-08-26 19:14:39 +02:00
const char * getID ( ) const throw ( ) { return this - > id_ ; }
/** extract the message to be displayed for the user */
const string & getUsermsg ( ) const throw ( ) ;
2007-08-14 08:14:21 +02:00
/** If this exception was caused by a chain of further exceptions,
2007-08-26 19:14:39 +02:00
* return the description of the first one registered in this throw sequence .
* This works only if every exceptions thrown as a consequence of another exception
2008-12-24 03:30:34 +01:00
* is properly constructed by passing the original exception to the constructor
2007-08-26 19:14:39 +02:00
* @ return the description string , maybe empty ( if there is no known root cause )
2007-08-14 08:14:21 +02:00
*/
2007-08-26 19:14:39 +02:00
const string & rootCause ( ) const throw ( ) { return this - > cause_ ; }
2010-02-13 20:56:41 +01:00
2008-12-24 03:30:34 +01:00
/** replace the previous or default friendly message for the user. To be localised. */
2007-08-26 19:14:39 +02:00
Error & setUsermsg ( const string & newMsg ) throw ( ) { this - > msg_ = newMsg ; return * this ; }
2010-02-13 20:56:41 +01:00
2007-08-26 19:14:39 +02:00
/** give additional developer info. Typically used at intermediate handlers to add context. */
Error & prependInfo ( const string & text ) throw ( ) { this - > desc_ . insert ( 0 , text ) ; return * this ; }
2007-08-14 08:14:21 +02:00
private :
2008-03-10 06:09:44 +01:00
const char * id_ ; ///< an LUMIERA_ERROR id, which is set as errorstate on construction
2008-12-24 03:30:34 +01:00
string msg_ ; ///< friendly message intended for users (to be localised)
2007-08-26 19:14:39 +02:00
string desc_ ; ///< detailed description of the error situation for the developers
mutable string what_ ; ///< buffer for generating the detailed description on demand
2008-12-24 03:30:34 +01:00
const string cause_ ; ///< description of first exception encountered in the chain
2010-02-13 20:56:41 +01:00
2009-08-02 18:00:03 +02:00
static const string extractCauseMsg ( std : : exception const & ) throw ( ) ;
2007-08-14 08:14:21 +02:00
} ;
2007-08-26 19:14:39 +02:00
2010-02-13 20:56:41 +01:00
2013-01-07 05:43:01 +01:00
/* === Exception sub-categories === */
2010-02-13 20:56:41 +01:00
namespace error {
2007-08-14 08:14:21 +02:00
2007-08-26 19:14:39 +02:00
/** global function for handling unknown exceptions
* encountered at functions declaring not to throw
* this kind of exception . Basically , any such event
* can be considered a severe design flaw ; we can just
* add some diagnostics prior to halting .
*/
2008-03-10 06:09:44 +01:00
void lumiera_unexpectedException ( ) throw ( ) ;
2010-02-13 20:56:41 +01:00
2007-08-26 19:14:39 +02:00
/** throw an error::Fatal indicating "assertion failure" */
void assertion_terminate ( const string & location ) ;
2010-02-13 20:56:41 +01:00
2007-08-26 19:14:39 +02:00
/* constants to be used as error IDs */
2010-02-13 20:56:41 +01:00
LUMIERA_ERROR_DECLARE ( LOGIC ) ; ///< contradiction to internal logic assumptions detected
LUMIERA_ERROR_DECLARE ( FATAL ) ; ///< unable to cope with, internal logic floundered
2008-03-10 06:09:44 +01:00
LUMIERA_ERROR_DECLARE ( CONFIG ) ; ///< execution aborted due to misconfiguration
LUMIERA_ERROR_DECLARE ( STATE ) ; ///< unforeseen internal state
2010-02-13 20:56:41 +01:00
LUMIERA_ERROR_DECLARE ( FLAG ) ; ///< non-cleared lumiera errorstate from C code
2008-03-10 06:09:44 +01:00
LUMIERA_ERROR_DECLARE ( INVALID ) ; ///< invalid input or parameters encountered
LUMIERA_ERROR_DECLARE ( EXTERNAL ) ; ///< failure in external service the application relies on
LUMIERA_ERROR_DECLARE ( ASSERTION ) ; ///< assertion failure
2007-08-26 19:14:39 +02:00
2009-07-04 03:32:15 +02:00
/* generic error situations */
2011-06-13 20:07:30 +02:00
LUMIERA_ERROR_DECLARE ( LIFECYCLE ) ; ///< Lifecycle assumptions violated
2010-02-13 20:56:41 +01:00
LUMIERA_ERROR_DECLARE ( WRONG_TYPE ) ; ///< runtime type mismatch
LUMIERA_ERROR_DECLARE ( ITER_EXHAUST ) ; ///< end of sequence reached
2012-01-04 04:05:03 +01:00
LUMIERA_ERROR_DECLARE ( CAPACITY ) ; ///< predefined fixed storage capacity
2012-01-02 06:11:27 +01:00
LUMIERA_ERROR_DECLARE ( INDEX_BOUNDS ) ; ///< index out of bounds
2010-02-13 20:56:41 +01:00
LUMIERA_ERROR_DECLARE ( BOTTOM_VALUE ) ; ///< invalid or NIL value
2010-12-31 05:59:53 +01:00
LUMIERA_ERROR_DECLARE ( UNCONNECTED ) ; ///< missing connection
LUMIERA_ERROR_DECLARE ( UNIMPLEMENTED ) ; ///< unimplemented feature
2010-11-28 01:43:55 +01:00
2010-02-13 20:56:41 +01:00
2009-07-04 03:32:15 +02:00
2010-02-13 20:56:41 +01:00
/** Macro for creating derived exception classes properly
2008-03-10 06:09:44 +01:00
* integrated into Lumiera ' s exception hierarchy . Using
2008-12-24 03:30:34 +01:00
* this macro assures that the new class will get the full
2007-08-26 19:14:39 +02:00
* set of constructors and behaviour common to all exception
* classes , so it should be used when creating an derived
2008-12-24 03:30:34 +01:00
* exception type for more then strictly local purposes
2007-08-26 19:14:39 +02:00
*/
2008-03-10 06:09:44 +01:00
# define LUMIERA_EXCEPTION_DECLARE(CLASS, PARENT, _ID_) \
class CLASS : public PARENT \
{ \
public : \
CLASS ( std : : string description = " " , \
const char * id = _ID_ ) throw ( ) \
: PARENT ( description , id ) { } \
\
2010-02-13 20:56:41 +01:00
CLASS ( std : : exception const & cause , \
2008-03-10 06:09:44 +01:00
std : : string description = " " , \
const char * id = _ID_ ) throw ( ) \
: PARENT ( cause , description , id ) { } \
2007-08-14 08:14:21 +02:00
} ;
2010-02-13 20:56:41 +01:00
2008-03-10 06:09:44 +01:00
//-------------------------CLASS-----PARENT--ID----------------------
LUMIERA_EXCEPTION_DECLARE ( Logic , Error , LUMIERA_ERROR_LOGIC ) ;
LUMIERA_EXCEPTION_DECLARE ( Fatal , Logic , LUMIERA_ERROR_FATAL ) ;
LUMIERA_EXCEPTION_DECLARE ( Config , Error , LUMIERA_ERROR_CONFIG ) ;
LUMIERA_EXCEPTION_DECLARE ( State , Error , LUMIERA_ERROR_STATE ) ;
2010-02-13 20:56:41 +01:00
LUMIERA_EXCEPTION_DECLARE ( Flag , State , LUMIERA_ERROR_FLAG ) ;
2008-03-10 06:09:44 +01:00
LUMIERA_EXCEPTION_DECLARE ( Invalid , Error , LUMIERA_ERROR_INVALID ) ;
LUMIERA_EXCEPTION_DECLARE ( External , Error , LUMIERA_ERROR_EXTERNAL ) ;
2007-08-26 19:14:39 +02:00
2007-08-19 21:57:19 +02:00
2008-04-14 05:15:16 +02:00
/** install our own handler for undeclared exceptions. Will be
2008-12-18 04:51:58 +01:00
* called automatically ON_BASIC_INIT when linking exception . cpp */
2008-04-14 05:15:16 +02:00
void install_unexpectedException_handler ( ) ;
2010-02-13 20:56:41 +01:00
/** @return error detail-info if currently set, a default message else */
const char * detailInfo ( ) ;
2007-08-14 08:14:21 +02:00
} // namespace error
2010-02-13 20:56:41 +01:00
2010-01-13 20:30:10 +01:00
/**
2010-02-13 20:56:41 +01:00
* Check the lumiera error state , which maybe was set by C - code .
* @ throw Errorflag exception to signal an detected lumiera error
* @ note specific error code and information is enclosed in
* the raised exception ; the error state is \ em not cleared .
*/
inline void
throwOnError ( )
{
if ( lumiera_err errorFlag = lumiera_error ( ) )
{
throw error : : Flag ( error : : detailInfo ( )
, errorFlag ) ;
} } //causes the error state to be set
/** Check the lumiera error state and throw a specific exception
* in case a non - cleared errorflag is detected . No - op else .
* @ throw instance of the lumiera : : Error subclass provided as
* template parameter , containing an lumiera : : error : : Flag
* as root cause to denote the detected error - flag state .
2010-01-13 20:30:10 +01:00
*/
2010-02-13 20:56:41 +01:00
template < class EX >
inline void
maybeThrow ( string description )
2010-01-13 20:30:10 +01:00
{
2010-02-13 20:56:41 +01:00
if ( lumiera_err errorFlag = lumiera_error ( ) )
2010-01-13 20:30:10 +01:00
{
2010-02-13 20:56:41 +01:00
throw EX ( error : : Flag ( error : : detailInfo ( )
, errorFlag )
, description ) ;
} }
template < class EX >
inline void
maybeThrow ( )
{
maybeThrow < EX > ( " " ) ;
2010-01-13 20:30:10 +01:00
}
2010-02-13 20:56:41 +01:00
2008-03-10 06:09:44 +01:00
} // namespace lumiera
2007-08-19 21:57:19 +02:00
2013-10-24 23:06:36 +02:00
/**************************************************/ /**
2011-11-07 00:50:03 +01:00
* convenience shortcut for a sequence of catch blocks
* just logging and consuming an error . Typically
* this sequence will be used within destructors ,
* which , by convention , must not throw
*/
# define ERROR_LOG_AND_IGNORE(_FLAG_,_OP_DESCR_) \
catch ( std : : exception & problem ) \
{ \
const char * errID = lumiera_error ( ) ; \
WARN ( _FLAG_ , " %s failed: %s " , _OP_DESCR_ , problem . what ( ) ) ; \
TRACE ( debugging , " Error flag was: %s " , errID ) ; \
} \
catch ( . . . ) \
{ \
const char * errID = lumiera_error ( ) ; \
ERROR ( _FLAG_ , " %s failed with unknown exception; " \
" error flag is: %s " \
, _OP_DESCR_ , errID ) ; \
}
2007-08-19 21:57:19 +02:00
2013-10-24 23:06:36 +02:00
/**************************************************/ /**
2007-08-19 21:57:19 +02:00
* if NoBug is used , redefine some macros
2008-03-10 06:09:44 +01:00
* to rather throw Lumiera Errors instead of aborting
2007-08-19 21:57:19 +02:00
*/
2013-01-07 05:43:01 +01:00
#if 0 ///////////////////////////////////TODO disabled for now. NoBug aborts are hard and may hold some locks. There are hooks to allow throwing from NoBug TODO use them....
2007-08-19 21:57:19 +02:00
# ifdef NOBUG_ABORT
# undef NOBUG_ABORT
2008-03-10 08:38:59 +01:00
# define LUMIERA_NOBUG_LOCATION \
2007-08-26 19:14:39 +02:00
std : : string ( NOBUG_BASENAME ( __FILE__ ) ) + " : " + NOBUG_STRINGIZE ( __LINE__ ) + " , function " + __func__
# define NOBUG_ABORT \
2008-03-10 08:38:59 +01:00
lumiera : : error : : assertion_terminate ( LUMIERA_NOBUG_LOCATION ) ;
2007-08-19 21:57:19 +02:00
# endif
2009-01-24 03:15:02 +01:00
# endif
2007-08-19 21:57:19 +02:00
2008-03-10 06:09:44 +01:00
# endif // LUMIERA_ERROR_HPP_