OpenFPGA/libs/libvtrutil/src/vtr_assert.h

137 lines
5.5 KiB
C++

#ifndef VTR_ASSERT_H
#define VTR_ASSERT_H
/*
* The header defines useful assertion macros for VTR projects.
*
* Three types of assertions are defined:
* VTR_ASSERT_OPT - low overhead assertions that should always be enabled
* VTR_ASSERT - medium overhead assertions that are usually be enabled
* VTR_ASSERT_SAFE - high overhead assertions typically enabled only for debugging
* VTR_ASSERT_DEBUG - very high overhead assertions typically enabled only for extreme debugging
* Each of the above assertions also have a *_MSG variants (e.g. VTR_ASSERT_MSG(expr, msg))
* which takes an additional argument specifying additional message text to be shown.
* By convention the message should state the condition *being checked* (and not the failure condition),
* since that the condition failed is obvious from the assertion failure itself.
*
* The macro VTR_ASSERT_LEVEL specifies the level of assertion checking desired:
*
* VTR_ASSERT_LEVEL == 4: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE, VTR_ASSERT_DEBUG enabled
* VTR_ASSERT_LEVEL == 3: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE enabled
* VTR_ASSERT_LEVEL == 2: VTR_ASSERT_OPT, VTR_ASSERT enabled
* VTR_ASSERT_LEVEL == 1: VTR_ASSERT_OPT enabled
* VTR_ASSERT_LEVEL == 0: No assertion checking enabled
* Note that an assertion levels beyond 4 are currently treated the same as level 4
*/
//Set a default assertion level if none is specified
#ifndef VTR_ASSERT_LEVEL
# define VTR_ASSERT_LEVEL 2
#endif
//Enable the assertions based on the specified level
#if VTR_ASSERT_LEVEL >= 4
# define VTR_ASSERT_DEBUG_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 3
# define VTR_ASSERT_SAFE_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 2
# define VTR_ASSERT_ENABLED
#endif
#if VTR_ASSERT_LEVEL >= 1
# define VTR_ASSERT_OPT_ENABLED
#endif
//Define the user assertion macros
#ifdef VTR_ASSERT_DEBUG_ENABLED
# define VTR_ASSERT_DEBUG(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_DEBUG_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_DEBUG(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_DEBUG_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_SAFE_ENABLED
# define VTR_ASSERT_SAFE(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_SAFE_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_SAFE(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_SAFE_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_ENABLED
# define VTR_ASSERT(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
#ifdef VTR_ASSERT_OPT_ENABLED
# define VTR_ASSERT_OPT(expr) VTR_ASSERT_IMPL(expr, nullptr)
# define VTR_ASSERT_OPT_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg)
#else
# define VTR_ASSERT_OPT(expr) VTR_ASSERT_IMPL_NOP(expr, nullptr)
# define VTR_ASSERT_OPT_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg)
#endif
//Define the assertion implementation macro
// We wrap the check in a do {} while() to ensure the function-like
// macro can be always be followed by a ';'
#define VTR_ASSERT_IMPL(expr, msg) \
do { \
if (!(expr)) { \
vtr::assert::handle_assert(#expr, __FILE__, __LINE__, VTR_ASSERT_FUNCTION, msg); \
} \
} while (false)
//Define the no-op assertion implementation macro
// We wrap the check in a do {} while() to ensure the function-like
// macro can be always be followed by a ';'
//
// Note that to avoid 'unused' variable warnings when assertions are
// disabled, we pass the expr and msg to sizeof(). We use sizeof specifically
// since it accepts expressions, and the C++ standard gaurentees sizeof's arguments
// are never evaluated (ensuring any expensive expressions are not evaluated when
// assertions are disabled). To avoid warnings about the unused result of sizeof()
// we cast it to void.
#define VTR_ASSERT_IMPL_NOP(expr, msg) \
do { \
static_cast<void>(sizeof(expr)); \
static_cast<void>(sizeof(msg)); \
} while (false)
//Figure out what macro to use to get the name of the current function
// We default to __func__ which is defined in C99
//
// g++ > 2.6 define __PRETTY_FUNC__ which includes class/namespace/overload
// information, so we prefer to use it if possible
#define VTR_ASSERT_FUNCTION __func__
#ifdef __GNUC__
# ifdef __GNUC_MINOR__
# if __GNUC__ >= 2 && __GNUC_MINOR__ > 6
# undef VTR_ASSERT_FUNCTION
# define VTR_ASSERT_FUNCTION __PRETTY_FUNCTION__
# endif
# endif
#endif
namespace vtr {
namespace assert {
//Assertion handling routine
//
//Note that we mark the routine with the standard C++11
//attribute 'noreturn' which tells the compiler this
//function will never return. This should ensure the
//compiler won't warn about detected conditions such as
//dead-code or potential null pointer dereferences
//which are gaurded against by assertions.
[[noreturn]] void handle_assert(const char* expr, const char* file, unsigned int line, const char* function, const char* msg);
} // namespace assert
} // namespace vtr
#endif //VTR_ASSERT_H