Files
Juliet/Juliet/include/Core/Common/CoreUtils.h

198 lines
7.6 KiB
C++

#pragma once
#include <Core/Common/CoreTypes.h>
#include <Juliet.h>
#include <algorithm>
#include <bit>
#include <cassert>
#include <concepts>
#include <source_location>
namespace Juliet
{
#define global static
// 1. Stringify helpers
#define JULIET_STR(x) #x
#define JULIET_TOSTRING(x) JULIET_STR(x)
// 2. Define the pragma operator based on compiler
#if defined(__clang__) || defined(__GNUC__)
#define JULIET_PRAGMA(x) _Pragma(#x)
#define JULIET_SUPPRESS_MSVC(id)
#define JULIET_SUPPRESS_CLANG(str) JULIET_PRAGMA(clang diagnostic ignored str)
#elif defined(_MSC_VER)
#define JULIET_PRAGMA(x) __pragma(x)
#define JULIET_SUPPRESS_MSVC(id) JULIET_PRAGMA(warning(disable : id))
#define JULIET_SUPPRESS_CLANG(str)
#else
#define JULIET_PRAGMA(x)
#define JULIET_SUPPRESS_MSVC(id)
#define JULIET_SUPPRESS_CLANG(str)
#endif
// 3. The Agnostic "Push/Pop"
#if defined(__clang__)
#define JULIET_WARNING_PUSH JULIET_PRAGMA(clang diagnostic push)
#define JULIET_WARNING_POP JULIET_PRAGMA(clang diagnostic pop)
#elif defined(_MSC_VER)
#define JULIET_WARNING_PUSH JULIET_PRAGMA(warning(push))
#define JULIET_WARNING_POP JULIET_PRAGMA(warning(pop))
#else
#define JULIET_WARNING_PUSH
#define JULIET_WARNING_POP
#endif
#if defined(_MSC_VER)
// MSVC specific intrinsic
#define JULIET_PLATFORM_BREAK() (__nop(), __debugbreak())
#elif defined(__clang__) || defined(__GNUC__)
// Clang/GCC specific intrinsic
#define JULIET_PLATFORM_BREAK() __builtin_trap()
#else
#include <signal.h>
#define JULIET_PLATFORM_BREAK() raise(SIGTRAP)
#endif
#if JULIET_DEBUG
#define JULIET_ASSERT_INTERNAL(expression, message) \
JULIET_WARNING_PUSH \
JULIET_SUPPRESS_CLANG("-Wextra-semi-stmt") \
JULIET_SUPPRESS_MSVC(4127) \
JULIET_SUPPRESS_MSVC(4548) \
{ \
if (!(expression)) [[unlikely]] \
{ \
Juliet::JulietAssert(#expression, message); \
} \
} \
JULIET_WARNING_POP \
static_assert(true, "")
#define AssertHR(hr_expression, message) \
do \
{ \
long hr_val = (hr_expression); \
if (hr_val < 0) \
{ \
Juliet::JulietAssert(#hr_expression, message, std::source_location::current(), hr_val); \
} \
} \
while (0)
#define GET_ASSERT_MACRO(_1, _2, NAME, ...) NAME
#define Assert(...) GET_ASSERT_MACRO(__VA_ARGS__, JULIET_ASSERT_INTERNAL, JULIET_ASSERT_NO_MSG)(__VA_ARGS__)
#define JULIET_ASSERT_NO_MSG(expression) JULIET_ASSERT_INTERNAL(expression, "No additional information provided.")
#define Unimplemented() \
do \
{ \
Juliet::JulietAssert("UNIMPLEMENTED", "This code path is not yet functional."); \
} \
while (0)
#else
#define Assert(...) ((void)0)
#define AssertHR(hr_expression, message) ((void)(hr_expression))
#define Unimplemented() ((void)0)
#endif
JULIET_API extern void JulietAssert(const char* expression, const char* message,
std::source_location location = std::source_location::current(), long handleResult = 0);
#define ZeroStruct(structInstance) ZeroSize(sizeof(structInstance), &(structInstance))
#define ZeroArray(array) ZeroSize(sizeof((array)), (array))
#define ZeroDynArray(Count, Pointer) ZeroSize((Count) * sizeof((Pointer)[0]), Pointer)
inline void ZeroSize(size_t size, void* ptr)
{
auto Byte = (uint8*)ptr;
while (size--)
{
*Byte++ = 0;
}
}
#define Restrict __restrict
template <class Function>
class DeferredFunction
{
public:
explicit DeferredFunction(const Function& otherFct) noexcept
: Callback(otherFct)
{
}
explicit DeferredFunction(Function&& otherFct) noexcept
: Callback(std::move(otherFct))
{
}
~DeferredFunction() noexcept { Callback(); }
DeferredFunction(const DeferredFunction&) = delete;
DeferredFunction(const DeferredFunction&&) = delete;
void operator=(const DeferredFunction&) = delete;
void operator=(DeferredFunction&&) = delete;
private:
Function Callback;
};
template <class Function>
auto Defer(Function&& fct) noexcept
{
return DeferredFunction<std::decay_t<Function>>{ std::forward<Function>(fct) };
}
inline bool IsValid(ByteBuffer buffer)
{
return buffer.Size > 0 && buffer.Data;
}
extern JULIET_API void Free(ByteBuffer& buffer);
template <std::integral T>
[[nodiscard]] constexpr T AlignPow2(T x, T alignment)
{
// Safety Check:
Assert(std::has_single_bit(static_cast<size_t>(alignment)));
return (x + alignment - 1) & ~(alignment - 1);
}
template <typename T>
inline void Swap(T* Restrict a, T* Restrict b)
{
T temp = std::move(*a);
*a = std::move(*b);
*b = std::move(temp);
}
// Move to another file dedicated to those
#if defined(__clang__)
#define COMPILER_CLANG 1
#elif defined(_MSC_VER)
#define COMPILER_MSVC 1
#endif
// Undef anything not defined
#if !defined(COMPILER_CLANG)
#define COMPILER_CLANG 0
#endif
#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif
#if COMPILER_MSVC
#define AlignOf(T) __alignof(T)
#elif COMPILER_CLANG
#define AlignOf(T) __alignof(T)
#elif COMPILER_GCC
#define AlignOf(T) __alignof__(T)
#else
#error AlignOf not defined for this compiler.
#endif
} // namespace Juliet