Files
Juliet/Juliet/include/Core/Common/NonNullPtr.h
2026-02-07 18:06:09 -05:00

112 lines
3.2 KiB
C++

#pragma once
#include <Core/Common/CoreUtils.h>
#include <type_traits>
namespace Juliet
{
template <typename Type, typename OtherType>
concept NonNullPtr_Convertible = std::is_convertible_v<OtherType*, Type*>;
template <typename Type, typename OtherType>
concept NonNullPtr_SameType = std::is_same_v<OtherType*, Type*>;
template <typename Type>
class NonNullPtr
{
public:
NonNullPtr(Type* ptr)
: InternalPtr(ptr)
{
Assert(ptr, "Tried to initialize a NonNullPtr with a null pointer");
}
template <typename OtherType>
requires NonNullPtr_Convertible<OtherType*, Type*>
NonNullPtr(const NonNullPtr<OtherType>& otherPtr)
: InternalPtr(otherPtr.Get())
{
Assert(InternalPtr, "Fatal Error: Assigned a non null ptr using another NonNullPtr but its was null.");
}
// Assignment
NonNullPtr& operator=(Type* ptr)
{
Assert(ptr, "Tried to assign a null pointer to a NonNullPtr!");
InternalPtr = ptr;
return *this;
}
template <typename OtherType>
requires NonNullPtr_Convertible<OtherType*, Type*>
NonNullPtr& operator=(const NonNullPtr<OtherType>& otherPtr)
{
InternalPtr = otherPtr.Get();
return *this;
}
// Accessors
operator Type*() const
{
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
return InternalPtr;
}
Type* Get() const
{
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
return InternalPtr;
}
Type& operator*() const
{
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
return *InternalPtr;
}
Type* operator->() const
{
Assert(InternalPtr, "NonNullPtr: Internal Pointer is Null");
return InternalPtr;
}
// Comparisons
bool operator==(const NonNullPtr& otherPtr) const { return InternalPtr == otherPtr.InternalPtr; }
template <typename OtherType>
requires NonNullPtr_SameType<Type, OtherType>
bool operator==(OtherType* otherRawPtr) const
{
return InternalPtr == otherRawPtr;
}
template <typename OtherType>
requires NonNullPtr_SameType<Type, OtherType>
friend bool operator==(OtherType* otherRawPtr, const NonNullPtr& nonNullPtr)
{
return otherRawPtr == nonNullPtr.InternalPtr;
}
// Forbid assigning a nullptr at compile time
NonNullPtr(std::nullptr_t)
: InternalPtr(nullptr)
{
static_assert(sizeof(Type) == 0, "Trying to initialize a NonNullPtr with a nullptr value");
}
NonNullPtr& operator=(std::nullptr_t)
{
static_assert(sizeof(Type) == 0, "Trying to assign a NonNullPtr with a nullptr value");
return *this;
}
explicit operator bool() const { return true; }
private:
Type* InternalPtr;
};
template <typename T>
NonNullPtr(T*) -> NonNullPtr<T>;
} // namespace Juliet