Commit 9c3af95c authored by Jakub Klinkovský's avatar Jakub Klinkovský
Browse files

Revised assert macros for Python bindings

parent cb838ebd
Loading
Loading
Loading
Loading
+120 −40
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
                          Assert.h  -  description
                             -------------------
    begin                : Jan 12, 2010
    copyright            : (C) 2013 by Tomas Oberhuber
    copyright            : (C) 2013 by Tomas Oberhuber et al.
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

@@ -10,21 +10,90 @@

#pragma once

#include <TNL/Devices/CudaCallable.h>

/****
 * Debugging assert
 * The purpose of this file is to define the TNL_ASSERT_* debugging macros as
 * shown below.
 *
 * If the 'NDEBUG' macro is defined, the build is considered to be optimized
 * and all assert macros are empty. Otherwise, the conditions are checked and
 * failures lead to the diagnostics message being printed to std::cerr and
 * program abortion (via 'throw EXIT_FAILURE' statement).
 *
 * For the purpose of providing Python bindings it is possible to change the
 * reporting behaviour by defining the TNL_THROW_ASSERTION_ERROR macro, which
 * leads to throwing the ::TNL::Assert::AssertionError holding the error
 * message (which is not printed in this case). The AssertionError class does
 * not inherit from std::exception to avoid being caught by normal exception
 * handlers, but the code for Python bindings can use it to translate it to the
 * Python's AssertionError exception.
 *
 * Implemented by: Jakub Klinkovsky
 */

#ifndef NDEBUG
#ifdef NDEBUG

// empty macros for optimized build
#define TNL_ASSERT_TRUE( val, msg )
#define TNL_ASSERT_FALSE( val, msg )
#define TNL_ASSERT_EQ( val1, val2, msg )
#define TNL_ASSERT_NE( val1, val2, msg )
#define TNL_ASSERT_LE( val1, val2, msg )
#define TNL_ASSERT_LT( val1, val2, msg )
#define TNL_ASSERT_GE( val1, val2, msg )
#define TNL_ASSERT_GT( val1, val2, msg )
#define TNL_ASSERT( ___tnl__assert_condition, ___tnl__assert_command )

#else /* #ifdef NDEBUG */

#include <sstream>
#include <iostream>
#include <stdio.h>

#include <TNL/Devices/CudaCallable.h>

namespace TNL {
namespace Assert {

#ifdef TNL_THROW_ASSERTION_ERROR
// This will be used by the code for Python bindings to translate assertion
// failures to the Python's AssertionError exception.
class AssertionError
{
public:
    AssertionError( const std::string& msg )
       : msg( msg )
    {}

    const char* what() const
    {
       return msg.c_str();
    }

private:
    std::string msg;
};

inline void
printDiagnosticsHost( const char* assertion,
                      const char* message,
                      const char* file,
                      const char* function,
                      int line,
                      const char* diagnostics )
{
   std::stringstream str;
   str << "Assertion '" << assertion << "' failed !!!\n"
       << "Message: " << message << "\n"
       << "File: " << file << "\n"
       << "Function: " << function << "\n"
       << "Line: " << line << "\n"
       << "Diagnostics:\n" << diagnostics << std::endl;
   throw AssertionError( str.str() );
}

#else // TNL_THROW_ASSERTION_ERROR

// This will be used in regular C++ code
inline void
printDiagnosticsHost( const char* assertion,
                      const char* message,
@@ -40,6 +109,7 @@ printDiagnosticsHost( const char* assertion,
             << "Line: " << line << "\n"
             << "Diagnostics:\n" << diagnostics << std::endl;
}
#endif // TNL_THROW_ASSERTION_ERROR

__cuda_callable__
inline void
@@ -247,7 +317,7 @@ TNL_IMPL_CMP_HELPER_( GT, > );


/****
 * Original assert macro with custom command for diagnostic.
 * Original assert macro with custom command for diagnostics.
 */

// __CUDA_ARCH__ is defined by the compiler only for code executed on GPU
@@ -262,7 +332,29 @@ TNL_IMPL_CMP_HELPER_( GT, > );
      asm("trap;");                                                                                            \
   }

#else // __CUDA_ARCH__
#else // #ifdef __CUDA_ARCH__
#ifdef TNL_THROW_ASSERTION_ERROR
// This will be used by the code for Python bindings to translate assertion
// failures to the Python's AssertionError exception.
#define TNL_ASSERT( ___tnl__assert_condition, ___tnl__assert_command )                                   \
   if( ! ( ___tnl__assert_condition ) )                                                                  \
   {                                                                                                     \
      std::stringstream buffer;                                                                          \
      auto old = std::cerr.rdbuf( buffer.rdbuf() );                                                      \
                                                                                                         \
      std::cerr << "Assertion '" << __STRING( ___tnl__assert_condition ) << "' failed !!!" << std::endl  \
                << "File: " << __FILE__ << std::endl                                                     \
                << "Function: " << __PRETTY_FUNCTION__ << std::endl                                      \
                << "Line: " << __LINE__ << std::endl                                                     \
                << "Diagnostics: ";                                                                      \
      ___tnl__assert_command;                                                                            \
                                                                                                         \
      std::string msg = buffer.str();                                                                    \
      std::cerr.rdbuf( old );                                                                            \
      throw ::TNL::Assert::AssertionError( msg );                                                        \
   }
#else // #ifdef TNL_THROW_ASSERTION_ERROR
// This will be used in regular C++ code
#define TNL_ASSERT( ___tnl__assert_condition, ___tnl__assert_command )                                   \
   if( ! ( ___tnl__assert_condition ) )                                                                  \
   {                                                                                                     \
@@ -274,19 +366,7 @@ TNL_IMPL_CMP_HELPER_( GT, > );
      ___tnl__assert_command;                                                                            \
      throw EXIT_FAILURE;                                                                                \
   }
#endif // __CUDA_ARCH__

#else /* #ifndef NDEBUG */

// empty macros for optimized build
#define TNL_ASSERT_TRUE( val, msg )
#define TNL_ASSERT_FALSE( val, msg )
#define TNL_ASSERT_EQ( val1, val2, msg )
#define TNL_ASSERT_NE( val1, val2, msg )
#define TNL_ASSERT_LE( val1, val2, msg )
#define TNL_ASSERT_LT( val1, val2, msg )
#define TNL_ASSERT_GE( val1, val2, msg )
#define TNL_ASSERT_GT( val1, val2, msg )
#define TNL_ASSERT( ___tnl__assert_condition, ___tnl__assert_command )
#endif // #ifdef TNL_THROW_ASSERTION_ERROR
#endif // #ifdef __CUDA_ARCH__

#endif /* #ifndef NDEBUG */
#endif // #ifdef NDEBUG