text: //
  // Copyright (c) Microsoft. All rights reserved.
  // See https://aka.ms/azai/license202106 for the full license information.
  //
  
  #pragma once
  #include <azac_error.h>
  #include <inttypes.h>
  
  // TODO: TFS#3671215 - Vision: C/C++ azac_api* files are in shared include directory, speech and vision share
  
  #ifndef _MSC_VER
  // macros in this header generate a bunch of
  // "ISO C++11 requires at least one argument for the "..." in a variadic macro" errors.
  // system_header pragma is the only mechanism that helps to suppress them.
  // https://stackoverflow.com/questions/35587137/how-to-suppress-gcc-variadic-macro-argument-warning-for-zero-arguments-for-a-par
  // TODO: try to make macros standard-compliant.
  #pragma GCC system_header
  #endif
  
  #ifndef __cplusplus
  #define static_assert _Static_assert
  #endif
  
  #define UNUSED(x) (void)(x)
  
  //-------------------------------------------------------
  //  Re-enabled ability to compile out all macros...
  //  However, currently still need to keep all macros until
  //  final review of all macros is complete.
  //-------------------------------------------------------
  
  #define AZAC_CONFIG_TRACE_INCLUDE_DBG_WITH_ALL       1
  
  #ifdef AZAC_CONFIG_TRACE_INCLUDE_DBG_WITH_ALL
  #if defined(AZAC_CONFIG_TRACE_ALL) && !defined(AZAC_CONFIG_DBG_TRACE_ALL) && (!defined(DEBUG) || !defined(_DEBUG))
  #define AZAC_CONFIG_DBG_TRACE_ALL                    1
  #endif
  #endif
  
  //-------------------------------------------------------
  //  AZAC_ and AZAC_DBG_ macro configuration
  //-------------------------------------------------------
  
  #ifdef AZAC_CONFIG_DBG_TRACE_ALL
  #define AZAC_CONFIG_DBG_TRACE_VERBOSE               1
  #define AZAC_CONFIG_DBG_TRACE_INFO                  1
  #define AZAC_CONFIG_DBG_TRACE_WARNING               1
  #define AZAC_CONFIG_DBG_TRACE_ERROR                 1
  #define AZAC_CONFIG_DBG_TRACE_FUNCTION              1
  #define AZAC_CONFIG_DBG_TRACE_SCOPE                 1
  #define AZAC_CONFIG_DBG_TRACE_ASSERT                1
  #define AZAC_CONFIG_DBG_TRACE_VERIFY                1
  #ifndef AZAC_CONFIG_TRACE_ALL
  #define AZAC_CONFIG_TRACE_ALL                       1
  #endif
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_ALL
  #define AZAC_CONFIG_TRACE_VERBOSE                   1
  #define AZAC_CONFIG_TRACE_INFO                      1
  #define AZAC_CONFIG_TRACE_WARNING                   1
  #define AZAC_CONFIG_TRACE_ERROR                     1
  #define AZAC_CONFIG_TRACE_FUNCTION                  1
  #define AZAC_CONFIG_TRACE_SCOPE                     1
  #define AZAC_CONFIG_TRACE_THROW_ON_FAIL             1
  #define AZAC_CONFIG_TRACE_REPORT_ON_FAIL            1
  #define AZAC_CONFIG_TRACE_RETURN_ON_FAIL            1
  #define AZAC_CONFIG_TRACE_EXITFN_ON_FAIL            1
  #endif
  
  //-----------------------------------------------------------
  //  AZAC_TRACE macro common implementations
  //-----------------------------------------------------------
  
  #define __AZAC_TRACE_LEVEL_INFO         0x08 // Trace_Info
  #define __AZAC_TRACE_LEVEL_WARNING      0x04 // Trace_Warning
  #define __AZAC_TRACE_LEVEL_ERROR        0x02 // Trace_Error
  #define __AZAC_TRACE_LEVEL_VERBOSE      0x10 // Trace_Verbose
  
  #ifndef __AZAC_DO_TRACE_IMPL
  #ifdef __cplusplus
  #include <algorithm>
  #include <stdio.h>
  #include <stdarg.h>
  #include <string>
  inline void __azac_do_trace_message(int level, const char* pszTitle, const char* fileName, const int lineNumber, const char* pszFormat, ...) throw()
  {
      UNUSED(level);
  
      bool logToConsole = false;
  #if defined(DEBUG) || defined(_DEBUG)
      logToConsole = true;
  #endif
  
      if (!logToConsole)
      {
          return;
      }
  
      try
      {
          va_list argptr;
          va_start(argptr, pszFormat);
  
          std::string format;
          while (*pszFormat == '\n' || *pszFormat == '\r')
          {
              if (*pszFormat == '\r')
              {
                  pszTitle = nullptr;
              }
  
              format += *pszFormat++;
          }
  
          if (pszTitle != nullptr)
          {
              format += pszTitle;
          }
  
          std::string fileNameOnly(fileName);
          std::replace(fileNameOnly.begin(), fileNameOnly.end(), '\\', '/');
  
          std::string fileNameLineNumber = " " + fileNameOnly.substr(fileNameOnly.find_last_of('/', std::string::npos) + 1) + ":" + std::to_string(lineNumber) + " ";
  
          format += fileNameLineNumber;
  
          format += pszFormat;
  
          if (format.length() < 1 || format[format.length() - 1] != '\n')
          {
              format += "\n";
          }
  
          vfprintf(stderr, format.c_str(), argptr);
  
          va_end(argptr);
      }
      catch(...)
      {
      }
  }
  #define __AZAC_DO_TRACE_IMPL __azac_do_trace_message
  #else // __cplusplus
  #define __AZAC_DO_TRACE_IMPL
  #endif // __cplusplus
  #endif
  
  #define __AZAC_DOTRACE(level, title, fileName, lineNumber, ...)                     \
      do {                                                                            \
          __AZAC_DO_TRACE_IMPL(level, title, fileName, lineNumber, ##__VA_ARGS__);    \
      } while (0)
  
  #define __AZAC_TRACE_INFO(title, fileName, lineNumber, msg, ...) __AZAC_DOTRACE(__AZAC_TRACE_LEVEL_INFO, title, fileName, lineNumber, msg, ##__VA_ARGS__)
  #define __AZAC_TRACE_INFO_IF(cond, title, fileName, lineNumber, msg, ...)           \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              __AZAC_TRACE_INFO(title, fileName, lineNumber, msg, ##__VA_ARGS__);     \
      } } while (0)
  
  #define __AZAC_TRACE_WARNING(title, fileName, lineNumber, msg, ...) __AZAC_DOTRACE(__AZAC_TRACE_LEVEL_WARNING, title, fileName, lineNumber, msg, ##__VA_ARGS__)
  #define __AZAC_TRACE_WARNING_IF(cond, title, fileName, lineNumber, msg, ...)        \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              __AZAC_TRACE_WARNING(title, fileName, lineNumber, msg, ##__VA_ARGS__);  \
      } } while (0)
  
  #define __AZAC_TRACE_ERROR(title, fileName, lineNumber, msg, ...) __AZAC_DOTRACE(__AZAC_TRACE_LEVEL_ERROR, title, fileName, lineNumber, msg, ##__VA_ARGS__)
  #define __AZAC_TRACE_ERROR_IF(cond, title, fileName, lineNumber, msg, ...)          \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              __AZAC_TRACE_ERROR(title, fileName, lineNumber, msg, ##__VA_ARGS__);    \
      } } while (0)
  
  #define __AZAC_TRACE_VERBOSE(title, fileName, lineNumber, msg, ...) __AZAC_DOTRACE(__AZAC_TRACE_LEVEL_VERBOSE, title, fileName, lineNumber, msg, ##__VA_ARGS__)
  #define __AZAC_TRACE_VERBOSE_IF(cond, title, fileName, lineNumber, msg, ...)        \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              __AZAC_TRACE_VERBOSE(title, fileName, lineNumber, msg, ##__VA_ARGS__);  \
      } } while (0)
  
  #define ___AZAC_EXPR_AS_STRING(_String) "" #_String
  #define __AZAC_EXPR_AS_STRING(_String) ___AZAC_EXPR_AS_STRING(_String)
  
  #define __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x)             __AZAC_TRACE_ERROR(title, fileName, lineNumber, __AZAC_EXPR_AS_STRING(hr) " = 0x%0" PRIxPTR, x)
  
  #define __AZAC_REPORT_ON_FAIL(title, fileName, lineNumber, hr)                      \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (AZAC_FAILED(x)) {                                                       \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
      } } while (0)
  #define __AZAC_REPORT_ON_FAIL_IFNOT(title, fileName, lineNumber, hr, hrNot)         \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (x != hrNot) {                                                           \
              if (AZAC_FAILED(x)) {                                                   \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
      } } } while (0)
  
  #define __AZAC_T_RETURN_HR(title, fileName, lineNumber, hr)                         \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (AZAC_FAILED(x)) {                                                       \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
          }                                                                           \
          return x;                                                                   \
      } while (0)
  #define __AZAC_T_RETURN_HR_IF(title, fileName, lineNumber, hr, cond)                \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              AZACHR x = hr;                                                          \
              if (AZAC_FAILED(x)) {                                                   \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
              }                                                                       \
              return x;                                                               \
      } } while (0)
  #define __AZAC_T_RETURN_ON_FAIL(title, fileName, lineNumber, hr)                    \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (AZAC_FAILED(x)) {                                                       \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
              return x;                                                               \
      } } while (0)
  #define __AZAC_T_RETURN_ON_FAIL_IF_NOT(title, fileName, lineNumber, hr, hrNot)      \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (x != hrNot) {                                                           \
              if (AZAC_FAILED(x)) {                                                   \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
                  return x;                                                           \
      } } } while (0)
  #define __AZAC_RETURN_HR(hr) return hr
  #define __AZAC_RETURN_HR_IF(hr, cond)                           \
      do {                                                        \
          int fCond = !!(cond);                                   \
          if (fCond) {                                            \
              return hr;                                          \
      } } while (0)
  #define __AZAC_RETURN_ON_FAIL(hr)                               \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (AZAC_FAILED(x)) {                                   \
              return x;                                           \
      } } while (0)
  #define __AZAC_RETURN_ON_FAIL_IF_NOT(hr, hrNot)                 \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (x != hrNot) {                                       \
              if (AZAC_FAILED(x)) {                               \
                  return x;                                       \
      } } } while (0)
  
  #define __AZAC_T_EXITFN_HR(title, fileName, lineNumber, hr)                         \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (AZAC_FAILED(x)) {                                                       \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
          }                                                                           \
          goto AZAC_EXITFN_CLEANUP;                                                   \
      } while (0)
  #define __AZAC_T_EXITFN_HR_IF(title, fileName, lineNumber, hr, cond)                \
      do {                                                                            \
          int fCond = !!(cond);                                                       \
          if (fCond) {                                                                \
              AZACHR x = hr;                                                          \
              if (AZAC_FAILED(x)) {                                                   \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
              }                                                                       \
              goto AZAC_EXITFN_CLEANUP;                                               \
      } } while (0)
  #define __AZAC_T_EXITFN_ON_FAIL(title, fileName, lineNumber, hr)                    \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (AZAC_FAILED(x)) {                                                       \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
              goto AZAC_EXITFN_CLEANUP;                                               \
      } } while (0)
  #define __AZAC_T_EXITFN_ON_FAIL_IF_NOT(title, fileName, lineNumber, hr, hrNot)      \
      do {                                                                            \
          AZACHR x = hr;                                                              \
          if (x != hrNot) {                                                           \
              if (AZAC_FAILED(x)) {                                                   \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
                  goto AZAC_EXITFN_CLEANUP;                                           \
      } } } while (0)
  
  #define __AZAC_EXITFN_HR(hr)                                    \
      do {                                                        \
          AZACHR x = hr;                                          \
          goto AZAC_EXITFN_CLEANUP;                               \
      } while (0)
  #define __AZAC_EXITFN_HR_IF(hr, cond)                           \
      do {                                                        \
          int fCond = !!(cond);                                   \
          if (fCond) {                                            \
              AZACHR x = hr;                                      \
              goto AZAC_EXITFN_CLEANUP;                           \
      } } while (0)
  #define __AZAC_EXITFN_ON_FAIL(hr)                               \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (AZAC_FAILED(x)) {                                   \
              goto AZAC_EXITFN_CLEANUP;                           \
      } } while (0)
  #define __AZAC_EXITFN_ON_FAIL_IF_NOT(hr, hrNot)                 \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (x != hrNot) {                                       \
              if (AZAC_FAILED(x)) {                               \
                  goto AZAC_EXITFN_CLEANUP;                       \
      } } } while (0)
  
  #define __AZAC_TRACE_ASSERT(title, fileName, lineNumber, expr)          __AZAC_TRACE_ERROR(title, fileName, lineNumber, __AZAC_EXPR_AS_STRING(expr) " = false")
  #define __AZAC_TRACE_ASSERT_MSG(title, fileName, lineNumber, expr, ...) __AZAC_TRACE_ERROR(title, fileName, lineNumber, __AZAC_EXPR_AS_STRING(expr) " = false; " __VA_ARGS__)
  
  #define __AZAC_DBG_ASSERT(title, fileName, lineNumber, expr)                            \
      do {                                                                                \
          int fCond = !!(expr);                                                           \
          if (!fCond) {                                                                   \
              __AZAC_TRACE_ASSERT(title, fileName, lineNumber, expr);                     \
              abort();                                                                    \
      } } while (0)
  #define __AZAC_DBG_ASSERT_WITH_MESSAGE(title, fileName, lineNumber, expr, ...)          \
      do {                                                                                \
          int fCond = !!(expr);                                                           \
          if (!fCond) {                                                                   \
              __AZAC_TRACE_ASSERT_MSG(title, fileName, lineNumber, expr, ##__VA_ARGS__);  \
              abort();                                                                    \
      } } while (0)
  
  #define __AZAC_DBG_VERIFY(title, fileName, lineNumber, expr)                            \
      do {                                                                                \
          int fCond = !!(expr);                                                           \
          if (!fCond) {                                                                   \
              __AZAC_TRACE_ASSERT(title, fileName, lineNumber, expr);                     \
              abort();                                                                    \
      } } while (0)
  #define __AZAC_DBG_VERIFY_WITH_MESSAGE(title, fileName, lineNumber, expr, ...)          \
      do {                                                                                \
          int fCond = !!(expr);                                                           \
          if (!fCond) {                                                                   \
              __AZAC_TRACE_ASSERT_MSG(title, fileName, lineNumber, expr, ##__VA_ARGS__);  \
              abort();                                                                    \
      } } while (0)
  
  #ifdef __cplusplus
  
  #include <memory>
  #define __AZAC_TRACE_SCOPE(t1, fileName, lineNumber, t2, x, y)                                                  \
      __AZAC_TRACE_INFO(t1, fileName, lineNumber, "%s", x);                                                       \
      auto evaluateYInScopeInMacros##lineNumber = y;                                                              \
      auto leavingScopePrinterInMacros##lineNumber = [&evaluateYInScopeInMacros##lineNumber](int*) -> void {      \
          __AZAC_TRACE_INFO(t2, fileName, lineNumber, "%s", evaluateYInScopeInMacros##lineNumber);                \
      };                                                                                                          \
      std::unique_ptr<int, decltype(leavingScopePrinterInMacros##lineNumber)> onExit##lineNumber((int*)1, leavingScopePrinterInMacros##lineNumber)
  
  #ifndef __AZAC_THROW_HR_IMPL
  #define __AZAC_THROW_HR_IMPL(hr) __azac_rethrow(hr)
  #endif
  #ifndef __AZAC_THROW_HR
  #define __AZAC_THROW_HR(hr) __AZAC_THROW_HR_IMPL(hr)
  #endif
  
  #define __AZAC_T_THROW_ON_FAIL(title, fileName, lineNumber, hr)                 \
      do {                                                                        \
          AZACHR x = hr;                                                          \
          if (AZAC_FAILED(x)) {                                                   \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
              __AZAC_THROW_HR(x);                                                 \
      } } while (0)
  #define __AZAC_T_THROW_ON_FAIL_IF_NOT(title, fileName, lineNumber, hr, hrNot)   \
      do {                                                                        \
          AZACHR x = hr;                                                          \
          if (x != hrNot) {                                                       \
              if (AZAC_FAILED(x)) {                                               \
                  __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);            \
                  __AZAC_THROW_HR(x);                                             \
      } } } while (0)
  #define __AZAC_T_THROW_HR_IF(title, fileName, lineNumber, hr, cond)             \
      do {                                                                        \
          int fCond = !!(cond);                                                   \
          if (fCond) {                                                            \
              AZACHR x = hr;                                                      \
              __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                \
              __AZAC_THROW_HR(x);                                                 \
      } } while (0)
  #define __AZAC_T_THROW_HR(title, fileName, lineNumber, hr)                      \
      do {                                                                        \
          AZACHR x = hr;                                                          \
          __AZAC_TRACE_HR(title, fileName, lineNumber, hr, x);                    \
          __AZAC_THROW_HR(x);                                                     \
      } while (0)
  
  #define __AZAC_THROW_ON_FAIL(hr)                                \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (AZAC_FAILED(x)) {                                   \
              __AZAC_THROW_HR(x);                                 \
      } } while (0)
  #define __AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)                  \
      do {                                                        \
          AZACHR x = hr;                                          \
          if (x != hrNot) {                                       \
              if (AZAC_FAILED(x)) {                               \
                  __AZAC_THROW_HR(x);                             \
      } } } while (0)
  #define __AZAC_THROW_HR_IF(hr, cond)                            \
      do {                                                        \
          int fCond = !!(cond);                                   \
          if (fCond) {                                            \
              AZACHR x = hr;                                      \
              __AZAC_THROW_HR(x);                                 \
      } } while (0)
  
  #endif // __cplusplus
  
  
  
  //-------------------------------------------------------
  //  AZAC_ macro definitions
  //-------------------------------------------------------
  
  #ifdef AZAC_CONFIG_TRACE_VERBOSE
  #define AZAC_TRACE_VERBOSE(msg, ...)          __AZAC_TRACE_VERBOSE("AZAC_TRACE_VERBOSE: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_TRACE_VERBOSE_IF(cond, msg, ...) __AZAC_TRACE_VERBOSE_IF(cond, "AZAC_TRACE_VERBOSE: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_TRACE_VERBOSE(...)
  #define AZAC_TRACE_VERBOSE_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_VERBOSE
  #define AZAC_DBG_TRACE_VERBOSE(msg, ...)          __AZAC_TRACE_VERBOSE("AZAC_DBG_TRACE_VERBOSE: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_DBG_TRACE_VERBOSE_IF(cond, msg, ...) __AZAC_TRACE_VERBOSE_IF(cond, "AZAC_DBG_TRACE_VERBOSE: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_TRACE_VERBOSE(...)
  #define AZAC_DBG_TRACE_VERBOSE_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_INFO
  #define AZAC_TRACE_INFO(msg, ...)           __AZAC_TRACE_INFO("AZAC_TRACE_INFO: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_TRACE_INFO_IF(cond, msg, ...)  __AZAC_TRACE_INFO_IF(cond, "AZAC_TRACE_INFO: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_TRACE_INFO(...)
  #define AZAC_TRACE_INFO_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_INFO
  #define AZAC_DBG_TRACE_INFO(msg, ...)           __AZAC_TRACE_INFO("AZAC_DBG_TRACE_INFO: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_DBG_TRACE_INFO_IF(cond, msg, ...)  __AZAC_TRACE_INFO_IF(cond, "AZAC_DBG_TRACE_INFO: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_TRACE_INFO(...)
  #define AZAC_DBG_TRACE_INFO_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_WARNING
  #define AZAC_TRACE_WARNING(msg, ...)          __AZAC_TRACE_WARNING("AZAC_TRACE_WARNING:", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_TRACE_WARNING_IF(cond, msg, ...) __AZAC_TRACE_WARNING_IF(cond, "AZAC_TRACE_WARNING:", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_TRACE_WARNING(...)
  #define AZAC_TRACE_WARNING_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_WARNING
  #define AZAC_DBG_TRACE_WARNING(msg, ...)          __AZAC_TRACE_WARNING("AZAC_DBG_TRACE_WARNING:", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_DBG_TRACE_WARNING_IF(cond, msg, ...) __AZAC_TRACE_WARNING_IF(cond, "AZAC_DBG_TRACE_WARNING:", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_TRACE_WARNING(...)
  #define AZAC_DBG_TRACE_WARNING_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_ERROR
  #define AZAC_TRACE_ERROR(msg, ...)            __AZAC_TRACE_ERROR("AZAC_TRACE_ERROR: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_TRACE_ERROR_IF(cond, msg, ...)   __AZAC_TRACE_ERROR_IF(cond, "AZAC_TRACE_ERROR: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_TRACE_ERROR(...)
  #define AZAC_TRACE_ERROR_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_ERROR
  #define AZAC_DBG_TRACE_ERROR(msg, ...)            __AZAC_TRACE_ERROR("AZAC_DBG_TRACE_ERROR: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #define AZAC_DBG_TRACE_ERROR_IF(cond, msg, ...)   __AZAC_TRACE_ERROR_IF(cond, "AZAC_DBG_TRACE_ERROR: ", __FILE__, __LINE__, msg, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_TRACE_ERROR(...)
  #define AZAC_DBG_TRACE_ERROR_IF(...)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_FUNCTION
  #define AZAC_TRACE_FUNCTION(...) __AZAC_TRACE_VERBOSE("AZAC_TRACE_FUNCTION: ", __FILE__, __LINE__, __FUNCTION__)
  #else
  #define AZAC_TRACE_FUNCTION(...)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_FUNCTION
  #define AZAC_DBG_TRACE_FUNCTION(...) __AZAC_TRACE_VERBOSE("AZAC_DBG_TRACE_FUNCTION: ", __FILE__, __LINE__, __FUNCTION__)
  #else
  #define AZAC_DBG_TRACE_FUNCTION(...)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_REPORT_ON_FAIL
  #define AZAC_REPORT_ON_FAIL(hr)                     __AZAC_REPORT_ON_FAIL("AZAC_REPORT_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_REPORT_ON_FAIL_IFNOT(hr, hrNot)        __AZAC_REPORT_ON_FAIL_IFNOT("AZAC_REPORT_ON_FAIL: ", __FILE__, __LINE__, hr, hrNot)
  #else
  #define AZAC_REPORT_ON_FAIL(hr)                     UNUSED(hr)
  #define AZAC_REPORT_ON_FAIL_IFNOT(hr, hrNot)        UNUSED(hr); UNUSED(hrNot)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_RETURN_ON_FAIL
  #define AZAC_RETURN_HR(hr)                          __AZAC_T_RETURN_HR("AZAC_RETURN_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_RETURN_HR_IF(hr, cond)                 __AZAC_T_RETURN_HR_IF("AZAC_RETURN_ON_FAIL: ", __FILE__, __LINE__, hr, cond)
  #define AZAC_RETURN_ON_FAIL(hr)                     __AZAC_T_RETURN_ON_FAIL("AZAC_RETURN_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_RETURN_ON_FAIL_IF_NOT(hr, hrNot)       __AZAC_T_RETURN_ON_FAIL_IF_NOT("AZAC_RETURN_ON_FAIL: ", __FILE__, __LINE__, hr, hrNot)
  #else
  #define AZAC_RETURN_HR(hr)                          __AZAC_RETURN_HR(hr)
  #define AZAC_RETURN_HR_IF(hr, cond)                 __AZAC_RETURN_HR_IF(hr, cond)
  #define AZAC_RETURN_ON_FAIL(hr)                     __AZAC_RETURN_ON_FAIL(hr)
  #define AZAC_RETURN_ON_FAIL_IF_NOT(hr, hrNot)       __AZAC_RETURN_ON_FAIL_IF_NOT(hr, hrNot)
  #endif
  
  #define AZAC_IFTRUE_RETURN_HR(cond, hr)             AZAC_RETURN_HR_IF(hr, cond)
  #define AZAC_IFFALSE_RETURN_HR(cond, hr)            AZAC_RETURN_HR_IF(hr, !(cond))
  #define AZAC_IFFAILED_RETURN_HR(hr)                 AZAC_RETURN_ON_FAIL(hr)
  #define AZAC_IFFAILED_RETURN_HR_IFNOT(hr, hrNot)    AZAC_RETURN_ON_FAIL_IF_NOT(hr, hrNot)
  
  #define AZAC_IFTRUE_RETURN_X(cond, expr) \
      do {                                                        \
          int fCondT = !!(cond);                                  \
          if (fCondT) {                                           \
              return expr;                                        \
      } } while (0)
  
  #define AZAC_IFFALSE_RETURN_X(cond, expr) \
      do {                                                        \
          int fCondF = !!(cond);                                  \
          if (!fCondF) {                                          \
              return expr;                                        \
      } } while (0)
  
  #define AZAC_IFTRUE_RETURN(cond) \
      do {                                                        \
          int fCondT = !!(cond);                                  \
          if (fCondT) {                                           \
              return;                                             \
      } } while (0)
  
  #define AZAC_IFFALSE_RETURN(cond) \
      do {                                                        \
          int fCondF = !!(cond);                                  \
          if (!fCondF) {                                          \
              return;                                             \
      } } while (0)
  
  #ifdef AZAC_CONFIG_TRACE_EXITFN_ON_FAIL
  #define AZAC_EXITFN_HR(hr)                          __AZAC_T_EXITFN_HR("AZAC_EXITFN_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_EXITFN_HR_IF(hr, cond)                 __AZAC_T_EXITFN_HR_IF("AZAC_EXITFN_ON_FAIL: ", __FILE__, __LINE__, hr, cond)
  #define AZAC_EXITFN_ON_FAIL(hr)                     __AZAC_T_EXITFN_ON_FAIL("AZAC_EXITFN_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_EXITFN_ON_FAIL_IF_NOT(hr, hrNot)       __AZAC_EXITFN_ON_FAIL_IF_NOT("AZAC_EXITFN_ON_FAIL: ", __FILE__, __LINE__, hr, hrNot)
  #else
  #define AZAC_EXITFN_HR(hr)                          __AZAC_EXITFN_HR(hr)
  #define AZAC_EXITFN_HR_IF(hr, cond)                 __AZAC_EXITFN_HR_IF(hr, cond)
  #define AZAC_EXITFN_ON_FAIL(hr)                     __AZAC_EXITFN_ON_FAIL(hr)
  #define AZAC_EXITFN_ON_FAIL_IF_NOT(hr, hrNot)       __AZAC_EXITFN_ON_FAIL_IF_NOT(hr, hrNot)
  #endif
  
  #define AZAC_IFTRUE_EXITFN_WHR(cond, hr)            AZAC_EXITFN_HR_IF(hr, cond)
  #define AZAC_IFFALSE_EXITFN_WHR(cond, hr)           AZAC_EXITFN_HR_IF(hr, !(cond))
  #define AZAC_IFFAILED_EXITFN_WHR(hr)                AZAC_EXITFN_ON_FAIL(hr)
  #define AZAC_IFFAILED_EXITFN_WHR_IFNOT(hr, hrNot)   AZAC_EXITFN_ON_FAIL_IF_NOT(hr, hrNot)
  
  #define AZAC_IFTRUE_EXITFN_CLEANUP(cond, expr)                  \
      do {                                                        \
          int fCondT = !!(cond);                                  \
          if (fCondT) {                                           \
              expr;                                               \
              goto AZAC_EXITFN_CLEANUP;                           \
      } } while (0)
  
  #define AZAC_IFFALSE_EXITFN_CLEANUP(cond, expr)                 \
      do {                                                        \
          int fCondF = !!(cond);                                  \
          if (!fCondF) {                                          \
              expr;                                               \
              goto AZAC_EXITFN_CLEANUP;                           \
      } } while (0)
  
  #if defined(AZAC_CONFIG_DBG_TRACE_ASSERT) && (defined(DEBUG) || defined(_DEBUG))
  #define AZAC_DBG_ASSERT(expr)                   __AZAC_DBG_ASSERT("AZAC_ASSERT: ", __FILE__, __LINE__, expr)
  #define AZAC_DBG_ASSERT_WITH_MESSAGE(expr, ...) __AZAC_DBG_ASSERT_WITH_MESSAGE("AZAC_ASSERT: ", __FILE__, __LINE__, expr, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_ASSERT(expr)
  #define AZAC_DBG_ASSERT_WITH_MESSAGE(expr, ...)
  #endif
  
  #if defined(AZAC_CONFIG_DBG_TRACE_VERIFY) && (defined(DEBUG) || defined(_DEBUG))
  #define AZAC_DBG_VERIFY(expr)                   __AZAC_DBG_VERIFY("AZAC_VERIFY: ", __FILE__, __LINE__, expr)
  #define AZAC_DBG_VERIFY_WITH_MESSAGE(expr, ...) __AZAC_DBG_VERIFY_WITH_MESSAGE("AZAC_VERIFY: ", __FILE__, __LINE__, expr, ##__VA_ARGS__)
  #else
  #define AZAC_DBG_VERIFY(expr)                        (expr)
  #define AZAC_DBG_VERIFY_WITH_MESSAGE(expr, ...)      (expr)
  #endif
  
  #define AZAC_IFTRUE(cond, expr) \
      do {                                                        \
          int fCondT = !!(cond);                                  \
          if (fCondT) {                                           \
              expr;                                               \
      } } while (0)
  
  #define AZAC_IFFALSE(cond, expr) \
      do {                                                        \
          int fCondF = !!(cond);                                  \
          if (!fCondF) {                                          \
              expr;                                               \
      } } while (0)
  
  // handle circular dependency
  #ifndef AZAC_SUPRESS_COMMON_INCLUDE_FROM_DEBUG
  #define AZAC_SUPRESS_DEBUG_INCLUDE_FROM_COMMON
  #include <azac_api_c_common.h>
  #undef AZAC_SUPRESS_DEBUG_INCLUDE_FROM_COMMON
  #endif
  
  #ifdef __cplusplus
  
  #ifdef AZAC_CONFIG_TRACE_SCOPE
  #define AZAC_TRACE_SCOPE(x, y) __AZAC_TRACE_SCOPE("AZAC_TRACE_SCOPE_ENTER: ", __FILE__, __LINE__, "AZAC_TRACE_SCOPE_EXIT: ", x, y)
  #else
  #define AZAC_TRACE_SCOPE(x, y)
  #endif
  
  #ifdef AZAC_CONFIG_DBG_TRACE_SCOPE
  #define AZAC_DBG_TRACE_SCOPE(x, y) __AZAC_TRACE_SCOPE("AZAC_DBG_TRACE_SCOPE_ENTER: ", __FILE__, __LINE__, "AZAC_DBG_TRACE_SCOPE_EXIT: ", x, y)
  #else
  #define AZAC_DBG_TRACE_SCOPE(x, y)
  #endif
  
  #ifdef AZAC_CONFIG_TRACE_THROW_ON_FAIL
  #define AZAC_THROW_ON_FAIL(hr)                      __AZAC_T_THROW_ON_FAIL("AZAC_THROW_ON_FAIL: ", __FILE__, __LINE__, hr)
  #define AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)        __AZAC_T_THROW_ON_FAIL_IF_NOT("AZAC_THROW_ON_FAIL: ", __FILE__, __LINE__, hr, hrNot)
  #define AZAC_THROW_HR_IF(hr, cond)                  __AZAC_T_THROW_HR_IF("AZAC_THROW_HR_IF: ", __FILE__, __LINE__, hr, cond)
  #define AZAC_THROW_HR(hr)                           __AZAC_T_THROW_HR("AZAC_THROW_HR: ", __FILE__, __LINE__, hr)
  #else
  #define AZAC_THROW_ON_FAIL(hr)                      __AZAC_THROW_ON_FAIL(hr)
  #define AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)        __AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)
  #define AZAC_THROW_HR_IF(hr, cond)                  __AZAC_THROW_HR_IF(hr, cond)
  #define AZAC_THROW_HR(hr)                           __AZAC_THROW_HR(hr)
  #endif
  
  #define AZAC_IFTRUE_THROW_HR(cond, hr)              AZAC_THROW_HR_IF(hr, cond)
  #define AZAC_IFFALSE_THROW_HR(cond, hr)             AZAC_THROW_HR_IF(hr, !(cond))
  #define AZAC_IFFAILED_THROW_HR(hr)                  AZAC_THROW_ON_FAIL(hr)
  #define AZAC_IFFAILED_THROW_HR_IFNOT(hr, hrNot)     AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)
  
  #include <azac_api_c_error.h>
  #include <azac_api_c_diagnostics.h>
  #include <stdexcept>
  #include <string>
  
  inline void __azac_rethrow(AZACHR hr)
  {
      AZAC_TRACE_SCOPE("__azac_rethrow", "__azac_rethrow");
  
      auto handle = reinterpret_cast<AZAC_HANDLE>(hr);
      auto error = error_get_error_code(handle);
      if (error == AZAC_ERR_NONE)
      {
          throw hr;
      }
  
      auto callstack = error_get_call_stack(handle);
      auto what = error_get_message(handle);
  
      std::runtime_error er("");
      try
      {
          er = std::runtime_error(
              (what == nullptr ? "Exception with error code: " + std::to_string(error) : std::string(what)) +
              (callstack == nullptr ? "" : std::string(callstack)));
      }
      catch (...)
      {
          error_release(handle);
          throw hr;
      }
  
      error_release(handle);
      throw er;
  }
  
  #else // __cplusplus
  
  #define AZAC_TRACE_SCOPE(x, y)                      static_assert(false)
  #define AZAC_DBG_TRACE_SCOPE(x, y)                  static_assert(false)
  #define AZAC_THROW_ON_FAIL(hr)                      static_assert(false)
  #define AZAC_THROW_ON_FAIL_IF_NOT(hr, hrNot)        static_assert(false)
  #define AZAC_THROW_HR_IF(hr, cond)                  static_assert(false)
  #define AZAC_THROW_HR(hr)                           static_assert(false)
  #define AZAC_IFTRUE_THROW_HR(cond, hr)              static_assert(false)
  #define AZAC_IFFALSE_THROW_HR(cond, hr)             static_assert(false)
  #define AZAC_IFFAILED_THROW_HR(hr)                  static_assert(false)
  #define AZAC_IFFAILED_THROW_HR_IFNOT(hr, hrNot)     static_assert(false)
  
  #endif // __cplusplus
  
  //---------------------------------------------------------------------------
  
  #ifdef __AZAC_DEBUG_H_EXAMPLES_IN_MAIN
  
  void main()
  {
      int x = 4;
      printf("%s = %d\n", __AZAC_EXPR_AS_STRING(x + 3), x + 3);
  
      AZAC_TRACE_INFO("hello there");
      AZAC_TRACE_ERROR("hello there");
      AZAC_TRACE_WARNING("hello there");
      AZAC_TRACE_VERBOSE("hello there");
  
      AZAC_TRACE_INFO("hello there %d", 5);
      AZAC_TRACE_ERROR("hello there %d", 5);
      AZAC_TRACE_WARNING("hello there %d", 5);
      AZAC_TRACE_VERBOSE("hello there %d", 5);
  
      AZAC_TRACE_INFO_IF(false, "hello there false");
      AZAC_TRACE_ERROR_IF(false, "hello there false");
      AZAC_TRACE_WARNING_IF(false, "hello there false");
      AZAC_TRACE_VERBOSE_IF(false, "hello there false");
  
      AZAC_TRACE_INFO_IF(false, "hello there false %d", 5);
      AZAC_TRACE_ERROR_IF(false, "hello there false %d", 5);
      AZAC_TRACE_WARNING_IF(false, "hello there false %d", 5);
      AZAC_TRACE_VERBOSE_IF(false, "hello there false %d", 5);
  
      AZAC_TRACE_INFO_IF(true, "hello there true");
      AZAC_TRACE_ERROR_IF(true, "hello there true");
      AZAC_TRACE_WARNING_IF(true, "hello there true");
      AZAC_TRACE_VERBOSE_IF(true, "hello there true");
  
      AZAC_TRACE_INFO_IF(true, "hello there true %d", 5);
      AZAC_TRACE_ERROR_IF(true, "hello there true %d", 5);
      AZAC_TRACE_WARNING_IF(true, "hello there true %d", 5);
      AZAC_TRACE_VERBOSE_IF(true, "hello there true %d", 5);
  
      AZAC_DBG_TRACE_INFO("hello there");
      AZAC_DBG_TRACE_ERROR("hello there");
      AZAC_DBG_TRACE_WARNING("hello there");
      AZAC_DBG_TRACE_VERBOSE("hello there");
  
      AZAC_DBG_TRACE_INFO("hello there %d", 5);
      AZAC_DBG_TRACE_ERROR("hello there %d", 5);
      AZAC_DBG_TRACE_WARNING("hello there %d", 5);
      AZAC_DBG_TRACE_VERBOSE("hello there %d", 5);
  
      AZAC_DBG_TRACE_INFO_IF(false, "hello there false");
      AZAC_DBG_TRACE_ERROR_IF(false, "hello there false");
      AZAC_DBG_TRACE_WARNING_IF(false, "hello there false");
      AZAC_DBG_TRACE_VERBOSE_IF(false, "hello there false");
  
      AZAC_DBG_TRACE_INFO_IF(false, "hello there false %d", 5);
      AZAC_DBG_TRACE_ERROR_IF(false, "hello there false %d", 5);
      AZAC_DBG_TRACE_WARNING_IF(false, "hello there false %d", 5);
      AZAC_DBG_TRACE_VERBOSE_IF(false, "hello there false %d", 5);
  
      AZAC_DBG_TRACE_INFO_IF(true, "hello there true");
      AZAC_DBG_TRACE_ERROR_IF(true, "hello there true");
      AZAC_DBG_TRACE_WARNING_IF(true, "hello there true");
      AZAC_DBG_TRACE_VERBOSE_IF(true, "hello there true");
  
      AZAC_DBG_TRACE_INFO_IF(true, "hello there true %d", 5);
      AZAC_DBG_TRACE_ERROR_IF(true, "hello there true %d", 5);
      AZAC_DBG_TRACE_WARNING_IF(true, "hello there true %d", 5);
      AZAC_DBG_TRACE_VERBOSE_IF(true, "hello there true %d", 5);
  
      AZAC_TRACE_SCOPE("A", "B");
  
      AZAC_TRACE_FUNCTION();
      AZAC_DBG_TRACE_FUNCTION();
  
      AZAC_DBG_ASSERT(false);
      AZAC_DBG_ASSERT(true);
  
      AZAC_DBG_ASSERT_WITH_MESSAGE(false, "HEY!");
      AZAC_DBG_ASSERT_WITH_MESSAGE(true, "HEY!!");
  
      AZAC_DBG_VERIFY(false);
      AZAC_DBG_VERIFY(true);
  
      AZAC_DBG_VERIFY_WITH_MESSAGE(false, "HEY!");
      AZAC_DBG_VERIFY_WITH_MESSAGE(true, "HEY!!");
  
      AZACHR hr1 { 0x80001111 };
      AZACHR hr2 { 0x00001111 };
  
      AZAC_TRACE_VERBOSE("Testing out AZAC_REPORT_ON_FAIL, should see two failures...");
      AZAC_REPORT_ON_FAIL(hr1);
      AZAC_REPORT_ON_FAIL_IFNOT(hr1, 0x80001000);
      AZAC_TRACE_VERBOSE("Testing out AZAC_REPORT_ON_FAIL, should see two failures... Done!");
  
      AZAC_TRACE_VERBOSE("Testing out AZAC_REPORT_ON_FAIL, should see zero failures...");
      AZAC_REPORT_ON_FAIL(hr2);
      AZAC_REPORT_ON_FAIL_IFNOT(hr1, 0x80001111);
      AZAC_REPORT_ON_FAIL_IFNOT(hr2, 0x80001111);
      AZAC_REPORT_ON_FAIL_IFNOT(hr2, 0x80001000);
      AZAC_TRACE_VERBOSE("Testing out AZAC_REPORT_ON_FAIL, should see zero failures... Done!");
  }
  
  #endif
  