omni/core/Assert.h

File members: omni/core/Assert.h

// Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once

#include "Platform.h"
#include "VariadicMacroUtils.h"

#include <array>
#include <cstdio>
#include <utility>

namespace omni
{
namespace core
{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace detail
{

template <size_t N>
constexpr std::integral_constant<size_t, N - 1> length(const char (&)[N])
{
    return {};
}

template <size_t N>
constexpr std::integral_constant<size_t, N - 1> length(std::array<char, N>)
{
    return {};
}

template <typename T>
using LengthType = decltype(length(std::declval<T>()));

template <typename ARRAY>
constexpr void constCopyTo(ARRAY& out, size_t dst, const char* in, size_t sz)
{
    if (sz)
    {
        out[dst] = *in;
        constCopyTo(out, dst + 1, in + 1, sz - 1);
    }
}

template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N> constToArrayImpl(T (&a)[N], std::index_sequence<I...>)
{
    return { { a[I]... } };
}

template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> constToArray(T (&a)[N])
{
    return constToArrayImpl(a, std::make_index_sequence<N>{});
}

template <typename T>
constexpr const char* toChars(T& s)
{
    return s;
}

template <typename T, size_t N>
constexpr const char* toChars(const std::array<T, N>& s)
{
    return &(s[0]);
}

template <typename A, typename B, typename C>
constexpr std::array<char, LengthType<A>::value + LengthType<B>::value + LengthType<C>::value + 1> constConcat(
    const A& a, const B& b, const C& c)
{
    char o[LengthType<A>::value + LengthType<B>::value + LengthType<C>::value + 1]{};
    constCopyTo(o, 0, toChars(a), LengthType<A>::value);
    constCopyTo(o, LengthType<A>::value, toChars(b), LengthType<B>::value);
    constCopyTo(o, LengthType<A>::value + LengthType<B>::value, toChars(c), LengthType<C>::value);
    return constToArray(o);
}

template <typename A, typename B>
constexpr std::array<char, LengthType<A>::value + LengthType<B>::value + 1> constConcat(const A& a, const B& b)
{
    return constConcat(a, b, "");
}

template <typename A>
constexpr std::array<char, LengthType<A>::value + 1> constConcat(const A& a)
{
    return constConcat(a, "", "");
}

template <bool I>
struct Assertion
{
    constexpr static char Message[] = "Assertion (%s) failed:";
};

template <>
struct Assertion<false>
{
    constexpr static char Message[] = "Assertion (%s) failed.";
};

constexpr bool hasArg(const char*)
{
    return true;
}
constexpr bool hasArg()
{
    return false;
}

} // namespace detail
#endif
} // namespace core
} // namespace omni

#define OMNI_FATAL_UNLESS(cond_, ...)                                                                                  \
    do                                                                                                                 \
    {                                                                                                                  \
        if (!CARB_LIKELY(cond_))                                                                                       \
        {                                                                                                              \
            auto constexpr const failMsg_ = omni::core::detail::constConcat(                                           \
                omni::core::detail::Assertion<omni::core::detail::hasArg(OMNI_VA_FIRST(__VA_ARGS__))>::Message,        \
                OMNI_VA_FIRST_OR_EMPTY_STRING(__VA_ARGS__));                                                           \
            auto constexpr const fmt_ =                                                                                \
                omni::core::detail::constConcat(__FILE__ ":" CARB_STRINGIFY(__LINE__) ": ", failMsg_, "\n");           \
            std::fprintf(stderr, fmt_.data(), #cond_ OMNI_VA_COMMA_WITHOUT_FIRST(__VA_ARGS__));                        \
            OMNI_BREAK_POINT();                                                                                        \
        }                                                                                                              \
    } while (0)

#define OMNI_CHECK_ENABLED 1

#define OMNI_CHECK OMNI_FATAL_UNLESS

#if CARB_DEBUG
#    define OMNI_ASSERT(cond, ...) OMNI_FATAL_UNLESS(cond, __VA_ARGS__)

#    define OMNI_ASSERT_ENABLED 1
#else
#    define OMNI_ASSERT(cond, ...) ((void)0)

#    define OMNI_ASSERT_ENABLED 0
#endif