LCOV - code coverage report
Current view: top level - tools - Exception.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 22 24 91.7 %
Date: 2021-11-18 15:22:58 Functions: 10 130 7.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2020 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #ifndef __PLUMED_tools_Exception_h
      23             : #define __PLUMED_tools_Exception_h
      24             : 
      25             : #include <string>
      26             : #include <stdexcept>
      27             : #include <sstream>
      28             : 
      29             : namespace PLMD {
      30             : 
      31             : /**
      32             : \ingroup TOOLBOX
      33             : Class to deal with Plumed runtime errors.
      34             : 
      35             : This class and the related macros can be used to detect programming
      36             : errors. Typical cases are internal inconsistencies or errors in the plumed<->MD
      37             : interface. Mistakes made by final users (i.e. in the `plumed.dat` file)
      38             : should probably be documented in some better way (e.g. printing parts of the manual in the output).
      39             : However, also this class allows for significant information to be attached.
      40             : Let's try to make error messages as informative as possible!
      41             : 
      42             : \note This class has been rewritten in PLUMED 2.5. It works in a backward compatible manner,
      43             : but is much more flexible. The main novelty is that we can use insertion operators to
      44             : add arbitrary messages, as in `plumed_error()<<"check this vector "<<v;`
      45             : See below for more details.
      46             : 
      47             : To throw an error, just throw a c++ exception
      48             : \verbatim
      49             :   if(something_bad) throw Exception();
      50             : \endverbatim
      51             : or better add an error message to that
      52             : \verbatim
      53             :   if(something_bad) throw Exception("describe the error here");
      54             : \endverbatim
      55             : 
      56             : As of PLUMED 2.5 you can add multiple messages, they will just be concatenated,
      57             : but to do se you should use the insertion operator. Notice that anything that
      58             : can be formatted with an insertion operator can go to the exception, even a \ref Vector
      59             : \verbatim
      60             :   Vector v;
      61             :   if(something_bad) throw Exception()<<"problem with this "<<v;
      62             : \endverbatim
      63             : In principle you can mix the two syntax (add a message as an argument and insert others with `<<`),
      64             : however it is not very clear and should be avoided.
      65             : We only allow using arguments in parenthesis in order to keep backward compatibility.
      66             : 
      67             : \par Using macros
      68             : 
      69             : In order to provide more context, especially for debugging, it might be useful to know where the exception
      70             : originated from. The macros below add information about the exact location of the error in the file (filename, line
      71             : and, when available, function name). Macros ending in "error" unconditionally throw
      72             : the exception, whereas macros ending in "assert" first perform a conditional check
      73             : (similarly to standard assert()).
      74             : An extra `m` in the name (e.g. `plumed_merror`) indicates a macro that provides a message as its argument.
      75             : However, as of PLUMED 2.5 we should prefer adding messages using insertion operators.
      76             : \verbatim
      77             : // this is correct but not recommended. add a message please!
      78             :   plumed_assert(a>0);
      79             : 
      80             : // this is the old syntax (with argument).
      81             : // this syntax is basically available for backward compatibility.
      82             :   plumed_massert(a>0,"a should be larger than zero);
      83             : 
      84             : // this is the recommended syntax, with insertion operators.
      85             : // it allows to easily insert multiple objects
      86             :   plumed_assert(a>0)<<"a should be larger than zero. a="<<a;
      87             : 
      88             : // same as above, but the test is made explicitly:
      89             :   if(a<=0) plumed_error();
      90             :   if(a<=0) plumed_error("a should be larger than zero);
      91             :   if(a<=0) plumed_error()<<"a should be larger than zero. a="<<a;
      92             : \endverbatim
      93             : 
      94             : The additional macros
      95             : plumed_dbg_assert() and plumed_dbg_massert() are similar
      96             : to plumed_assert() and plumed_massert() respectively, but the corresponding
      97             : check is only performed when NDEBUG macro is not defined. They should
      98             : be used when the check is expensive and should be skipped in production
      99             : code. So, for instance, in the following case:
     100             : \verbatim
     101             :   plumed_dbg_assert(expensive_function(i)>0)<<"message";
     102             : \endverbatim
     103             : `expensive_function()` is not called in the production code.
     104             : Notice that the compiler should be able to completely optimize away the
     105             : whole statement including functions used to produce the message as in this example:
     106             : \verbatim
     107             :   plumed_dbg_assert(expensive_function(i)>0)<<"I did this check "<<other_expensive_function(i);
     108             : \endverbatim
     109             : 
     110             : Finally, notice that there is another macro available, \ref plumed_here.
     111             : In can be used in order to create an exception with information about the
     112             : line/file coordinates without trowing it. That is, the two following syntaxes
     113             : are equivalent
     114             : \verbatim
     115             : // First way, all at once
     116             : plumed_error()<<"some message";
     117             : /////////////////////////////////
     118             : // Second way, one step at a time
     119             : // Create exception
     120             : Exception e;
     121             : // Append information about line and file
     122             : e<<plumed_here;
     123             : // Append some other message
     124             : e<<"some message";
     125             : // Throw the resulting exception
     126             : throw e;
     127             : \endverbatim
     128             : 
     129             : Exceptions can be caught within plumed or outside of it.
     130             : E.g., in an external c++ code using PLUMED as a library, one can type
     131             : \verbatim
     132             :   try{
     133             :     plumed.cmd("setPrecision",n);
     134             :   } catch (std::exception & e) {
     135             :     printf("ee %s",e.what());
     136             :     exit(1);
     137             :   }
     138             : \endverbatim
     139             : This can be useful if an external code wants to exit in a controlled manner
     140             : (e.g. flushing files, printing the error message in a specific file, etc.)
     141             : but is anyway limited to c++ codes. Moreover,
     142             : since these errors are expected to be unrecoverable, the MD code will
     143             : usually not be able to do something more clever than exiting.
     144             : 
     145             : \note
     146             : We store message and stack trace in growing strings. This is in
     147             : principle not recommended, since copying the exception might fail if
     148             : copying the string throw another exception. However, this has been like
     149             : this in all previous PLUMED versions. In case it is necessary, we can replace
     150             : it later with a fixed size array placed on the stack.
     151             : 
     152             : */
     153             : class Exception : public std::exception
     154             : {
     155             : /// Reported message
     156             :   std::string msg;
     157             : /// Stack trace at exception
     158             :   std::string stackString;
     159             : /// Flag to remembed if we have to write the `+++ message follows +++` string.
     160             : /// Needed so that the string appears only at the beginning of the message.
     161             :   bool note;
     162             : /// Stream used to insert objects.
     163             : /// It is not copied when the Exception is copied.
     164             :   std::stringstream stream;
     165             : 
     166             : public:
     167             : 
     168             : /// Auxiliary containing the location of the exception in the file.
     169             : /// Typically used from the macros below.
     170             :   class Location {
     171             :   public:
     172             :     const char*file;
     173             :     const unsigned line;
     174             :     const char* pretty;
     175          48 :     explicit Location(const char*file,unsigned line,const char* pretty=nullptr):
     176             :       file(file),
     177             :       line(line),
     178          48 :       pretty(pretty)
     179             :     {}
     180             :   };
     181             : 
     182             : /// Auxiliary containing the failed assertion.
     183             : /// Typically used from the macros below.
     184             :   class Assertion {
     185             :   public:
     186             :     const char*assertion;
     187          11 :     explicit Assertion(const char*assertion=nullptr):
     188          11 :       assertion(assertion)
     189             :     {}
     190             :   };
     191             : 
     192             : /// Default constructor with no message.
     193             : /// Only records the stack trace.
     194             :   Exception();
     195             : 
     196             : /// Constructor compatible with PLUMED <=2.4.
     197           3 :   explicit Exception(const std::string & msg):
     198           3 :     Exception()
     199             :   {
     200           3 :     *this << msg;
     201           3 :   }
     202             : 
     203             : /// Copy constructor.
     204             : /// Needed to make sure stream is not copied
     205          30 :   Exception(const Exception & e):
     206             :     msg(e.msg),
     207             :     stackString(e.stackString),
     208         120 :     note(e.note)
     209             :   {
     210          30 :   }
     211             : 
     212             : /// Assignment.
     213             : /// Needed to make sure stream is not copied
     214             :   Exception & operator=(const Exception & e) {
     215             :     msg=e.msg;
     216             :     stackString=e.stackString;
     217             :     note=e.note;
     218             :     stream.str("");
     219             :     return *this;
     220             :   }
     221             : 
     222             : /// Returns the error message.
     223             : /// In case the environment variable PLUMED_STACK_TRACE was defined
     224             : /// and equal to `yes` when the exception was raised,
     225             : /// the error message will contain the stack trace as well.
     226           0 :   virtual const char* what() const noexcept {return msg.c_str();}
     227             : 
     228             : /// Returns the stack trace.
     229             : /// Stack trace stored only if the required functions were found at configure time.
     230           0 :   virtual const char* stack() const noexcept {return stackString.c_str();}
     231             : 
     232             : /// Destructor should be defined and should not throw other exceptions
     233          62 :   virtual ~Exception() noexcept {}
     234             : 
     235             : /// Insert location.
     236             : /// Format the location properly.
     237             :   Exception& operator<<(const Location&);
     238             : 
     239             : /// Insert assertion.
     240             : /// Format the assertion properly
     241             :   Exception& operator<<(const Assertion&);
     242             : 
     243             : /// Insert string.
     244             : /// Append this string to the message.
     245             :   Exception& operator<<(const std::string&);
     246             : 
     247             : /// Insert anything else.
     248             : /// This allows to dump also other types (e.g. double, or even Vector).
     249             : /// Anything that can be written on a stream can go here.
     250             :   template<typename T>
     251          10 :   Exception& operator<<(const T & x) {
     252          10 :     stream<<x;
     253          20 :     (*this)<<stream.str();
     254          20 :     stream.str("");
     255          10 :     return *this;
     256             :   }
     257             : };
     258             : 
     259             : /// Class representing a generic error
     260         144 : class ExceptionError :
     261             :   public Exception {
     262             : public:
     263           1 :   using Exception::Exception;
     264             :   template<typename T>
     265             :   ExceptionError& operator<<(const T & x) {
     266          96 :     *((Exception*) this) <<x;
     267             :     return *this;
     268             :   }
     269             : };
     270             : 
     271             : /// Class representing a debug error (can only be thrown when using debug options)
     272           1 : class ExceptionDebug :
     273             :   public Exception {
     274             : public:
     275           1 :   using Exception::Exception;
     276             :   template<typename T>
     277             :   ExceptionDebug& operator<<(const T & x) {
     278             :     *((Exception*) this) <<x;
     279             :     return *this;
     280             :   }
     281             : };
     282             : 
     283             : #ifdef __GNUG__
     284             : // With GNU compiler, we can use __PRETTY_FUNCTION__ to get the function name
     285             : #define __PLUMED_FUNCNAME __PRETTY_FUNCTION__
     286             : #else
     287             : // Otherwise, we use the standard C++11 variable
     288             : #define __PLUMED_FUNCNAME __func__
     289             : #endif
     290             : 
     291             : /// \relates PLMD::Exception
     292             : /// Auxiliary macro that generates a PLMD::Exception::Location object.
     293             : /// Might be useful if we want to use derived exceptions that could
     294             : /// be thrown using `throw DerivedException()<<plumed_here<<" "<<other stuff"`.
     295             : /// It is used in the macros below to throw PLMD::Exception.
     296             : #define plumed_here PLMD::Exception::Location(__FILE__,__LINE__,__PLUMED_FUNCNAME)
     297             : 
     298             : /// \relates PLMD::Exception
     299             : /// Throw an exception with information about the position in the file.
     300             : /// Messages can be inserted with `plumed_error()<<"message"`.
     301             : #define plumed_error() throw PLMD::ExceptionError() << plumed_here
     302             : 
     303             : /// \relates PLMD::Exception
     304             : /// Throw an exception with information about the position in the file
     305             : /// and a message. Mostly available for backward compatibility
     306             : #define plumed_merror(msg) plumed_error() << msg
     307             : 
     308             : /// \relates PLMD::Exception
     309             : /// Launches plumed_merror only if test evaluates to false.
     310             : /// The string describing the test is also reported.
     311             : /// Further messages can be inserted with `<<`.
     312             : #define plumed_assert(test) if(!(test)) plumed_error() << PLMD::Exception::Assertion(#test)
     313             : 
     314             : /// \relates PLMD::Exception
     315             : /// Launches plumed_merror only if test evaluates to false.
     316             : /// The string describing the test is also reported, in addition to
     317             : /// messages reported in the extra argument. Mostly available for backward compatibility.
     318             : #define plumed_massert(test,msg) plumed_assert(test) << msg
     319             : 
     320             : #ifdef NDEBUG
     321             : 
     322             : // These are the versions used when compiling with NDEBUG flag.
     323             : // The condition is always true, so that the rest of the statement
     324             : // should be optimized away.
     325             : #define plumed_dbg_assert(test) plumed_assert(true)
     326             : #define plumed_dbg_massert(test,msg) plumed_massert(true,msg)
     327             : 
     328             : #else
     329             : 
     330             : /// \relates PLMD::Exception
     331             : /// Same as \ref plumed_assert, but only evaluates the condition if NDEBUG is not defined.
     332             : #define plumed_dbg_assert(test) if(!(test)) throw PLMD::ExceptionDebug() << plumed_here << PLMD::Exception::Assertion(#test)
     333             : 
     334             : /// \relates PLMD::Exception
     335             : /// Same as \ref plumed_massert, but only evaluates the condition if NDEBUG is not defined.
     336             : #define plumed_dbg_massert(test,msg) plumed_dbg_assert(test) << msg
     337             : 
     338             : #endif
     339             : 
     340             : }
     341             : #endif

Generated by: LCOV version 1.14