mirror of
https://github.com/LNH-team/pico-launcher.git
synced 2026-06-02 09:06:54 +02:00
Add new shared pointer and make use of it
This commit is contained in:
35
arm9/source/core/AtomicSharedPtr.cpp
Normal file
35
arm9/source/core/AtomicSharedPtr.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "AtomicSharedPtr.h"
|
||||
|
||||
void AtomicSharedPtrBase::Reset(void* newObject, RefCount* newRefCount, bool increaseNewRefCount)
|
||||
{
|
||||
u32 irq = rtos_disableIrqs(); // 1
|
||||
auto refCount = _refCount;
|
||||
_object = newObject;
|
||||
_refCount = newRefCount;
|
||||
if (increaseNewRefCount && _refCount)
|
||||
{
|
||||
_refCount->refCount++;
|
||||
}
|
||||
if (refCount && --refCount->refCount == 0) [[gnu::unlikely]]
|
||||
{
|
||||
refCount->weakRefCount++; // ensure the ref count is not destructed elsewhere
|
||||
rtos_restoreIrqs(irq); // 1
|
||||
refCount->DestructObject();
|
||||
irq = rtos_disableIrqs(); // 2
|
||||
if (--refCount->weakRefCount == 0) [[gnu::unlikely]]
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 2
|
||||
delete refCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 2
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 1
|
||||
}
|
||||
}
|
||||
134
arm9/source/core/AtomicSharedPtr.h
Normal file
134
arm9/source/core/AtomicSharedPtr.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "SharedPtr.h"
|
||||
|
||||
class AtomicSharedPtrBase
|
||||
{
|
||||
public:
|
||||
void Reset()
|
||||
{
|
||||
Reset(nullptr, nullptr, false);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* volatile _object;
|
||||
RefCount* volatile _refCount;
|
||||
|
||||
AtomicSharedPtrBase()
|
||||
: _object(nullptr), _refCount(nullptr) { }
|
||||
|
||||
AtomicSharedPtrBase(void* object, RefCount* refCount)
|
||||
: _object(object), _refCount(refCount) { }
|
||||
|
||||
~AtomicSharedPtrBase()
|
||||
{
|
||||
Reset(nullptr, nullptr, false);
|
||||
}
|
||||
|
||||
void Reset(void* newObject, RefCount* newRefCount, bool increaseNewRefCount);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AtomicSharedPtr : public AtomicSharedPtrBase
|
||||
{
|
||||
public:
|
||||
AtomicSharedPtr() { }
|
||||
|
||||
AtomicSharedPtr(std::nullptr_t) { }
|
||||
|
||||
AtomicSharedPtr(const SharedPtr<T>& sharedPtr)
|
||||
: AtomicSharedPtrBase(sharedPtr._object, sharedPtr._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
AtomicSharedPtr(const SharedPtr<Y>& sharedPtr)
|
||||
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
explicit AtomicSharedPtr(const SharedPtr<Y>& sharedPtr)
|
||||
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
AtomicSharedPtr(SharedPtr<T>&& sharedPtr)
|
||||
: AtomicSharedPtrBase(sharedPtr._object, sharedPtr._refCount)
|
||||
{
|
||||
sharedPtr._object = nullptr;
|
||||
sharedPtr._refCount = nullptr;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
AtomicSharedPtr(SharedPtr<Y>&& sharedPtr)
|
||||
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
|
||||
{
|
||||
sharedPtr._object = nullptr;
|
||||
sharedPtr._refCount = nullptr;
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
explicit AtomicSharedPtr(SharedPtr<Y>&& sharedPtr)
|
||||
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
|
||||
{
|
||||
sharedPtr._object = nullptr;
|
||||
sharedPtr._refCount = nullptr;
|
||||
}
|
||||
|
||||
AtomicSharedPtr& operator=(const SharedPtr<T>& sharedPtr)
|
||||
{
|
||||
Reset(sharedPtr._object, sharedPtr._refCount, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
AtomicSharedPtr<T>& operator=(const SharedPtr<Y>& sharedPtr)
|
||||
{
|
||||
Reset(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AtomicSharedPtr& operator=(SharedPtr<T>&& sharedPtr)
|
||||
{
|
||||
Reset(sharedPtr._object, sharedPtr._refCount, false);
|
||||
sharedPtr._object = nullptr;
|
||||
sharedPtr._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
AtomicSharedPtr<T>& operator=(SharedPtr<Y>&& sharedPtr)
|
||||
{
|
||||
Reset(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount, false);
|
||||
sharedPtr._object = nullptr;
|
||||
sharedPtr._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SharedPtr<T> Lock() const
|
||||
{
|
||||
u32 irq = rtos_disableIrqs();
|
||||
auto object = static_cast<T*>(_object);
|
||||
auto refCount = _refCount;
|
||||
if (refCount)
|
||||
{
|
||||
refCount->refCount++;
|
||||
}
|
||||
rtos_restoreIrqs(irq);
|
||||
return SharedPtr<T>(object, refCount);
|
||||
}
|
||||
};
|
||||
42
arm9/source/core/EnableSharedFromThis.h
Normal file
42
arm9/source/core/EnableSharedFromThis.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "SharedPtr.h"
|
||||
#include "WeakPtr.h"
|
||||
|
||||
class EnableSharedFromThisBase
|
||||
{
|
||||
template <class Y>
|
||||
friend class SharedPtr;
|
||||
|
||||
template <class Y>
|
||||
friend class EnableSharedFromThis;
|
||||
|
||||
private:
|
||||
EnableSharedFromThisBase() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class EnableSharedFromThis : public EnableSharedFromThisBase
|
||||
{
|
||||
template <class Y>
|
||||
friend class SharedPtr;
|
||||
|
||||
protected:
|
||||
SharedPtr<T> SharedFromThis()
|
||||
{
|
||||
return __sharedFromThisWeakPtr.Lock();
|
||||
}
|
||||
|
||||
WeakPtr<T> WeakFromThis()
|
||||
{
|
||||
return __sharedFromThisWeakPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
WeakPtr<T> __sharedFromThisWeakPtr;
|
||||
|
||||
template <class Y>
|
||||
void __SetSharedFromThisWeakPtr(const SharedPtr<Y>& sharedPtr)
|
||||
{
|
||||
__sharedFromThisWeakPtr = WeakPtr<Y>(sharedPtr.GetPointer(), sharedPtr._refCount);
|
||||
}
|
||||
};
|
||||
58
arm9/source/core/RefCount.h
Normal file
58
arm9/source/core/RefCount.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
|
||||
extern "C" void shared_ptr_increase_ref_count(vu32& refCount);
|
||||
|
||||
class RefCount
|
||||
{
|
||||
public:
|
||||
vu32 refCount;
|
||||
vu32 weakRefCount;
|
||||
|
||||
virtual ~RefCount() = default;
|
||||
|
||||
virtual void DestructObject() = 0;
|
||||
|
||||
protected:
|
||||
explicit RefCount()
|
||||
: refCount(1), weakRefCount(0) { }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class StandaloneRefCount : public RefCount
|
||||
{
|
||||
public:
|
||||
explicit StandaloneRefCount(T* object)
|
||||
: _object(object) { }
|
||||
|
||||
void DestructObject() final
|
||||
{
|
||||
delete _object;
|
||||
}
|
||||
|
||||
private:
|
||||
T* _object;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class alignas(T) MakeSharedRefCount : public RefCount
|
||||
{
|
||||
public:
|
||||
explicit MakeSharedRefCount(auto&&... args)
|
||||
{
|
||||
new (_object.data()) T(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
|
||||
T* GetObject()
|
||||
{
|
||||
return reinterpret_cast<T*>(_object.data());
|
||||
}
|
||||
|
||||
void DestructObject() final
|
||||
{
|
||||
reinterpret_cast<T*>(_object.data())->~T();
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<u8, sizeof(T)> _object alignas(T);
|
||||
};
|
||||
31
arm9/source/core/SharedPtr.cpp
Normal file
31
arm9/source/core/SharedPtr.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "SharedPtr.h"
|
||||
|
||||
void SharedPtrBase::ResetIntern()
|
||||
{
|
||||
auto refCount = _refCount;
|
||||
_object = nullptr;
|
||||
_refCount = nullptr;
|
||||
u32 irq = rtos_disableIrqs(); // 1
|
||||
if (--refCount->refCount == 0) [[gnu::unlikely]]
|
||||
{
|
||||
refCount->weakRefCount++; // ensure the ref count is not destructed elsewhere
|
||||
rtos_restoreIrqs(irq); // 1
|
||||
refCount->DestructObject();
|
||||
irq = rtos_disableIrqs(); // 2
|
||||
if (--refCount->weakRefCount == 0) [[gnu::unlikely]]
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 2
|
||||
delete refCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 2
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq); // 1
|
||||
}
|
||||
}
|
||||
@@ -1,163 +1,209 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include "RefCount.h"
|
||||
|
||||
static inline u32 arm_getCpsr()
|
||||
{
|
||||
u32 cpsr;
|
||||
asm volatile("mrs %0, cpsr" : "=r" (cpsr));
|
||||
return cpsr;
|
||||
}
|
||||
|
||||
static inline void arm_setCpsrControl(u32 cpsrControl)
|
||||
{
|
||||
asm volatile("msr cpsr_c, %0" :: "r" (cpsrControl) : "cc");
|
||||
}
|
||||
|
||||
static inline u32 arm_disableIrqs(void)
|
||||
{
|
||||
u32 oldCpsr = arm_getCpsr();
|
||||
arm_setCpsrControl(oldCpsr | 0x80);
|
||||
return oldCpsr;
|
||||
}
|
||||
|
||||
static inline void arm_restoreIrqs(u32 oldCpsr)
|
||||
{
|
||||
arm_setCpsrControl(oldCpsr);
|
||||
}
|
||||
class EnableSharedFromThisBase;
|
||||
|
||||
template <class T>
|
||||
class SharedPtr
|
||||
class EnableSharedFromThis;
|
||||
|
||||
class SharedPtrBase
|
||||
{
|
||||
T* _pointer;
|
||||
vu32* _refCount;
|
||||
|
||||
public:
|
||||
SharedPtr()
|
||||
: _pointer(nullptr), _refCount(nullptr) { (void)sizeof(T); }
|
||||
|
||||
explicit SharedPtr(T* pointer)
|
||||
: _pointer(pointer), _refCount(pointer ? new u32(1) : nullptr) { (void)sizeof(T); }
|
||||
|
||||
SharedPtr(const SharedPtr& other)
|
||||
void Reset()
|
||||
{
|
||||
u32 irq = arm_disableIrqs();
|
||||
_pointer = other._pointer;
|
||||
_refCount = other._refCount;
|
||||
if (_pointer)
|
||||
if (_refCount != nullptr)
|
||||
{
|
||||
(*_refCount)++;
|
||||
ResetIntern();
|
||||
}
|
||||
arm_restoreIrqs(irq);
|
||||
}
|
||||
|
||||
SharedPtr(SharedPtr&& other)
|
||||
: _pointer(other._pointer), _refCount(other._refCount)
|
||||
{
|
||||
other._pointer = nullptr;
|
||||
other._refCount = nullptr;
|
||||
}
|
||||
protected:
|
||||
void* _object;
|
||||
RefCount* _refCount;
|
||||
|
||||
~SharedPtr()
|
||||
SharedPtrBase()
|
||||
: _object(nullptr), _refCount(nullptr) { }
|
||||
|
||||
SharedPtrBase(void* object, RefCount* refCount)
|
||||
: _object(object), _refCount(refCount) { }
|
||||
|
||||
SharedPtrBase(const void* object, RefCount* refCount)
|
||||
: _object((void*)object), _refCount(refCount) { }
|
||||
|
||||
~SharedPtrBase()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void ResetIntern();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SharedPtr : public SharedPtrBase
|
||||
{
|
||||
template <class Y> friend class WeakPtr;
|
||||
template <class Y> friend class SharedPtr;
|
||||
template <class Y> friend class AtomicSharedPtr;
|
||||
template <class Y> friend class EnableSharedFromThis;
|
||||
|
||||
public:
|
||||
SharedPtr() { }
|
||||
|
||||
SharedPtr(std::nullptr_t) { }
|
||||
|
||||
explicit SharedPtr(T* object)
|
||||
: SharedPtrBase(object, object == nullptr ? nullptr : new StandaloneRefCount<T>(object))
|
||||
{
|
||||
if (_object != nullptr)
|
||||
{
|
||||
if constexpr (std::is_convertible<T*, EnableSharedFromThisBase*>::value)
|
||||
{
|
||||
_refCount->weakRefCount = 1;
|
||||
GetPointer()->__SetSharedFromThisWeakPtr(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
explicit SharedPtr(Y* object)
|
||||
: SharedPtrBase(static_cast<T*>(object), object == nullptr ? nullptr : new StandaloneRefCount<Y>(object))
|
||||
{
|
||||
if (object != nullptr)
|
||||
{
|
||||
if constexpr (std::is_convertible<Y*, EnableSharedFromThisBase*>::value)
|
||||
{
|
||||
_refCount->weakRefCount = 1;
|
||||
GetPointer()->__SetSharedFromThisWeakPtr(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr(const SharedPtr& other)
|
||||
: SharedPtrBase(other._object, other._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
SharedPtr(const SharedPtr<Y>& other)
|
||||
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
explicit SharedPtr(const SharedPtr<Y>& other)
|
||||
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr(SharedPtr&& other)
|
||||
: SharedPtrBase(other._object, other._refCount)
|
||||
{
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
SharedPtr(SharedPtr<Y>&& other)
|
||||
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
|
||||
{
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
explicit SharedPtr(SharedPtr<Y>&& other)
|
||||
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
|
||||
{
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
}
|
||||
|
||||
static SharedPtr<T> MakeShared(auto&&... args)
|
||||
{
|
||||
auto refCount = new MakeSharedRefCount<T>(std::forward<decltype(args)>(args)...);
|
||||
return SharedPtr<T>(refCount->GetObject(), refCount, true);
|
||||
}
|
||||
|
||||
SharedPtr& operator=(const SharedPtr& other)
|
||||
{
|
||||
u32 irq = arm_disableIrqs();
|
||||
T* pointer = _pointer;
|
||||
if (pointer)
|
||||
Reset();
|
||||
_object = other._object;
|
||||
_refCount = other._refCount;
|
||||
if (_refCount)
|
||||
{
|
||||
vu32* refCount = _refCount;
|
||||
u32 newValue = *refCount - 1;
|
||||
*refCount = newValue;
|
||||
_pointer = other._pointer;
|
||||
_refCount = other._refCount;
|
||||
if (_pointer)
|
||||
{
|
||||
(*_refCount)++;
|
||||
}
|
||||
arm_restoreIrqs(irq);
|
||||
if (newValue == 0)
|
||||
{
|
||||
delete pointer;
|
||||
delete refCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pointer = other._pointer;
|
||||
_refCount = other._refCount;
|
||||
if (_pointer)
|
||||
{
|
||||
(*_refCount)++;
|
||||
}
|
||||
arm_restoreIrqs(irq);
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
SharedPtr<T>& operator=(const SharedPtr<Y>& other)
|
||||
{
|
||||
Reset();
|
||||
_object = static_cast<T*>(other.GetPointer());
|
||||
_refCount = other._refCount;
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->refCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
SharedPtr& operator=(SharedPtr&& other)
|
||||
{
|
||||
u32 irq = arm_disableIrqs();
|
||||
T* pointer = _pointer;
|
||||
if (pointer)
|
||||
{
|
||||
vu32* refCount = _refCount;
|
||||
u32 newValue = *refCount - 1;
|
||||
*refCount = newValue;
|
||||
_pointer = other._pointer;
|
||||
_refCount = other._refCount;
|
||||
other._pointer = nullptr;
|
||||
other._refCount = nullptr;
|
||||
arm_restoreIrqs(irq);
|
||||
if (newValue == 0)
|
||||
{
|
||||
delete pointer;
|
||||
delete refCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pointer = other._pointer;
|
||||
_refCount = other._refCount;
|
||||
other._pointer = nullptr;
|
||||
other._refCount = nullptr;
|
||||
arm_restoreIrqs(irq);
|
||||
}
|
||||
Reset();
|
||||
_object = other._object;
|
||||
_refCount = other._refCount;
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
void Reset()
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
SharedPtr<T>& operator=(SharedPtr<Y>&& other)
|
||||
{
|
||||
u32 irq = arm_disableIrqs();
|
||||
T* pointer = _pointer;
|
||||
if (pointer)
|
||||
{
|
||||
vu32* refCount = _refCount;
|
||||
u32 newValue = *refCount - 1;
|
||||
*refCount = newValue;
|
||||
_pointer = nullptr;
|
||||
_refCount = nullptr;
|
||||
arm_restoreIrqs(irq);
|
||||
if (newValue == 0)
|
||||
{
|
||||
delete pointer;
|
||||
delete refCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arm_restoreIrqs(irq);
|
||||
}
|
||||
Reset();
|
||||
_object = static_cast<T*>(other.GetPointer());
|
||||
_refCount = other._refCount;
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr T& operator*() const { return *_pointer; }
|
||||
constexpr T* operator->() const { return _pointer; }
|
||||
T& operator*() const { return *static_cast<T*>(_object); }
|
||||
T* operator->() const { return static_cast<T*>(_object); }
|
||||
T* GetPointer() const { return static_cast<T*>(_object); }
|
||||
|
||||
constexpr T* GetPointer() const { return _pointer; }
|
||||
constexpr u32 GetRefCount() const { return _refCount ? *_refCount : 0; }
|
||||
constexpr bool IsValid() const { return _pointer; }
|
||||
bool IsValid() const { return _object != nullptr; }
|
||||
operator bool() const { return _object != nullptr; }
|
||||
|
||||
private:
|
||||
SharedPtr(T* object, RefCount* refCount)
|
||||
: SharedPtrBase(object, refCount) { }
|
||||
|
||||
SharedPtr(T* object, RefCount* refCount, bool doSharedFromThis)
|
||||
: SharedPtrBase(object, refCount)
|
||||
{
|
||||
if (doSharedFromThis)
|
||||
{
|
||||
if constexpr (std::is_convertible<T*, EnableSharedFromThisBase*>::value)
|
||||
{
|
||||
_refCount->weakRefCount = 1;
|
||||
GetPointer()->__SetSharedFromThisWeakPtr(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
15
arm9/source/core/SharedPtrAsm.s
Normal file
15
arm9/source/core/SharedPtrAsm.s
Normal file
@@ -0,0 +1,15 @@
|
||||
.section .itcm
|
||||
.arm
|
||||
|
||||
// r0 = &refCount
|
||||
.global shared_ptr_increase_ref_count
|
||||
.type shared_ptr_increase_ref_count, %function
|
||||
shared_ptr_increase_ref_count:
|
||||
mrs r2, cpsr
|
||||
orr r1, r2, #0x80
|
||||
msr cpsr_c, r1
|
||||
ldr r12, [r0]
|
||||
add r12, r12, #1
|
||||
str r12, [r0]
|
||||
msr cpsr_c, r2
|
||||
bx lr
|
||||
35
arm9/source/core/WeakPtr.cpp
Normal file
35
arm9/source/core/WeakPtr.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "common.h"
|
||||
#include <libtwl/rtos/rtosIrq.h>
|
||||
#include "WeakPtr.h"
|
||||
|
||||
void WeakPtrBase::ResetIntern()
|
||||
{
|
||||
u32 irq = rtos_disableIrqs();
|
||||
auto refCount = _refCount;
|
||||
if (--refCount->weakRefCount == 0)
|
||||
{
|
||||
_refCount = nullptr;
|
||||
rtos_restoreIrqs(irq);
|
||||
delete refCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq);
|
||||
}
|
||||
}
|
||||
|
||||
bool WeakPtrBase::LockIntern() const
|
||||
{
|
||||
u32 irq = rtos_disableIrqs();
|
||||
if (_refCount->refCount != 0)
|
||||
{
|
||||
_refCount->refCount++;
|
||||
rtos_restoreIrqs(irq);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtos_restoreIrqs(irq);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
158
arm9/source/core/WeakPtr.h
Normal file
158
arm9/source/core/WeakPtr.h
Normal file
@@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include "RefCount.h"
|
||||
#include "SharedPtr.h"
|
||||
|
||||
class WeakPtrBase
|
||||
{
|
||||
public:
|
||||
~WeakPtrBase()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RefCount* _refCount;
|
||||
|
||||
WeakPtrBase()
|
||||
: _refCount(nullptr) { }
|
||||
|
||||
explicit WeakPtrBase(RefCount* refCount)
|
||||
: _refCount(refCount) { }
|
||||
|
||||
void ResetIntern();
|
||||
bool LockIntern() const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class WeakPtr : public WeakPtrBase
|
||||
{
|
||||
template <class Y> friend class WeakPtr;
|
||||
template <class Y> friend class EnableSharedFromThis;
|
||||
|
||||
public:
|
||||
WeakPtr() { }
|
||||
|
||||
WeakPtr(std::nullptr_t) { }
|
||||
|
||||
WeakPtr(const WeakPtr& other)
|
||||
: WeakPtrBase(other._refCount), _object(other._object)
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
}
|
||||
|
||||
WeakPtr(WeakPtr&& other)
|
||||
: WeakPtrBase(other._refCount), _object(other._object)
|
||||
{
|
||||
other._refCount = nullptr;
|
||||
other._object = nullptr;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
WeakPtr(const SharedPtr<Y>& sharedPtr)
|
||||
: WeakPtrBase(sharedPtr._refCount), _object(static_cast<T*>(sharedPtr.GetPointer()))
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
explicit WeakPtr(const SharedPtr<Y>& sharedPtr)
|
||||
: WeakPtrBase(sharedPtr._refCount), _object(static_cast<T*>(sharedPtr.GetPointer()))
|
||||
{
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
}
|
||||
|
||||
WeakPtr& operator=(const WeakPtr& other)
|
||||
{
|
||||
Reset();
|
||||
_object = other._object;
|
||||
_refCount = other._refCount;
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
WeakPtr<T>& operator=(const WeakPtr<Y>& other)
|
||||
{
|
||||
Reset();
|
||||
_object = static_cast<T*>(static_cast<Y*>(other._object));
|
||||
_refCount = other._refCount;
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
WeakPtr<T>& operator=(const SharedPtr<Y>& sharedPtr)
|
||||
{
|
||||
Reset();
|
||||
_object = static_cast<T*>(sharedPtr.GetPointer());
|
||||
_refCount = sharedPtr._refCount;
|
||||
if (_refCount)
|
||||
{
|
||||
shared_ptr_increase_ref_count(_refCount->weakRefCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
WeakPtr& operator=(WeakPtr&& other)
|
||||
{
|
||||
Reset();
|
||||
_object = other._object;
|
||||
_refCount = other._refCount;
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Y> requires std::assignable_from<T*&, Y*>
|
||||
WeakPtr<T>& operator=(WeakPtr<Y>&& other)
|
||||
{
|
||||
Reset();
|
||||
_object = static_cast<T*>(static_cast<Y*>(other._object));
|
||||
_refCount = other._refCount;
|
||||
other._object = nullptr;
|
||||
other._refCount = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SharedPtr<T> Lock() const
|
||||
{
|
||||
if (_refCount && LockIntern())
|
||||
{
|
||||
return SharedPtr<T>(_object, _refCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SharedPtr<T>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T* _object;
|
||||
|
||||
WeakPtr(T* object, RefCount* refCount)
|
||||
: WeakPtrBase(refCount), _object(object) { }
|
||||
};
|
||||
Reference in New Issue
Block a user