#pragma once #include "deimos/core/std.h" #include "deimos/core/gsl.h" #define deimos_StaticAssert(...) static_assert(__VA_ARGS__, #__VA_ARGS__) [[noreturn]] inline void deimos_Trap() { __builtin_trap(); } #define deimos_Panic(MSG) do { deimos_Trap(); } while (0) #define deimos_NO_COPY(TYPE) \ TYPE(const TYPE&) = delete; \ TYPE& operator=(const TYPE&) = delete; #define deimos_NO_MOVE(TYPE) \ TYPE(TYPE&&) = delete; \ TYPE& operator=(TYPE&&) = delete; #define deimos_NO_COPY_MOVE(TYPE) \ deimos_NO_COPY(TYPE); \ deimos_NO_MOVE(TYPE); #define deimos_DEFAULT_COPY(TYPE) \ TYPE(const TYPE&) = default; \ TYPE& operator=(const TYPE&) = default; #define deimos_DEFAULT_MOVE(TYPE) \ TYPE(TYPE&&) = default; \ TYPE& operator=(TYPE&&) = default; #define deimos_DEFAULT_COPY_MOVE(TYPE) \ deimos_DEFAULT_COPY(TYPE); \ deimos_DEFAULT_MOVE(TYPE); namespace deimos { struct uint128_t { uint64_t high; uint64_t low; constexpr bool operator==(const uint128_t& other) const = default; }; struct SourceLocation { gsl::czstring file; int32_t line; constexpr SourceLocation( // NOLINT gsl::czstring file_ = __builtin_FILE(), int32_t line_ = __builtin_LINE()) : file{file_}, line{line_} {} }; template T Min(T a, T b) { return (a < b) ? a : b; } template T Max(T a, T b) { return (a > b) ? a : b; } [[maybe_unused]] static constexpr int64_t Kilobytes = 1024; [[maybe_unused]] static constexpr int64_t Megabytes = 1024 * 1024; [[maybe_unused]] static constexpr int64_t Gigabytes = 1024 * 1024 * 1024; constexpr int64_t AlignUp(int64_t value, int64_t align) { return __builtin_align_up(value, align); } template constexpr T* OffsetBytes(T* p, int64_t offset) { return std::bit_cast(std::bit_cast(p) + std::bit_cast(offset)); } constexpr void MemoryCopy(void* dst, const void* src, int64_t size) { __builtin_memcpy(dst, src, (size_t)size); } inline void MemoryZero(void* dst, int64_t size) { __builtin_memset(dst, 0, (size_t)size); } template constexpr int64_t ArraySize(const T (&)[N]) { return N; } template class Span { T* m_begin = nullptr; int64_t m_size = 0; public: constexpr Span() = default; ~Span() = default; deimos_DEFAULT_COPY_MOVE(Span); constexpr Span(T* begin, int64_t size) : m_begin{begin}, m_size{size} { Expects(size >= 0); } constexpr Span(std::initializer_list list) : m_begin{list.begin()}, m_size{(int64_t)list.size()} {} template requires std::convertible_to constexpr Span(const Span& other) : // NOLINT(*-explicit-conversions) m_begin{other.begin()}, m_size{other.size()} {} constexpr T* data() const { return m_begin; } constexpr T* begin() const { return m_begin; } constexpr T* end() const { return m_begin + m_size; } // NOLINT constexpr int64_t size() const { return m_size; } constexpr bool empty() const { return m_size == 0; } constexpr T& operator[](int64_t i) const { Expects(i >= 0 && i < m_size); return m_begin[i]; // NOLINT } }; template inline Span AsBytes(Span span) { return { reinterpret_cast(span.data()), span.size() * (int64_t)sizeof(T) }; } class StringView { const char* m_begin = nullptr; int64_t m_size = 0; public: constexpr StringView() = default; deimos_DEFAULT_COPY_MOVE(StringView); ~StringView() = default; constexpr StringView(gsl::czstring str) : // NOLINT(*-explicit-conversions) m_begin{str}, m_size{(int64_t)__builtin_strlen(str)} {} constexpr StringView(const char* begin, int64_t size) : m_begin{begin}, m_size{size} {} constexpr const char* data() const { return m_begin; } constexpr int64_t size() const { return m_size; } constexpr bool empty() const { return m_size == 0; } }; inline Span AsBytes(StringView span) { return { reinterpret_cast(span.data()), span.size() }; } deimos_StaticAssert(std::is_trivially_destructible_v); deimos_StaticAssert(std::is_trivially_copyable_v); } // namespace deimos