/*******************************************************************************
 * (c) Copyright 2015 Microsemi Corporation.  All rights reserved.
 *
 *
 *
 * SVN $Revision: $
 * SVN $Date: $
 */

/*!
 *\file
 *\brief
 *		 Assertions Module : Public Assertions interface
 */
#if !defined(EGL_ASSERT_H__)
#define EGL_ASSERT_H__

/*!
 *\brief
 *	 Run-time Conditional assert
 *
 *	 If EXPRESSION is FALSE, ASSERT.
 *
 *\param[in]	EXPRESSION		Expression to assert is NOT true
 *\param[in]	REASONCODE		Integer value to log with the assertion message
 */
#define EGL_ASSERT(EXPRESSION, REASONCODE)                                                          \
    do                                                                                          \
    {                                                                                           \
        if(!(EXPRESSION))                                                                       \
        {                                                                                       \
            egl_assert_abort(__FILE__, __FUNCTION__, __LINE__, (int)(REASONCODE), #EXPRESSION); \
        }                                                                                       \
    } while(0)

/*!
 *\brief
 *	 Run-time Null pointer assert
 *
 *	 This is the ONLY supported mechanism for asserting on NULL pointers.
 *	 Checks against 0 are NOT permitted
 *
 *\param[in]	PTR		Pointer to verify against NULL
 *
 */
#define ASSERT_NOT_NULL(PTR)                                                               \
    do                                                                                     \
    {                                                                                      \
        if((PTR) == NULL)                                                                  \
        {                                                                                  \
            egl_assert_abort(__FILE__, __FUNCTION__, __LINE__, 0, "NULL POINTER : " #PTR); \
        }                                                                                  \
    } while(0)

/*!
 *\brief
 *	 Run-time Unconditional assert
 *
 *   Include the REASONCODE in the logged message
 *
 *	 Use this when the code has reached an impossible or fatal location in the code
 *
 *\param[in]	REASONCODE		Integer value to log with the assertion message
 */
#define SWERR(REASONCODE)                                                               \
    do                                                                                  \
    {                                                                                   \
        egl_assert_abort(__FILE__, __FUNCTION__, __LINE__, (int)(REASONCODE), "SWERR"); \
    } while(0)

/* Static asserts allow compile time checks of constant expressions. They're supported in C++ 0X
 * and are being considered for the C1X standard. Examples:
 *
 * STATIC_ASSERT(sizeof(my_struct) == 512);
 * STATIC_ASSERT(sizeof(int) == 4);
 * STATIC_ASSERT(M_PI/2);
 */

/* Note we need the 2 concats below because arguments to ##
 * are not expanded, so we need to expand __LINE__ with one indirection
 * before doing the actual concatenation
 */
#define ASSERT_CONCAT_(a, b)   a##b
#define ASSERT_CONCAT(a, b)    ASSERT_CONCAT_(a, b)
/* This can't be used twice on the same line so ensure if using in headers
 * that the headers are not included twice (by wrapping in #ifndef...#endif)
 * Note it doesn't cause an issue when used on same line of separate modules
 * compiled with gcc -combine -fwhole-program.
 */

/*!
 *\brief
 *	 Compiletime conditional assert
 *
 *	 If EXPRESSION is FALSE, force a compile-time 'divide-by-zero'
 *
 *   This should ONLY appear in .c files, never in .h files.
 *
 *   This is useful for verifying items such as table sizes are as expected.
 */
#define STATIC_ASSERT(EXPRESSION)   enum { ASSERT_CONCAT(assert_line_, __COUNTER__) = 1/(!!(EXPRESSION)) }

#ifdef __cplusplus
extern "C" {
#endif


/*!
 *\brief
 *	 Initialise the assertions library
 *
 *	 This needs to be called once per application.
 *	 It must be called *before* any asserts are possible.
 */
extern void egl_assert_init(void);

/*
 *	 Cause the process/system to actually abort and restart
 *
 *	 This function is never called directly by the user, only via the #ASSERT macros
 */
extern void egl_assert_abort(const char* theFile,
                             const char* theFunction,
                             const int   theLine,
                             const int   assertionValue,
                             const char* theExpression);



#ifdef __cplusplus
}
#endif
#endif              /* EGL_ASSERT_H__ */


