#pragma once #include #include #include #include #include #include namespace host { struct PanicError : public std::runtime_error { public: // copy and move constructors explicit PanicError(std::string msg) : runtime_error(msg), m_message(std::move(msg)) {} auto detail() const -> std::string_view { const auto sv = std::string_view{m_message}; const auto pos = sv.find(": "); return pos == std::string_view::npos ? sv : sv.substr(pos + 2); } private: std::string m_message; }; template [[noreturn]] inline auto panic(std::source_location location, Args&&... args) -> void { std::ostringstream os; os << "Runtime check failed at " << location.file_name() << ":" << location.line(); if constexpr (sizeof...(args) > 0) { os << ": "; (os << ... << std::forward(args)); } else { os << " in " << location.function_name(); } throw PanicError(std::move(os).str()); } template struct RuntimeCheck { using Loc_t = std::source_location; template explicit RuntimeCheck(Cond&& condition, Args&&... args, Loc_t location = Loc_t::current()) { if (!condition) { [[unlikely]]; ::host::panic(location, std::forward(args)...); } } }; template explicit RuntimeCheck(Cond&&, Args&&...) -> RuntimeCheck; template inline constexpr auto div_ceil(T a, U b) { return (a + b - 1) / b; } template inline constexpr auto div_ceil(T a, U b) { return (a + b - 1) / b; } inline auto dtype_bytes(DLDataType dtype) -> std::size_t { return static_cast(dtype.bits / 8); } namespace pointer { // we only allow void * pointer arithmetic for safety template inline auto offset(T* ptr, U... offset) -> void* { static_assert(std::is_same_v, "Pointer arithmetic is only allowed for void* pointers"); return static_cast(ptr) + (... + offset); } template inline auto offset(const T* ptr, U... offset) -> const void* { static_assert(std::is_same_v, "Pointer arithmetic is only allowed for void* pointers"); return static_cast(ptr) + (... + offset); } } // namespace pointer } // namespace host