/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

#pragma once

#include <executorch/runtime/platform/abort.h>
#include <executorch/runtime/platform/compiler.h>
#include <executorch/runtime/platform/log.h>

/**
 * Assertion failure message emit method.
 *
 * @param[in] _format Printf-style message format string.
 * @param[in] ... Format string arguments.
 */
#define ET_ASSERT_MESSAGE_EMIT(_format, ...)     \
  ET_LOG(                                        \
      Fatal,                                     \
      "In function %s(), assert failed" _format, \
      ET_FUNCTION,                               \
      ##__VA_ARGS__)

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed even in release builds.
 *
 * @param[in] _cond Condition asserted as true.
 * @param[in] _format Printf-style message format string.
 * @param[in] ... Format string arguments.
 */
#define ET_CHECK_MSG(_cond, _format, ...)                               \
  do {                                                                  \
    if ET_UNLIKELY (!(_cond)) {                                         \
      ET_ASSERT_MESSAGE_EMIT(" (%s): " _format, #_cond, ##__VA_ARGS__); \
      ::executorch::runtime::runtime_abort();                           \
    }                                                                   \
  } while (0)

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed even in release builds.
 *
 * @param[in] _cond Condition asserted as true.
 */
#define ET_CHECK(_cond)                       \
  do {                                        \
    if ET_UNLIKELY (!(_cond)) {               \
      ET_ASSERT_MESSAGE_EMIT(": %s", #_cond); \
      ::executorch::runtime::runtime_abort(); \
    }                                         \
  } while (0)

#ifdef NDEBUG

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed in debug builds, but not release builds.
 *
 * @param[in] _cond Condition asserted as true.
 * @param[in] _format Printf-style message format string.
 * @param[in] ... Format string arguments.
 */
#define ET_DCHECK_MSG(_cond, _format, ...) ((void)0)

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed in debug builds, but not release builds.
 *
 * @param[in] _cond Condition asserted as true.
 */
#define ET_DCHECK(_cond) ((void)0)
#define ET_DEBUG_ONLY [[maybe_unused]]

#else // NDEBUG

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed in debug builds, but not release builds.
 *
 * @param[in] _cond Condition asserted as true.
 * @param[in] _format Printf-style message format string.
 * @param[in] ... Format string arguments.
 */
#define ET_DCHECK_MSG(_cond, _format, ...) \
  ET_CHECK_MSG(_cond, _format, ##__VA_ARGS__)

/**
 * Abort the runtime if the condition is not true.
 * This check will be performed in debug builds, but not release builds.
 *
 * @param[in] _cond Condition asserted as true.
 */
#define ET_DCHECK(_cond) ET_CHECK(_cond)
#define ET_DEBUG_ONLY

#endif // NDEBUG

/**
 * Assert that this code location is unreachable during execution.
 */
#define ET_ASSERT_UNREACHABLE()                                   \
  do {                                                            \
    ET_CHECK_MSG(false, "Execution should not reach this point"); \
    ET_UNREACHABLE();                                             \
  } while (0)

/**
 * Assert that this code location is unreachable during execution.
 *
 * @param[in] _message Message on how to avoid this assertion error.
 */
#define ET_ASSERT_UNREACHABLE_MSG(_format, ...)            \
  do {                                                     \
    ET_CHECK_MSG(                                          \
        false,                                             \
        "Execution should not reach this point. " _format, \
        ##__VA_ARGS__);                                    \
    ET_UNREACHABLE();                                      \
  } while (0)
