CedaAssert.h

// CedaAssert.h
//
// Author David Barrett-Lennard  
// (C)opyright Cedanet Pty Ltd 2004

#pragma once
#ifndef Ceda_cxUtils_CedaAssert_H
#define Ceda_cxUtils_CedaAssert_H

#include "cxUtils.h"

// From https://github.com/nemequ/portable-snippets/blob/master/debug-trap/debug-trap.h
#if defined(__has_builtin) && !defined(__ibmxl__)
#  if __has_builtin(__builtin_debugtrap)
#    define psnip_trap() __builtin_debugtrap()
#  elif __has_builtin(__debugbreak)
#    define psnip_trap() __debugbreak()
#  endif
#endif
#if !defined(psnip_trap)
#  if defined(_MSC_VER) || defined(__INTEL_COMPILER)
#    define psnip_trap() __debugbreak()
#  elif defined(__ARMCC_VERSION)
#    define psnip_trap() __breakpoint(42)
#  elif defined(__ibmxl__) || defined(__xlC__)
#    include <builtins.h>
#    define psnip_trap() __trap(42)
#  elif defined(__DMC__) && defined(_M_IX86)
     static inline void psnip_trap(void) { __asm int 3h; }
#  elif defined(__i386__) || defined(__x86_64__)
     static inline void psnip_trap(void) { __asm__ __volatile__("int3"); }
#  elif defined(__thumb__)
     static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xde01"); }
#  elif defined(__aarch64__)
     static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xd4200000"); }
#  elif defined(__arm__)
     static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xe7f001f0"); }
#  elif defined (__alpha__) && !defined(__osf__)
     static inline void psnip_trap(void) { __asm__ __volatile__("bpt"); }
#  elif defined(_54_)
     static inline void psnip_trap(void) { __asm__ __volatile__("ESTOP"); }
#  elif defined(_55_)
     static inline void psnip_trap(void) { __asm__ __volatile__(";\n .if (.MNEMONIC)\n ESTOP_1\n .else\n ESTOP_1()\n .endif\n NOP"); }
#  elif defined(_64P_)
     static inline void psnip_trap(void) { __asm__ __volatile__("SWBP 0"); }
#  elif defined(_6x_)
     static inline void psnip_trap(void) { __asm__ __volatile__("NOP\n .word 0x10000000"); }
#  elif defined(__STDC_HOSTED__) && (__STDC_HOSTED__ == 0) && defined(__GNUC__)
#    define psnip_trap() __builtin_trap()
#  else
#    include <signal.h>
#    if defined(SIGTRAP)
#      define psnip_trap() raise(SIGTRAP)
#    else
#      define psnip_trap() raise(SIGABRT)
#    endif
#  endif
#endif

#define cxBreakInDebugger() psnip_trap()

#ifdef CEDA_ASSERTION_FAILURE_THROWS_EXCEPTION
    #define cxAlwaysAssert(expr) (void) (!!(expr) || (ceda::ThrowCedaAssertionException(#expr, __FILE__, __LINE__),0) )
#else
    #define cxAlwaysAssert(expr) (void) (!!(expr) || !ceda::TraceAssertionError(#expr, __FILE__, __LINE__) || (cxBreakInDebugger(),0) )
#endif

#define cxAlwaysVerify(expr) cxAlwaysAssert(expr)

#ifdef CEDA_CHECK_ASSERTIONS
    #define cxAssert(expr) cxAlwaysAssert(expr)
    #define cxVerify(expr) cxAlwaysAssert(expr)
#else
    #define cxAssert(f)          ((void)0)
    #define cxVerify(f)          ((void)(f))
#endif

#define cxTodo()    cxAlwaysAssert(0)

#define cxAssertUnreachable() { cxAssert(0); ceda::DeclareUnreachable(); }

namespace ceda
{
// Should the assertion dialog be displayed when an assertion occurs?  This is false by default.  It can be 
// convenient to disable the dialog when it doesn't pin point the first assertion correctly, or you simply
// want to avoid seeing the dialog appear during program development.
cxUtils_API void EnableShowAssertionDialog(bool show);

// Used to trace the error to the trace file, and display the assertion dialog (if enabled)
// Returns true if the assertion should break the program for the debugger.
cxUtils_API bool TraceAssertionError(const char* expression, const char* file, int lineNumber);

// Throw a CedaAssertionException
cxUtils_API void ThrowCedaAssertionException(const char* expression, const char* file, int lineNumber);

[[noreturn]] inline void DeclareUnreachable() { throw; }
} // namespace ceda

#endif // include guard