#ifndef ARBUTILS_BORROWEDPTR_HPP #define ARBUTILS_BORROWEDPTR_HPP #include #include "../Assert.hpp" namespace ArbUt { /// A borrowed pointer is used to indicate a pointer that is not owned by an object, but instead borrowed from /// another owning object that is assumed to always be kept alive during the entire lifetime of the borrowing /// object. template class BorrowedPtr { private: T* _raw; public: inline BorrowedPtr() noexcept : _raw(nullptr){}; inline BorrowedPtr(T* ptr) noexcept : _raw(ptr){}; inline BorrowedPtr(const BorrowedPtr& other) noexcept : _raw(other._raw){}; inline BorrowedPtr(const std::unique_ptr& other) noexcept : _raw(other.get()){}; ~BorrowedPtr() noexcept = default; inline BorrowedPtr& operator=(const BorrowedPtr& rhs) noexcept { _raw = rhs._raw; return *this; } inline T* operator->() const { AssertNotNull(_raw); return _raw; } inline T operator*() const { if constexpr (std::is_abstract()) { static_assert(!std::is_abstract(), "You're not allowed to dereference an abstract class."); } else { AssertNotNull(_raw); return *_raw; } } inline T* GetRaw() const noexcept { return _raw; } inline bool operator==(const BorrowedPtr& rhs) const noexcept { return _raw == rhs._raw; } inline bool operator!=(const BorrowedPtr& rhs) const noexcept { return _raw != rhs._raw; } [[nodiscard]] inline constexpr bool IsNull() const noexcept { return _raw == nullptr; } inline BorrowedPtr Const() const noexcept { return BorrowedPtr(_raw); } template inline BorrowedPtr As() const { auto cast = dynamic_cast(_raw); return BorrowedPtr(cast); } template inline bool TryAs(BorrowedPtr& out) const noexcept { auto cast = dynamic_cast(_raw); if (cast == nullptr) return false; out = BorrowedPtr(cast); return true; } template inline BorrowedPtr ForceAs() const noexcept { auto cast = reinterpret_cast(_raw); return BorrowedPtr(cast); } }; } namespace std { template struct hash> { std::size_t operator()(const ArbUt::BorrowedPtr& k) const { return (size_t)k.GetRaw(); } }; } #endif // ARBUTILS_BORROWEDPTR_HPP