aboutsummaryrefslogtreecommitdiff
path: root/zencore/include
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-09-15 19:49:20 +0200
committerStefan Boberg <[email protected]>2021-09-15 19:49:20 +0200
commit83ccd52321a23c8f1c8a3228cbbf34b8f199a22b (patch)
tree9cf1fb68651f616aef2fa28000e4f328ef9204d8 /zencore/include
parentAdded GetSize/GetData functions to reduce cognitive load and bridge the gap b... (diff)
parentTweaked logging to streamline access, and simplified setup code for new loggers (diff)
downloadzen-83ccd52321a23c8f1c8a3228cbbf34b8f199a22b.tar.xz
zen-83ccd52321a23c8f1c8a3228cbbf34b8f199a22b.zip
Merge branch 'main' into cbpackage-update
Diffstat (limited to 'zencore/include')
-rw-r--r--zencore/include/zencore/atomic.h31
-rw-r--r--zencore/include/zencore/compactbinary.h2
-rw-r--r--zencore/include/zencore/compactbinarybuilder.h2
-rw-r--r--zencore/include/zencore/endian.h12
-rw-r--r--zencore/include/zencore/except.h37
-rw-r--r--zencore/include/zencore/fmtutils.h2
-rw-r--r--zencore/include/zencore/intmath.h52
-rw-r--r--zencore/include/zencore/iohash.h1
-rw-r--r--zencore/include/zencore/logging.h27
-rw-r--r--zencore/include/zencore/memory.h32
-rw-r--r--zencore/include/zencore/sharedbuffer.h2
-rw-r--r--zencore/include/zencore/string.h10
-rw-r--r--zencore/include/zencore/thread.h8
-rw-r--r--zencore/include/zencore/timer.h10
-rw-r--r--zencore/include/zencore/zencore.h68
15 files changed, 252 insertions, 44 deletions
diff --git a/zencore/include/zencore/atomic.h b/zencore/include/zencore/atomic.h
index 457128bd4..7e261771b 100644
--- a/zencore/include/zencore/atomic.h
+++ b/zencore/include/zencore/atomic.h
@@ -2,7 +2,14 @@
#pragma once
+#include <zencore/zencore.h>
+
+#if ZEN_COMPILER_MSC
#include <intrin.h>
+#else
+#include <atomic>
+#endif
+
#include <cinttypes>
namespace zen {
@@ -10,34 +17,58 @@ namespace zen {
inline uint32_t
AtomicIncrement(volatile uint32_t& value)
{
+#if ZEN_COMPILER_MSC
return _InterlockedIncrement((long volatile*)&value);
+#else
+ return ((std::atomic<uint32_t>*)(&value))->fetch_add(1, std::memory_order_seq_cst) + 1;
+#endif
}
inline uint32_t
AtomicDecrement(volatile uint32_t& value)
{
+#if ZEN_COMPILER_MSC
return _InterlockedDecrement((long volatile*)&value);
+#else
+ return ((std::atomic<uint32_t>*)(&value))->fetch_sub(1, std::memory_order_seq_cst) - 1;
+#endif
}
inline uint64_t
AtomicIncrement(volatile uint64_t& value)
{
+#if ZEN_COMPILER_MSC
return _InterlockedIncrement64((__int64 volatile*)&value);
+#else
+ return ((std::atomic<uint64_t>*)(&value))->fetch_add(1, std::memory_order_seq_cst) + 1;
+#endif
}
inline uint64_t
AtomicDecrement(volatile uint64_t& value)
{
+#if ZEN_COMPILER_MSC
return _InterlockedDecrement64((__int64 volatile*)&value);
+#else
+ return ((std::atomic<uint64_t>*)(&value))->fetch_sub(1, std::memory_order_seq_cst) - 1;
+#endif
}
inline uint32_t
AtomicAdd(volatile uint32_t& value, uint32_t amount)
{
+#if ZEN_COMPILER_MSC
return _InterlockedExchangeAdd((long volatile*)&value, amount);
+#else
+ return ((std::atomic<uint32_t>*)(&value))->fetch_add(amount, std::memory_order_seq_cst);
+#endif
}
inline uint64_t
AtomicAdd(volatile uint64_t& value, uint64_t amount)
{
+#if ZEN_COMPILER_MSC
return _InterlockedExchangeAdd64((__int64 volatile*)&value, amount);
+#else
+ return ((std::atomic<uint64_t>*)(&value))->fetch_add(amount, std::memory_order_seq_cst);
+#endif
}
} // namespace zen
diff --git a/zencore/include/zencore/compactbinary.h b/zencore/include/zencore/compactbinary.h
index 09619be8b..4fce129ea 100644
--- a/zencore/include/zencore/compactbinary.h
+++ b/zencore/include/zencore/compactbinary.h
@@ -748,6 +748,8 @@ private:
friend class CbFieldViewIterator;
+ friend class CbFieldIterator;
+
/** Pointer to the first byte past the end of the last field. Set to null at the end. */
const void* FieldsEnd = nullptr;
};
diff --git a/zencore/include/zencore/compactbinarybuilder.h b/zencore/include/zencore/compactbinarybuilder.h
index f7f2bbfd3..5f6d9fd0c 100644
--- a/zencore/include/zencore/compactbinarybuilder.h
+++ b/zencore/include/zencore/compactbinarybuilder.h
@@ -533,7 +533,7 @@ operator<<(CbWriter& Writer, const CbArray& Value)
}
inline CbWriter&
-operator<<(CbWriter& Writer, nullptr_t)
+operator<<(CbWriter& Writer, std::nullptr_t)
{
Writer.AddNull();
return Writer;
diff --git a/zencore/include/zencore/endian.h b/zencore/include/zencore/endian.h
index 1f79a59e8..d44a27b01 100644
--- a/zencore/include/zencore/endian.h
+++ b/zencore/include/zencore/endian.h
@@ -7,19 +7,31 @@ namespace zen {
inline uint16_t
ByteSwap(uint16_t x)
{
+#if ZEN_COMPILER_MSC
return _byteswap_ushort(x);
+#else
+ return __builtin_bswap16(x);
+#endif
}
inline uint32_t
ByteSwap(uint32_t x)
{
+#if ZEN_COMPILER_MSC
return _byteswap_ulong(x);
+#else
+ return __builtin_bswap32(x);
+#endif
}
inline uint64_t
ByteSwap(uint64_t x)
{
+#if ZEN_COMPILER_MSC
return _byteswap_uint64(x);
+#else
+ return __builtin_bswap64(x);
+#endif
}
inline uint16_t
diff --git a/zencore/include/zencore/except.h b/zencore/include/zencore/except.h
index 8625f01d0..36cca895f 100644
--- a/zencore/include/zencore/except.h
+++ b/zencore/include/zencore/except.h
@@ -3,12 +3,18 @@
#pragma once
#include <zencore/string.h>
-#include <zencore/windows.h>
+#if ZEN_PLATFORM_WINDOWS
+# include <zencore/windows.h>
+#else
+# include <errno.h>
+#endif
#include <source_location>
#include <string>
+#include <system_error>
namespace zen {
+#if ZEN_PLATFORM_WINDOWS
class WindowsException : public std::exception
{
public:
@@ -45,17 +51,36 @@ private:
};
ZENCORE_API void ThrowSystemException(HRESULT hRes, std::string_view Message);
+#endif // ZEN_PLATFORM_WINDOWS
+
+ZENCORE_API void ThrowLastError(std::string_view Message);
+
+#if __cpp_lib_source_location
+ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location);
+#endif
+
+ZENCORE_API std::string GetLastErrorAsString();
+ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode);
inline void
ThrowSystemException(const char* Message)
{
+#if ZEN_PLATFORM_WINDOWS
throw WindowsException(Message);
+#else
+ ThrowLastError(Message);
+#endif
}
-ZENCORE_API void ThrowLastError(std::string_view Message);
-ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location);
-ZENCORE_API std::string GetLastErrorAsString();
-ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode);
+inline int32_t
+GetLastError()
+{
+#if ZEN_PLATFORM_WINDOWS
+ return ::GetLastError();
+#else
+ return errno;
+#endif
+}
inline std::error_code
MakeWin32ErrorCode(uint32_t Win32ErrorCode) noexcept
@@ -66,7 +91,7 @@ MakeWin32ErrorCode(uint32_t Win32ErrorCode) noexcept
inline std::error_code
MakeErrorCodeFromLastError() noexcept
{
- return std::error_code(::GetLastError(), std::system_category());
+ return std::error_code(zen::GetLastError(), std::system_category());
}
} // namespace zen
diff --git a/zencore/include/zencore/fmtutils.h b/zencore/include/zencore/fmtutils.h
index fb5a08d56..29e2ae78a 100644
--- a/zencore/include/zencore/fmtutils.h
+++ b/zencore/include/zencore/fmtutils.h
@@ -43,7 +43,7 @@ struct fmt::formatter<std::filesystem::path> : formatter<string_view>
auto format(const std::filesystem::path& Path, FormatContext& ctx)
{
zen::ExtendableStringBuilder<128> String;
- WideToUtf8(Path.c_str(), String);
+ String << Path.u8string();
return formatter<string_view>::format(String.ToView(), ctx);
}
};
diff --git a/zencore/include/zencore/intmath.h b/zencore/include/zencore/intmath.h
index 792b8b2b4..814a03df4 100644
--- a/zencore/include/zencore/intmath.h
+++ b/zencore/include/zencore/intmath.h
@@ -9,8 +9,46 @@
//////////////////////////////////////////////////////////////////////////
-#pragma intrinsic(_BitScanReverse)
-#pragma intrinsic(_BitScanReverse64)
+#if ZEN_COMPILER_MSC || ZEN_PLATFORM_WINDOWS
+# pragma intrinsic(_BitScanReverse)
+# pragma intrinsic(_BitScanReverse64)
+#else
+inline uint8_t
+_BitScanReverse(unsigned long* Index, uint32_t Mask)
+{
+ if (Mask == 0)
+ {
+ return 0;
+ }
+
+ *Index = __builtin_clz(Mask);
+ return 1;
+}
+
+inline uint8_t
+_BitScanReverse64(unsigned long* Index, uint64_t Mask)
+{
+ if (Mask == 0)
+ {
+ return 0;
+ }
+
+ *Index = __builtin_clzll(Mask);
+ return 0;
+}
+
+inline uint8_t
+_BitScanForward64(unsigned long* Index, uint64_t Mask)
+{
+ if (Mask == 0)
+ {
+ return 0;
+ }
+
+ *Index = __builtin_ctzll(Mask);
+ return 0;
+}
+#endif
namespace zen {
@@ -121,8 +159,10 @@ IsPointerAligned(const void* Ptr, uint64_t Alignment)
//////////////////////////////////////////////////////////////////////////
-#ifdef min
-# error "Looks like you did #include <windows.h> -- use <zencore/windows.h> instead"
+#if ZEN_PLATFORM_WINDOWS
+# ifdef min
+# error "Looks like you did #include <windows.h> -- use <zencore/windows.h> instead"
+# endif
#endif
constexpr auto
@@ -137,4 +177,8 @@ Max(auto x, auto y)
return x > y ? x : y;
}
+//////////////////////////////////////////////////////////////////////////
+
+void intmath_forcelink(); // internal
+
} // namespace zen
diff --git a/zencore/include/zencore/iohash.h b/zencore/include/zencore/iohash.h
index aaa638684..fd0f4b2a7 100644
--- a/zencore/include/zencore/iohash.h
+++ b/zencore/include/zencore/iohash.h
@@ -8,6 +8,7 @@
#include <zencore/blake3.h>
#include <zencore/memory.h>
+#include <compare>
#include <string_view>
namespace zen {
diff --git a/zencore/include/zencore/logging.h b/zencore/include/zencore/logging.h
index a2404a5e9..4eee20414 100644
--- a/zencore/include/zencore/logging.h
+++ b/zencore/include/zencore/logging.h
@@ -13,6 +13,7 @@
namespace zen::logging {
spdlog::logger& Default();
+void SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger);
spdlog::logger& ConsoleLog();
spdlog::logger& Get(std::string_view Name);
@@ -20,3 +21,29 @@ void InitializeLogging();
void ShutdownLogging();
} // namespace zen::logging
+
+namespace zen {
+extern spdlog::logger* TheDefaultLogger;
+
+inline spdlog::logger&
+Log()
+{
+ return *TheDefaultLogger;
+}
+
+using logging::ConsoleLog;
+} // namespace zen
+
+using zen::ConsoleLog;
+using zen::Log;
+
+// Helper macros for logging
+
+using namespace std::literals;
+
+#define ZEN_TRACE(fmtstr, ...) Log().trace(fmtstr##sv, __VA_ARGS__)
+#define ZEN_DEBUG(fmtstr, ...) Log().debug(fmtstr##sv, __VA_ARGS__)
+#define ZEN_INFO(fmtstr, ...) Log().info(fmtstr##sv, __VA_ARGS__)
+#define ZEN_WARN(fmtstr, ...) Log().warn(fmtstr##sv, __VA_ARGS__)
+#define ZEN_ERROR(fmtstr, ...) Log().error(fmtstr##sv, __VA_ARGS__)
+#define ZEN_CRITICAL(fmtstr, ...) Log().critical(fmtstr##sv, __VA_ARGS__)
diff --git a/zencore/include/zencore/memory.h b/zencore/include/zencore/memory.h
index 5a324955d..9d6339595 100644
--- a/zencore/include/zencore/memory.h
+++ b/zencore/include/zencore/memory.h
@@ -8,6 +8,8 @@
#include <zencore/thread.h>
#include <algorithm>
+#include <cstddef>
+#include <cstring>
#include <span>
#include <vector>
@@ -81,7 +83,7 @@ struct MutableMemoryView
{
}
- inline bool IsEmpty() const { return m_Data == m_DataEnd; }
+ inline bool IsEmpty() const { return m_Data == m_DataEnd; }
void* GetData() const { return m_Data; }
void* GetDataEnd() const { return m_DataEnd; }
size_t GetSize() const { return reinterpret_cast<uint8_t*>(m_DataEnd) - reinterpret_cast<uint8_t*>(m_Data); }
@@ -111,7 +113,7 @@ struct MutableMemoryView
}
/** Modifies the view by chopping the given number of bytes from the left. */
- inline constexpr void RightChopInline(uint64_t InSize)
+ inline void RightChopInline(uint64_t InSize)
{
const uint64_t Offset = zen::Min(GetSize(), InSize);
m_Data = GetDataAtOffsetNoCheck(Offset);
@@ -151,7 +153,7 @@ struct MutableMemoryView
return View;
}
- inline constexpr MutableMemoryView& operator+=(size_t InSize)
+ inline MutableMemoryView& operator+=(size_t InSize)
{
RightChopInline(InSize);
return *this;
@@ -192,10 +194,10 @@ struct MemoryView
{
}
- inline bool Contains(const MemoryView& Other) const { return (m_Data <= Other.m_Data) && (m_DataEnd >= Other.m_DataEnd); }
- inline bool IsEmpty() const { return m_Data == m_DataEnd; }
- const void* GetData() const { return m_Data; }
- const void* GetDataEnd() const { return m_DataEnd; }
+ inline bool Contains(const MemoryView& Other) const { return (m_Data <= Other.m_Data) && (m_DataEnd >= Other.m_DataEnd); }
+ inline bool IsEmpty() const { return m_Data == m_DataEnd; }
+ const void* GetData() const { return m_Data; }
+ const void* GetDataEnd() const { return m_DataEnd; }
size_t GetSize() const { return reinterpret_cast<const uint8_t*>(m_DataEnd) - reinterpret_cast<const uint8_t*>(m_Data); }
inline bool operator==(const MemoryView& Rhs) const { return m_Data == Rhs.m_Data && m_DataEnd == Rhs.m_DataEnd; }
@@ -206,14 +208,14 @@ struct MemoryView
return Size == InView.GetSize() && (memcmp(m_Data, InView.GetData(), Size) == 0);
}
- inline constexpr MemoryView& operator+=(size_t InSize)
+ inline MemoryView& operator+=(size_t InSize)
{
RightChopInline(InSize);
return *this;
}
/** Modifies the view by chopping the given number of bytes from the left. */
- inline constexpr void RightChopInline(uint64_t InSize)
+ inline void RightChopInline(uint64_t InSize)
{
const uint64_t Offset = std::min(GetSize(), InSize);
m_Data = GetDataAtOffsetNoCheck(Offset);
@@ -244,7 +246,7 @@ struct MemoryView
}
/** Returns the left-most part of the view by taking the given number of bytes from the left. */
- constexpr inline MemoryView Left(uint64_t InSize) const
+ inline MemoryView Left(uint64_t InSize) const
{
MemoryView View(*this);
View.LeftInline(InSize);
@@ -252,7 +254,7 @@ struct MemoryView
}
/** Modifies the view to be the given number of bytes from the left. */
- constexpr inline void LeftInline(uint64_t InSize)
+ inline void LeftInline(uint64_t InSize)
{
InSize = zen::Min(GetSize(), InSize);
m_DataEnd = std::min(m_DataEnd, m_Data + InSize);
@@ -296,28 +298,28 @@ MutableMemoryView::CopyFrom(MemoryView InView) const
}
/** Advances the start of the view by an offset, which is clamped to stay within the view. */
-constexpr inline MemoryView
+inline MemoryView
operator+(const MemoryView& View, uint64_t Offset)
{
return MemoryView(View) += Offset;
}
/** Advances the start of the view by an offset, which is clamped to stay within the view. */
-constexpr inline MemoryView
+inline MemoryView
operator+(uint64_t Offset, const MemoryView& View)
{
return MemoryView(View) += Offset;
}
/** Advances the start of the view by an offset, which is clamped to stay within the view. */
-constexpr inline MutableMemoryView
+inline MutableMemoryView
operator+(const MutableMemoryView& View, uint64_t Offset)
{
return MutableMemoryView(View) += Offset;
}
/** Advances the start of the view by an offset, which is clamped to stay within the view. */
-constexpr inline MutableMemoryView
+inline MutableMemoryView
operator+(uint64_t Offset, const MutableMemoryView& View)
{
return MutableMemoryView(View) += Offset;
diff --git a/zencore/include/zencore/sharedbuffer.h b/zencore/include/zencore/sharedbuffer.h
index b230c05b1..640c3fe74 100644
--- a/zencore/include/zencore/sharedbuffer.h
+++ b/zencore/include/zencore/sharedbuffer.h
@@ -12,6 +12,8 @@
namespace zen {
+class SharedBuffer;
+
/**
* Reference to a memory buffer with a single owner
*
diff --git a/zencore/include/zencore/string.h b/zencore/include/zencore/string.h
index de2ca71d9..2b5f20f86 100644
--- a/zencore/include/zencore/string.h
+++ b/zencore/include/zencore/string.h
@@ -560,15 +560,17 @@ NiceRate(uint64_t Num, uint32_t DurationMilliseconds, const char* Unit = "B")
if (DurationMilliseconds)
{
- NiceNumToBuffer(Num * 1000 / DurationMilliseconds, Buffer);
+ // Leave a little of 'Buffer' for the "Unit/s" suffix
+ std::span<char> BufferSpan(Buffer, sizeof(Buffer) - 8);
+ NiceNumToBuffer(Num * 1000 / DurationMilliseconds, BufferSpan);
}
else
{
- strcpy_s(Buffer, "0");
+ strcpy(Buffer, "0");
}
- strcat_s(Buffer, Unit);
- strcat_s(Buffer, "/s");
+ strncat(Buffer, Unit, 4);
+ strcat(Buffer, "/s");
return Buffer;
}
diff --git a/zencore/include/zencore/thread.h b/zencore/include/zencore/thread.h
index 30d0c0897..b18da6031 100644
--- a/zencore/include/zencore/thread.h
+++ b/zencore/include/zencore/thread.h
@@ -4,6 +4,10 @@
#include "zencore.h"
+#if !ZEN_PLATFORM_WINDOWS
+# include <shared_mutex>
+#endif
+
namespace zen {
/**
@@ -60,7 +64,11 @@ public:
};
private:
+#if ZEN_PLATFORM_WINDOWS
void* m_Srw = nullptr;
+#else
+ std::shared_mutex m_Mutex;
+#endif
};
/** Basic abstraction of a simple event synchronization mechanism (aka 'binary semaphore')
diff --git a/zencore/include/zencore/timer.h b/zencore/include/zencore/timer.h
index c9122eb44..eb284eaee 100644
--- a/zencore/include/zencore/timer.h
+++ b/zencore/include/zencore/timer.h
@@ -2,10 +2,16 @@
#pragma once
-#include <intrin.h>
-#include <stdint.h>
#include "zencore.h"
+#if ZEN_COMPILER_MSC
+# include <intrin.h>
+#elif ZEN_ARCH_X64
+# include <x86intrin.h>
+#endif
+
+#include <stdint.h>
+
namespace zen {
// High frequency timers
diff --git a/zencore/include/zencore/zencore.h b/zencore/include/zencore/zencore.h
index 206046f0b..73446b447 100644
--- a/zencore/include/zencore/zencore.h
+++ b/zencore/include/zencore/zencore.h
@@ -10,24 +10,65 @@
// Platform
//
-#define ZEN_PLATFORM_WINDOWS 1
-#define ZEN_PLATFORM_LINUX 0
-#define ZEN_PLATFORM_MACOS 0
+#define ZEN_PLATFORM_WINDOWS 0
+#define ZEN_PLATFORM_LINUX 0
+#define ZEN_PLATFORM_MACOS 0
+
+#ifdef _WIN32
+# undef ZEN_PLATFORM_WINDOWS
+# define ZEN_PLATFORM_WINDOWS 1
+#elif defined(__linux__)
+# undef ZEN_PLATFORM_LINUX
+# define ZEN_PLATFORM_LINUX 1
+#elif defined(__APPLE__)
+# undef ZEN_PLATFORM_MACOS
+# define ZEN_PLATFORM_MACOS 1
+#endif
//////////////////////////////////////////////////////////////////////////
// Compiler
//
-#ifdef _MSC_VER
-# define ZEN_COMPILER_MSC 1
+#define ZEN_COMPILER_CLANG 0
+#define ZEN_COMPILER_MSC 0
+#define ZEN_COMPILER_GCC 0
+
+// Clang can define __GNUC__ and/or _MSC_VER so we check for Clang first
+#ifdef __clang__
+# undef ZEN_COMPILER_CLANG
+# define ZEN_COMPILER_CLANG 1
+#elif defined(_MSC_VER)
+# undef ZEN_COMPILER_MSC
+# define ZEN_COMPILER_MSC 1
+#elif defined(__GNUC__)
+# undef ZEN_COMPILER_GCC
+# define ZEN_COMPILER_GCC 1
+#else
+# error Unknown compiler
#endif
-#ifndef ZEN_COMPILER_MSC
-# define ZEN_COMPILER_MSC 0
+// Check for C++20 support
+#if !ZEN_PLATFORM_WINDOWS
+# if ZEN_COMPILER_CLANG && __clang_major__ < 14
+# error LLVM-14 onwards required for complete C++20 support
+# elif ZEN_COMPILER_GCC && __GNUC__ < 11
+# error GCC-11 onwards required for complete C++20 support
+# endif
#endif
-#ifndef ZEN_COMPILER_CLANG
-# define ZEN_COMPILER_CLANG 0
+
+//////////////////////////////////////////////////////////////////////////
+// Architecture
+//
+
+#if defined(__amd64__) || defined(_M_X64)
+# define ZEN_ARCH_X64 1
+# define ZEN_ARCH_ARM64 0
+#elif defined(__arm64__) || defined(_M_ARM64)
+# define ZEN_ARCH_X64 0
+# define ZEN_ARCH_ARM64 1
+#else
+# error Unknown architecture
#endif
//////////////////////////////////////////////////////////////////////////
@@ -58,7 +99,7 @@ public:
AssertException(const char* Msg);
~AssertException();
- [[nodiscard]] virtual char const* what() const override { return m_Msg.c_str(); }
+ [[nodiscard]] virtual char const* what() const noexcept override { return m_Msg.c_str(); }
private:
std::string m_Msg;
@@ -100,7 +141,12 @@ char (&ZenArrayCountHelper(const T (&)[N]))[N + 1];
//////////////////////////////////////////////////////////////////////////
-#define ZEN_NOINLINE __declspec(noinline)
+#if ZEN_COMPILER_MSC
+# define ZEN_NOINLINE __declspec(noinline)
+#else
+# define ZEN_NOINLINE __attribute__((noinline))
+#endif
+
#define ZEN_UNUSED(...) ((void)__VA_ARGS__)
#define ZEN_NOT_IMPLEMENTED(...) ZEN_ASSERT(false)
#define ZENCORE_API // Placeholder to allow DLL configs in the future