lemon/assert.h
changeset 127 1c9a9e2f7d4d
parent 112 d2ee5e7f00ef
child 142 8b703d177341
equal deleted inserted replaced
1:9411a9f95424 2:09d135cc2e1a
    24 /// \brief Extended assertion handling
    24 /// \brief Extended assertion handling
    25 
    25 
    26 #include <lemon/error.h>
    26 #include <lemon/error.h>
    27 
    27 
    28 namespace lemon {
    28 namespace lemon {
    29 
       
    30   /// @{
       
    31 
       
    32   ///\e
       
    33   class AssertionFailedError : public LogicError {
       
    34   protected:
       
    35     const char *_assertion;
       
    36     const char *_file;
       
    37     int _line;
       
    38     const char *_function;
       
    39     const char *_message;
       
    40 
       
    41     mutable ExceptionMember<std::string> _message_holder;
       
    42   public:
       
    43     ///\e
       
    44     AssertionFailedError(const char *file, int line, const char *function,
       
    45 			 const char *msg, const char *assertion = 0) :
       
    46       _assertion(assertion), _file(file), _line(line), 
       
    47       _function(function), _message(msg) {}
       
    48 
       
    49     ///\e
       
    50     const char* assertion() const { return _assertion; }
       
    51     ///\e
       
    52     const char* message() const { return _message; }
       
    53     ///\e
       
    54     const char* file() const { return _file; }
       
    55     ///\e
       
    56     const char* function() const { return _function; }
       
    57     ///\e
       
    58     int line() const { return _line; }
       
    59 
       
    60 
       
    61     virtual const char* what() const throw() {
       
    62       try {
       
    63 	std::ostringstream ostr;
       
    64 	ostr << _file << ":" << _line << ": ";
       
    65 	if (_function)
       
    66 	  ostr << _function << ": ";
       
    67 	ostr << _message;
       
    68 	if (_assertion)
       
    69 	   ostr << " (assertion '" << _assertion << "' failed)";
       
    70 	_message_holder.set(ostr.str());
       
    71 	return ostr.str().c_str();
       
    72       }
       
    73       catch(...) {}
       
    74       if( _message_holder.valid() ) return _message_holder.get().c_str();
       
    75       return "lemon::AssertionFailedError";
       
    76     }
       
    77     virtual ~AssertionFailedError() throw() {}
       
    78   };
       
    79 
       
    80 
       
    81   inline void assert_fail_log(const char *file, int line,
       
    82 			      const char *function,
       
    83 			      const std::exception& exception, 
       
    84 			      const char *assertion)
       
    85   {
       
    86     std::cerr << file << ":" << line << ": ";
       
    87     if (function)
       
    88       std::cerr << function << ": ";
       
    89     std::cerr << exception.what();
       
    90     if (assertion)
       
    91       std::cerr << " (assertion '" << assertion << "' failed)";
       
    92     std::cerr << std::endl;
       
    93   }
       
    94 
    29 
    95   inline void assert_fail_log(const char *file, int line, const char *function,
    30   inline void assert_fail_log(const char *file, int line, const char *function,
    96 			      const char *message, const char *assertion)
    31 			      const char *message, const char *assertion)
    97   {
    32   {
    98     std::cerr << file << ":" << line << ": ";
    33     std::cerr << file << ":" << line << ": ";
   102     if (assertion)
    37     if (assertion)
   103       std::cerr << " (assertion '" << assertion << "' failed)";
    38       std::cerr << " (assertion '" << assertion << "' failed)";
   104     std::cerr << std::endl;
    39     std::cerr << std::endl;
   105   }
    40   }
   106 
    41 
   107   inline void assert_fail_log(const char *file, int line, const char *function, 
       
   108 			      const std::string& message, const char *assertion)
       
   109   {
       
   110     assert_fail_log(file, line, function, message.c_str(), assertion);
       
   111   }
       
   112 
       
   113   inline void assert_fail_abort(const char *file, int line, 
       
   114 				const char *function,
       
   115 				const std::exception& exception,
       
   116 				const char *assertion)
       
   117   {
       
   118     assert_fail_log(file, line, function, exception, assertion);
       
   119     std::abort();
       
   120   }
       
   121 
       
   122   inline void assert_fail_abort(const char *file, int line,
    42   inline void assert_fail_abort(const char *file, int line,
   123 				const char *function, const char* message,
    43 				const char *function, const char* message,
   124 				const char *assertion)
    44 				const char *assertion)
   125   {
    45   {
   126     assert_fail_log(file, line, function, message, assertion);
    46     assert_fail_log(file, line, function, message, assertion);
   127     std::abort();
    47     std::abort();
   128   }
    48   }
   129 
    49 
   130   inline void assert_fail_abort(const char *file, int line, 
    50   namespace _assert_bits {
   131 				const char *function, 
    51     
   132 				const std::string& message,
    52     
   133 				const char *assertion)
    53     inline const char* cstringify(const std::string& str) {
   134   {
    54       return str.c_str();
   135     assert_fail_log(file, line, function, message.c_str(), assertion);
    55     }
   136     std::abort();
    56 
       
    57     inline const char* cstringify(const char* str) {
       
    58       return str;
       
    59     }    
   137   }
    60   }
   138 
       
   139   inline void assert_fail_error(const char *file, int line, 
       
   140 				  const char *function,
       
   141 				  const std::exception& exception,
       
   142 				  const char *assertion)
       
   143   {
       
   144     throw AssertionFailedError(file, line, function, 
       
   145 			       exception.what(), assertion);
       
   146   }
       
   147 
       
   148   inline void assert_fail_error(const char *file, int line,
       
   149 				  const char *function, const char *message,
       
   150 				  const char *assertion)
       
   151   {
       
   152     throw AssertionFailedError(file, line, function, message, assertion);
       
   153   }
       
   154 
       
   155   inline void assert_fail_error(const char *file, int line,
       
   156 				  const char *function, 
       
   157 				  const std::string& message,
       
   158 				  const char *assertion)
       
   159   {
       
   160     throw AssertionFailedError(file, line, function, message.c_str(), assertion);
       
   161   }
       
   162 
       
   163   template <typename Exception>
       
   164   inline void assert_fail_exception(const char *, int, const char *,
       
   165 				    const Exception& exception,
       
   166 				    const char *, const std::exception* = 
       
   167 				    static_cast<const Exception*>(0))
       
   168   {
       
   169     throw exception;
       
   170   }
       
   171 
       
   172   inline void assert_fail_exception(const char *file, int line,
       
   173 				    const char *function, const char *message,
       
   174 				    const char *assertion)
       
   175   {
       
   176     throw AssertionFailedError(file, line, function, message, assertion);
       
   177   }
       
   178 
       
   179   inline void assert_fail_exception(const char *file, int line, 
       
   180 				    const char *function, 
       
   181 				    const std::string& message,
       
   182 				    const char *assertion)
       
   183   {
       
   184     throw AssertionFailedError(file, line, function, message.c_str(), assertion);
       
   185   }
       
   186 
       
   187 /// @}
       
   188 
       
   189 }
    61 }
       
    62 
   190 #endif // LEMON_ASSERT_H
    63 #endif // LEMON_ASSERT_H
   191 
    64 
   192 #undef LEMON_ASSERT
    65 #undef LEMON_ASSERT
   193 #undef LEMON_FIXME
    66 #undef LEMON_FIXME
       
    67 #undef LEMON_DEBUG
   194 
    68 
   195 #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
    69 #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   196   (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
    70   (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   197   (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
       
   198   (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +		\
       
   199   (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
    71   (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1
   200 #error "LEMON assertion system is not set properly"
    72 #error "LEMON assertion system is not set properly"
   201 #endif
    73 #endif
   202 
    74 
   203 #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
    75 #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) +		\
   204      (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
    76      (defined(LEMON_ASSERT_ABORT) ? 1 : 0) +		\
   205      (defined(LEMON_ASSERT_ERROR) ? 1 : 0) +		\
       
   206      (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) +	\
       
   207      (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||	\
    77      (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 ||	\
   208      defined(LEMON_ENABLE_ASSERTS)) &&			\
    78      defined(LEMON_ENABLE_ASSERTS)) &&			\
   209   defined(LEMON_DISABLE_ASSERTS)
    79   (defined(LEMON_DISABLE_ASSERTS) ||			\
       
    80    defined(NDEBUG))
   210 #error "LEMON assertion system is not set properly"
    81 #error "LEMON assertion system is not set properly"
   211 #endif
    82 #endif
   212 
    83 
   213 
    84 
   214 #if defined LEMON_ASSERT_LOG
    85 #if defined LEMON_ASSERT_LOG
   215 #  undef LEMON_ASSERT_HANDLER
    86 #  undef LEMON_ASSERT_HANDLER
   216 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
    87 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log
   217 #elif defined LEMON_ASSERT_ABORT
    88 #elif defined LEMON_ASSERT_ABORT
   218 #  undef LEMON_ASSERT_HANDLER
    89 #  undef LEMON_ASSERT_HANDLER
   219 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
    90 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   220 #elif defined LEMON_ASSERT_ERROR
       
   221 #  undef LEMON_ASSERT_HANDLER
       
   222 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error
       
   223 #elif defined LEMON_ASSERT_EXCEPTION
       
   224 #  undef LEMON_ASSERT_HANDLER
       
   225 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception
       
   226 #elif defined LEMON_ASSERT_CUSTOM
    91 #elif defined LEMON_ASSERT_CUSTOM
   227 #  undef LEMON_ASSERT_HANDLER
    92 #  undef LEMON_ASSERT_HANDLER
   228 #  ifndef LEMON_CUSTOM_ASSERT_HANDLER
    93 #  ifndef LEMON_CUSTOM_ASSERT_HANDLER
   229 #    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
    94 #    error "LEMON_CUSTOM_ASSERT_HANDLER is not set"
   230 #  endif
    95 #  endif
   231 #  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
    96 #  define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER
   232 #elif defined LEMON_ENABLE_ASSERTS
    97 #elif defined LEMON_DISABLE_ASSERTS
   233 #  undef LEMON_ASSERT_HANDLER
    98 #  undef LEMON_ASSERT_HANDLER
       
    99 #elif defined NDEBUG
       
   100 #  undef LEMON_ASSERT_HANDLER
       
   101 #else
   234 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   102 #  define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort
   235 #else
   103 #endif
   236 #  undef LEMON_ASSERT_HANDLER
       
   237 #endif
       
   238 
       
   239 
   104 
   240 #ifndef LEMON_FUNCTION_NAME
   105 #ifndef LEMON_FUNCTION_NAME
   241 #  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
   106 #  define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__)
   242 #endif
   107 #endif
   243 
   108 
   245 
   110 
   246 /// \ingroup exceptions
   111 /// \ingroup exceptions
   247 ///
   112 ///
   248 /// \brief Macro for assertion with customizable message
   113 /// \brief Macro for assertion with customizable message
   249 ///
   114 ///
   250 /// Macro for assertion with customizable message.  
   115 /// Macro for assertion with customizable message.  \param exp An
   251 /// \param exp An expression that must be convertible to \c bool.
   116 /// expression that must be convertible to \c bool.  If it is \c
   252 /// If it is \c false, then an assertion is raised. The concrete
   117 /// false, then an assertion is raised. The concrete behaviour depends
   253 /// behaviour depends on the settings of the assertion system.
   118 /// on the settings of the assertion system.  \param msg A <tt>const
   254 /// \param msg A <tt>const char*</tt>, a <tt>const std::string&</tt> or
   119 /// char*</tt> parameter, which can be used to provide information
   255 /// a <tt>const std::exception&</tt> parameter, which can be used to
   120 /// about the circumstances of the failed assertion.
   256 /// provide information about the circumstances of the failed assertion.
   121 ///
   257 ///
   122 /// The assertions are enabled in the default behaviour.
   258 /// The assertions are disabled in the default behaviour.
   123 /// You can disable them with the following code:
   259 /// You can enable them with the following code:
   124 /// \code
   260 /// \code
   125 /// #define LEMON_DISABLE_ASSERTS
   261 /// #define LEMON_ENABLE_ASSERTS
       
   262 /// \endcode
   126 /// \endcode
   263 /// or with compilation parameters:
   127 /// or with compilation parameters:
   264 /// \code
   128 /// \code
   265 /// g++ -DLEMON_ENABLE_ASSERTS
   129 /// g++ -DLEMON_DISABLE_ASSERTS
   266 /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS'
   130 /// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS'
   267 /// \endcode
   131 /// \endcode
       
   132 /// The checking is also disabled when the standard macro \c NDEBUG is defined.
   268 /// 
   133 /// 
   269 /// The LEMON assertion system has a wide range of customization
   134 /// The LEMON assertion system has a wide range of customization
   270 /// properties. As a default behaviour the failed assertion prints a
   135 /// properties. As a default behaviour the failed assertion prints a
   271 /// short log message to the standard error and aborts the execution.
   136 /// short log message to the standard error and aborts the execution.
   272 ///
   137 ///
   273 /// The following modes can be used in the assertion system: 
   138 /// The following modes can be used in the assertion system: 
   274 ///
   139 ///
   275 /// - \c LEMON_ASSERT_LOG The failed assertion prints a short log
   140 /// - \c LEMON_ASSERT_LOG The failed assertion prints a short log
   276 ///   message to the standard error and continues the execution.
   141 ///   message to the standard error and continues the execution.
   277 /// - \c LEMON_ASSERT_ABORT This mode is similar to the
   142 /// - \c LEMON_ASSERT_ABORT This mode is similar to the \c
   278 ///   \c LEMON_ASSERT_LOG, but it aborts the program. It is the default
   143 ///   LEMON_ASSERT_LOG, but it aborts the program. It is the default
   279 ///   behaviour mode when the assertions are enabled with
   144 ///   behaviour.
   280 ///   \c LEMON_ENABLE_ASSERTS.
       
   281 /// - \c LEMON_ASSERT_ERROR The assertion throws an
       
   282 ///   \ref lemon::AssertionFailedError "AssertionFailedError".
       
   283 ///   If the \c msg parameter is an exception, then the result of the
       
   284 ///   \ref lemon::Exception::what() "what()" member function is passed
       
   285 ///   as error message.
       
   286 /// - \c LEMON_ASSERT_EXCEPTION If the specified \c msg is an
       
   287 ///   exception, then it raised directly (solving that the exception
       
   288 ///   can not be thrown polymorphically), otherwise an \ref
       
   289 ///   lemon::AssertionFailedError "AssertionFailedError" is thrown with
       
   290 ///   the given parameters.
       
   291 /// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler
   145 /// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler
   292 ///   functions. Three overloaded functions should be defined with the
   146 ///   function.
   293 ///   following parameter lists:
       
   294 ///   \code
   147 ///   \code
   295 ///     void custom_assert_handler(const char* file, int line, const char* function,
   148 ///     void custom_assert_handler(const char* file, int line, const char* function,
   296 ///                                const char* message, const char* assertion);
   149 ///                                const char* message, const char* assertion);
   297 ///     void custom_assert_handler(const char* file, int line, const char* function,
       
   298 ///                                const std::string& message, const char* assertion);
       
   299 ///     void custom_assert_handler(const char* file, int line, const char* function,
       
   300 ///                                const std::exception& message, const char* assertion);
       
   301 ///   \endcode
   150 ///   \endcode
   302 ///   The name of the functions should be defined as the \c
   151 ///   The name of the function should be defined as the \c
   303 ///   LEMON_CUSTOM_ASSERT_HANDLER macro name. 
   152 ///   LEMON_CUSTOM_ASSERT_HANDLER macro name. 
   304 ///   \code
   153 ///   \code
   305 ///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
   154 ///     #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler
   306 ///   \endcode
   155 ///   \endcode
   307 ///   Whenever an assertion is occured, one of the custom assertion
   156 ///   Whenever an assertion is occured, the custom assertion
   308 ///   handlers is called with appropiate parameters.
   157 ///   handler is called with appropiate parameters.
   309 ///
   158 ///
   310 /// The assertion mode can also be changed within one compilation unit.
   159 /// The assertion mode can also be changed within one compilation unit.
   311 /// If the macros are redefined with other settings and the
   160 /// If the macros are redefined with other settings and the
   312 /// \ref lemon/assert.h "assert.h" file is reincluded, then the
   161 /// \ref lemon/assert.h "assert.h" file is reincluded, then the
   313 /// behaviour is changed appropiately to the new settings.
   162 /// behaviour is changed appropiately to the new settings.
   314 #  define LEMON_ASSERT(exp, msg)					\
   163 #  define LEMON_ASSERT(exp, msg)					\
   315   (static_cast<void> (!!(exp) ? 0 : (					\
   164   (static_cast<void> (!!(exp) ? 0 : (					\
   316     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,				\
   165     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,				\
   317 			 LEMON_FUNCTION_NAME,				\
   166 			 LEMON_FUNCTION_NAME,				\
   318 			 msg, #exp), 0)))
   167 			 ::lemon::_assert_bits::cstringify(msg), #exp), 0)))
   319 
       
   320 
   168 
   321 /// \ingroup exceptions
   169 /// \ingroup exceptions
   322 ///
   170 ///
   323 /// \brief Macro for mark not yet implemented features.
   171 /// \brief Macro for mark not yet implemented features.
   324 ///
   172 ///
   325 /// Macro for mark not yet implemented features and outstanding bugs.
   173 /// Macro for mark not yet implemented features and outstanding bugs.
   326 /// It is close to be the shortcut of the following code:
   174 /// It is close to be the shortcut of the following code:
   327 /// \code
   175 /// \code
   328 ///   LEMON_ASSERT(false, msg);
   176 ///   LEMON_ASSERT(false, msg);
   329 /// \endcode
   177 /// \endcode
       
   178 ///
       
   179 /// \see LEMON_ASSERT 
   330 #  define LEMON_FIXME(msg)						\
   180 #  define LEMON_FIXME(msg)						\
   331        (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   181   (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   332 			     "FIXME: " msg, static_cast<const char*>(0)))
   182 			::lemon::_assert_bits::cstringify(msg),		\
       
   183 			static_cast<const char*>(0)))
       
   184 
       
   185 /// \ingroup exceptions
       
   186 ///
       
   187 /// \brief Macro for internal assertions
       
   188 ///
       
   189 /// Macro for internal assertions, it is used in the library to check
       
   190 /// the consistency of results of algorithms, several pre- and
       
   191 /// postconditions and invariants. The checking is disabled by
       
   192 /// default, but it can be turned on with the macro \c
       
   193 /// LEMON_ENABLE_DEBUG.
       
   194 /// \code
       
   195 /// #define LEMON_ENABLE_DEBUG
       
   196 /// \endcode
       
   197 /// or with compilation parameters:
       
   198 /// \code
       
   199 /// g++ -DLEMON_ENABLE_DEBUG
       
   200 /// make CXXFLAGS='-DLEMON_ENABLE_DEBUG'
       
   201 /// \endcode
       
   202 ///
       
   203 /// This macro works like the \c LEMON_ASSERT macro, therefore the
       
   204 /// current behaviour depends on the settings of \c LEMON_ASSERT
       
   205 /// macro.
       
   206 ///
       
   207 /// \see LEMON_ASSERT 
       
   208 #  define LEMON_DEBUG(exp, msg)						\
       
   209   (static_cast<void> (!!(exp) ? 0 : (					\
       
   210     LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                            \
       
   211 			 LEMON_FUNCTION_NAME,				\
       
   212 			 ::lemon::_assert_bits::cstringify(msg), #exp), 0)))
   333 
   213 
   334 #else
   214 #else
   335 
   215 
   336 #  ifndef LEMON_ASSERT_HANDLER
   216 #  ifndef LEMON_ASSERT_HANDLER
   337 #    define LEMON_ASSERT(exp, msg)  (static_cast<void>(0))
   217 #    define LEMON_ASSERT(exp, msg)  (static_cast<void>(0))
   338 #    define LEMON_FIXME(msg) (static_cast<void>(0))
   218 #    define LEMON_FIXME(msg) (static_cast<void>(0))
       
   219 #    define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
   339 #  else
   220 #  else
   340 #    define LEMON_ASSERT(exp, msg)                 \
   221 #    define LEMON_ASSERT(exp, msg)					\
   341        (static_cast<void> (!!(exp) ? 0 : (         \
   222        (static_cast<void> (!!(exp) ? 0 : (				\
   342          LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
   223         LEMON_ASSERT_HANDLER(__FILE__, __LINE__,                        \
   343                               LEMON_FUNCTION_NAME, \
   224 			     LEMON_FUNCTION_NAME,			\
   344                               msg, #exp), 0)))
   225 			     ::lemon::_assert_bits::cstringify(msg),	\
   345 #    define LEMON_FIXME(msg) \
   226 			     #exp), 0)))
       
   227 #    define LEMON_FIXME(msg)						\
   346        (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   228        (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME,	\
   347 			     "FIXME: " msg,  static_cast<const char*>(0)))
   229 			     ::lemon::_assert_bits::cstringify(msg),	\
       
   230 			     static_cast<const char*>(0)))
       
   231 
       
   232 #    if LEMON_ENABLE_DEBUG
       
   233 #      define LEMON_DEBUG(exp, msg)
       
   234          (static_cast<void> (!!(exp) ? 0 : (         \
       
   235            LEMON_ASSERT_HANDLER(__FILE__, __LINE__,  \
       
   236                                 LEMON_FUNCTION_NAME, \
       
   237 				::lemon::_assert_bits::cstringify(msg),	\
       
   238 				#exp), 0)))
       
   239 #    else
       
   240 #      define LEMON_DEBUG(exp, msg) (static_cast<void>(0))
       
   241 #    endif
   348 #  endif
   242 #  endif
   349 
   243 
   350 #endif
   244 #endif
   351 
   245 
   352 
   246 #ifdef DOXYGEN
       
   247 
       
   248 
       
   249 #else
       
   250 
       
   251 
       
   252 #endif
       
   253 
       
   254