LUMIERA.clone/src/lib/error.hpp

302 lines
10 KiB
C++
Raw Normal View History

/*
ERROR.hpp - Lumiera Exception Interface (C++)
2010-12-17 23:28:49 +01:00
Copyright (C) Lumiera.org
2008,2010 Hermann Vosseler <Ichthyostega@web.de>
2010-12-17 23:28:49 +01: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.
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
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 02139, USA.
2010-12-17 23:28:49 +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.
**
** @see error-state.c
** @see error.hpp
**
*/
2008-03-10 06:09:44 +01:00
#ifndef LUMIERA_ERROR_HPP_
#define LUMIERA_ERROR_HPP_
#include "include/logging.h"
#include "include/lifecycle.h"
2007-08-26 19:14:39 +02:00
#include "lib/error.h"
2018-04-01 23:45:00 +02:00
#include <exception>
#include <string>
2018-04-01 23:45:00 +02: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*;
2018-04-01 23:45:00 +02:00
#define LERR_(_NAME_) LUMIERA_ERROR_##_NAME_
2007-08-26 19:14:39 +02:00
/** error-ID for unspecified exceptions */
2018-04-01 23:45:00 +02:00
LUMIERA_ERROR_DECLARE(EXCEPTION);
/**
2018-04-01 23:45:00 +02:00
* Interface and Base definition for all Lumiera Exceptions.
* Provides common operations for getting an diagnostic message
* and to obtaining the _root cause_ message, i.e. the message
* from the first exception encountered in a chain of exceptions.
*/
2018-04-01 23:45:00 +02:00
class Error
: public std::exception
{
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
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;
2018-04-01 23:45:00 +02:00
Error (Error &&) = default;
Error (Error const&) = default;
Error& operator= (Error &&) = delete;
Error& operator= (Error const&) = delete;
/** 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_;
}
/** 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)
*/
2018-04-01 23:45:00 +02:00
string const&
rootCause () const noexcept
{
return cause_;
}
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;
}
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
private:
2018-04-01 23:45:00 +02:00
static const string
extractCauseMsg (std::exception const&) noexcept;
};
2007-08-26 19:14:39 +02:00
/* === Exception sub-categories === */
namespace error {
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.
*/
2008-03-10 06:09:44 +01:00
void lumiera_unexpectedException () throw();
2007-08-26 19:14:39 +02:00
/** throw an error::Fatal indicating "assertion failure" */
void assertion_terminate (const string& location);
2007-08-26 19:14:39 +02:00
/* constants to be used as error IDs */
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
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
/* generic error situations */
LUMIERA_ERROR_DECLARE (LIFECYCLE); ///< Lifecycle assumptions violated
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
LUMIERA_ERROR_DECLARE (CAPACITY); ///< predefined fixed storage capacity
LUMIERA_ERROR_DECLARE (INDEX_BOUNDS); ///< index out of bounds
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
LUMIERA_ERROR_DECLARE (UNIMPLEMENTED);///< unimplemented feature
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
: PAR{description, id}
{ }
LumieraError (std::exception const& cause
,std::string description=""
,lumiera_err const id=eID) noexcept
: PAR{cause, description, id}
{ }
};
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
/** install our own handler for undeclared exceptions. Will be
* called automatically ON_BASIC_INIT when linking exception.cpp */
2018-04-01 23:45:00 +02:00
void install_unexpectedException_handler();
/** @return error detail-info if currently set, a default message else */
2018-04-01 23:45:00 +02:00
CStr detailInfo();
} // namespace error
/**
* 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.
*/
template<class EX>
inline void
2018-04-01 23:45:00 +02:00
maybeThrow (string description ="")
{
if (lumiera_err errorFlag =lumiera_error())
{
2018-04-01 23:45:00 +02:00
throw EX (error::Flag{error::detailInfo(), errorFlag}
,description);
} }
2008-03-10 06:09:44 +01:00
} // namespace lumiera
/**************************************************//**
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); \
}
/**************************************************//**
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
*/
#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....
#ifdef NOBUG_ABORT
#undef NOBUG_ABORT
#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 \
lumiera::error::assertion_terminate (LUMIERA_NOBUG_LOCATION);
#endif
2009-01-24 03:15:02 +01:00
#endif
2008-03-10 06:09:44 +01:00
#endif // LUMIERA_ERROR_HPP_