#pragma once #include #include #include namespace shader::ir { template struct PointerWrapper { using underlying_type = ImplT; ImplT *impl = nullptr; PointerWrapper() = default; PointerWrapper(ImplT *impl) : impl(impl) {} template requires std::is_base_of_v PointerWrapper(PointerWrapper node) : impl(node.impl) {} explicit operator bool() const { return impl != nullptr; } bool operator==(std::nullptr_t) const { return impl == nullptr; } bool operator==(ImplT *other) const { return impl == other; } template Self &operator=(this Self &self, ImplT *other) { self.impl = other; return self; } template requires std::is_base_of_v Self &operator=(this Self &self, PointerWrapper other) { self.impl = other.get(); return self; } // ImplT *operator->() const { return impl; } ImplT *get() const { return impl; } auto operator<=>(const PointerWrapper &) const = default; bool operator==(const PointerWrapper &) const = default; template T cast() const requires requires { static_cast(impl); } { return T(dynamic_cast(impl)); } template T staticCast() const requires requires { static_cast(impl); } { assert(impl == nullptr || cast() != nullptr); return T(static_cast(impl)); } template bool isa() const { if (impl == nullptr) { return false; } if constexpr (std::is_same_v, std::remove_cvref_t>) { return true; } else if constexpr (!requires { cast() != nullptr; }) { return false; } else { return cast() != nullptr; } } template requires(sizeof...(T) > 1) bool isa() const { return (isa() || ...); } }; } // namespace shader::ir namespace std { template requires std::is_base_of_v< shader::ir::PointerWrapper, T> struct hash { constexpr std::size_t operator()(const T &pointer) const noexcept { return hash{}(pointer.impl); } }; } // namespace std