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
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
Copyright ( C )
2011-02-05 20:56:51 +01:00
2008 , 2010 Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
* * Lumiera * * is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation ; either version 2 of the License , or ( at your
option ) any later version . See the file COPYING for further details .
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
2018-04-01 23:45:00 +02:00
* * when a unclear error state is detected .
2013-01-07 05:43:01 +01:00
* *
* * @ 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
2018-04-02 03:27:07 +02:00
# define _STDBOOL_H // prevent <atomic> from including stdbool.h
2009-01-25 00:24:42 +01:00
# include "include/logging.h"
2024-03-11 22:47:29 +01:00
# include "lib/hash-standard.hpp"
2007-08-26 19:14:39 +02:00
# include "lib/error.h"
2018-04-01 23:45:00 +02:00
2016-01-05 03:32:24 +01:00
# include <exception>
2014-08-17 08:03:21 +02:00
# include <string>
2007-08-14 08:14:21 +02:00
2018-04-01 23:45:00 +02:00
2024-03-16 02:04:47 +01:00
# define LERR_(_NAME_) lumiera::error::LUMIERA_ERROR_##_NAME_
2008-11-26 05:19:59 +01:00
namespace lumiera {
2007-08-26 19:14:39 +02:00
using std : : string ;
2018-04-01 23:45:00 +02:00
using CStr = const char * ;
2010-02-13 20:56:41 +01:00
2024-03-16 02:04:47 +01:00
namespace error {
/** error-ID for unspecified exceptions */
LUMIERA_ERROR_DECLARE ( EXCEPTION ) ;
}
2010-02-13 20:56:41 +01:00
2007-08-14 08:14:21 +02:00
/**
2018-04-01 23:45:00 +02:00
* Interface and Base definition for all Lumiera Exceptions .
2024-03-12 23:46:33 +01:00
* Provides common operations for getting a diagnostic message
* and to obtain the _root cause_ message , i . e . the message
2018-04-01 23:45:00 +02:00
* from the first exception encountered in a chain of exceptions .
2007-08-14 08:14:21 +02:00
*/
2018-04-01 23:45:00 +02:00
class Error
: public std : : exception
2007-08-14 08:14:21 +02:00
{
2018-04-01 23:45:00 +02:00
lumiera_err const id_ ; ///< an LUMIERA_ERROR id, which is set as errorstate on construction
string msg_ ; ///< friendly message intended for users (to be localised)
string desc_ ; ///< detailed description of the error situation for the developers
mutable string what_ ; ///< buffer for generating the detailed description on demand
const string cause_ ; ///< description of first exception encountered in the chain
2007-08-14 08:14:21 +02:00
public :
2018-04-01 23:45:00 +02:00
virtual ~ Error ( ) noexcept { } ; ///< this is an interface
2007-08-26 19:14:39 +02:00
2018-04-01 23:45:00 +02:00
Error ( string description = " "
, lumiera_err const id = LERR_ ( EXCEPTION ) ) noexcept ;
Error ( std : : exception const & cause
, string description = " "
, lumiera_err const id = LERR_ ( EXCEPTION ) ) noexcept ;
2007-08-17 00:36:07 +02:00
2018-04-01 23:45:00 +02:00
Error ( Error & & ) = default ;
Error ( Error const & ) = default ;
Error & operator = ( Error & & ) = delete ;
Error & operator = ( Error const & ) = delete ;
2010-02-13 20:56:41 +01:00
2018-04-01 23:45:00 +02:00
/** std::exception interface : yield a diagnostic message */
virtual CStr
what ( ) const noexcept override ;
/** the internal Lumiera-error-ID
* ( was set as C - errorstate in ctor ) */
lumiera_err
getID ( ) const noexcept
{
return id_ ;
}
2007-08-26 19:14:39 +02:00
/** extract the message to be displayed for the user */
2018-04-01 23:45:00 +02:00
string const &
getUsermsg ( ) const noexcept
{
return msg_ ;
}
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 .
2018-04-01 23:45:00 +02:00
* 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
*/
2018-04-01 23:45:00 +02:00
string const &
rootCause ( ) const noexcept
{
return cause_ ;
}
2010-02-13 20:56:41 +01:00
2018-04-01 23:45:00 +02:00
/** replace the previous or default friendly message for the user.
* @ note to be localised / translated .
*/
Error &
setUsermsg ( string const & newMsg ) noexcept
{
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. */
2018-04-01 23:45:00 +02:00
Error &
prependInfo ( string const & text ) noexcept
{
desc_ . insert ( 0 , text ) ;
return * this ;
}
2007-08-26 19:14:39 +02:00
2007-08-14 08:14:21 +02:00
private :
2018-04-01 23:45:00 +02:00
static const string
extractCauseMsg ( std : : exception const & ) noexcept ;
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
2018-04-01 23:45:00 +02:00
* encountered at functions declaring not to throw
2007-08-26 19:14:39 +02:00
* this kind of exception . Basically , any such event
* can be considered a severe design flaw ; we can just
* add some diagnostics prior to halting .
*/
2018-04-26 12:07:08 +02:00
void lumiera_unexpectedException ( ) noexcept ;
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
2024-03-12 20:14:29 +01:00
LUMIERA_ERROR_DECLARE ( SAFETY_LIMIT ) ; ///< exceeding fixed internal safety limit
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
2018-04-01 23:45:00 +02:00
/**
* Derived specific exceptions within Lumiera ' s exception hierarchy .
*/
template < lumiera_err const & eID , class PAR = Error >
class LumieraError
: public PAR
{
public :
LumieraError ( std : : string description = " "
, lumiera_err const id = eID ) noexcept
2018-04-14 03:24:45 +02:00
: PAR { description , id ? id : eID }
2018-04-01 23:45:00 +02:00
{ }
LumieraError ( std : : exception const & cause
, std : : string description = " "
, lumiera_err const id = eID ) noexcept
2018-04-14 03:24:45 +02:00
: PAR { cause , description , id ? id : eID }
2018-04-01 23:45:00 +02:00
{ }
2007-08-14 08:14:21 +02:00
} ;
2010-02-13 20:56:41 +01:00
2018-04-01 23:45:00 +02:00
//----CLASS-------------------ID--------------PARENT------
using Logic = LumieraError < LERR_ ( LOGIC ) > ;
using Fatal = LumieraError < LERR_ ( FATAL ) , Logic > ;
using State = LumieraError < LERR_ ( STATE ) > ;
using Flag = LumieraError < LERR_ ( FLAG ) , State > ;
using Invalid = LumieraError < LERR_ ( INVALID ) > ;
using Config = LumieraError < LERR_ ( CONFIG ) , Invalid > ;
using External = LumieraError < LERR_ ( 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 */
2018-04-01 23:45:00 +02:00
void install_unexpectedException_handler ( ) ;
2008-04-14 05:15:16 +02:00
2010-02-13 20:56:41 +01:00
/** @return error detail-info if currently set, a default message else */
2018-04-01 23:45:00 +02:00
CStr detailInfo ( ) ;
2010-02-13 20:56:41 +01:00
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
2024-03-12 23:46:33 +01:00
* the raised exception ; the error state is _not cleared_ .
2010-02-13 20:56:41 +01:00
*/
inline void
throwOnError ( )
{
if ( lumiera_err errorFlag = lumiera_error ( ) )
{
throw error : : Flag ( error : : detailInfo ( )
, errorFlag ) ;
2023-10-01 20:11:45 +02:00
} }
2010-02-13 20:56:41 +01:00
/** 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
2018-04-01 23:45:00 +02:00
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
{
2018-04-01 23:45:00 +02:00
throw EX ( error : : Flag { error : : detailInfo ( ) , errorFlag }
2010-02-13 20:56:41 +01:00
, description ) ;
} }
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 " \
2023-06-12 17:21:41 +02:00
, _OP_DESCR_ , errID ? errID : " ?? " ) ; \
2011-11-07 00:50:03 +01:00
}
2024-02-15 20:33:28 +01:00
# define ERROR_LOG_AND_RETHROW(_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 ) ; \
throw ; \
} \
catch ( . . . ) \
{ \
const char * errID = lumiera_error ( ) ; \
ERROR ( _FLAG_ , " %s failed with unknown exception; " \
" error flag is: %s " \
, _OP_DESCR_ , errID ? errID : " ?? " ) ; \
throw ; \
}
2021-04-04 15:46:40 +02:00
/******************************************************/ /**
* convenience shortcut to catch and absorb any exception ,
* then returning a default value instead . This scheme is
* typically used within signal handlers in the GTK UI ,
* since GTK ( written in C ) can not propagate exceptions
*/
# define ON_EXCEPTION_RETURN(_VAL_,_OP_DESCR_) \
catch ( std : : exception & problem ) \
{ \
const char * errID = lumiera_error ( ) ; \
2024-02-15 20:33:28 +01:00
WARN ( stage , " %s (Handler) failed: %s " , \
2021-04-04 15:46:40 +02:00
_OP_DESCR_ , problem . what ( ) ) ; \
TRACE ( debugging , " Error flag was: %s " , errID ) ; \
return ( _VAL_ ) ; \
} \
catch ( . . . ) \
{ \
const char * errID = lumiera_error ( ) ; \
2024-02-15 20:33:28 +01:00
ERROR ( stage , " (Handler) %s failed with " \
2021-04-04 15:46:40 +02:00
" unknown exception; error flag is: %s " \
2023-06-12 17:21:41 +02:00
, _OP_DESCR_ , errID ? errID : " ?? " ) ; \
2021-04-04 15:46:40 +02:00
return ( _VAL_ ) ; \
}
2007-08-19 21:57:19 +02:00
2013-10-24 23:06:36 +02:00
/**************************************************/ /**
2018-04-01 23:45:00 +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_