Luna/libluna/include/luna/SharedPtr.h

154 lines
3.0 KiB
C
Raw Normal View History

2022-12-23 09:23:13 +00:00
#pragma once
#include <luna/Alloc.h>
#include <luna/Atomic.h>
#include <luna/Hash.h>
2022-12-31 11:02:15 +00:00
#include <luna/OwnedPtr.h>
2022-12-23 09:23:13 +00:00
#include <luna/Result.h>
#include <luna/ScopeGuard.h>
namespace __detail
{
struct RefCount
{
void ref()
{
m_ref_count++;
}
bool unref()
{
m_ref_count--;
return m_ref_count == 0;
}
private:
Atomic<int> m_ref_count { 1 };
};
}
template <typename T> class SharedPtr
{
using RefCount = __detail::RefCount;
public:
2023-01-13 17:54:39 +00:00
SharedPtr()
{
m_ptr = nullptr;
m_ref_count = nullptr;
}
2022-12-23 09:23:13 +00:00
SharedPtr(T* ptr, RefCount* ref_count) : m_ptr(ptr), m_ref_count(ref_count)
{
}
SharedPtr(const SharedPtr<T>& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count)
{
if (m_ref_count) m_ref_count->ref();
2022-12-23 09:23:13 +00:00
}
SharedPtr(SharedPtr<T>&& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count)
{
other.m_ptr = nullptr;
other.m_ref_count = nullptr;
}
template <typename Tp> operator SharedPtr<Tp>()
{
if (m_ref_count) m_ref_count->ref();
return { (Tp*)m_ptr, m_ref_count };
}
2022-12-23 09:23:13 +00:00
~SharedPtr()
{
if (m_ref_count && m_ref_count->unref())
{
delete m_ref_count;
delete m_ptr;
}
}
2022-12-23 09:31:48 +00:00
SharedPtr<T>& operator=(const SharedPtr<T>& other)
{
if (&other == this) return *this;
if (m_ref_count && m_ref_count->unref())
{
delete m_ref_count;
delete m_ptr;
}
m_ptr = other.m_ptr;
m_ref_count = other.m_ref_count;
if (m_ref_count) m_ref_count->ref();
2022-12-23 09:31:48 +00:00
return *this;
}
bool operator==(const SharedPtr<T>& other)
{
return m_ptr == other.m_ptr && m_ref_count == other.m_ref_count;
}
2022-12-23 09:23:13 +00:00
T* ptr() const
{
return m_ptr;
}
T* operator->() const
{
return m_ptr;
}
T& operator*() const
{
return *m_ptr;
}
operator bool() const
{
return m_ptr != nullptr;
}
2022-12-23 09:23:13 +00:00
private:
T* m_ptr;
RefCount* m_ref_count;
};
// NOTE: ptr is deleted if any of the adopt_shared* functions fail to construct a SharedPtr.
template <typename T> Result<SharedPtr<T>> adopt_shared(T* ptr)
2022-12-23 09:23:13 +00:00
{
using RefCount = __detail::RefCount;
auto guard = make_scope_guard([ptr] { delete ptr; });
2023-01-10 18:31:41 +00:00
RefCount* const ref_count = TRY(make<RefCount>());
2022-12-23 09:23:13 +00:00
guard.deactivate();
return SharedPtr<T> { ptr, ref_count };
}
template <typename T, class... Args> Result<SharedPtr<T>> make_shared(Args... args)
{
T* raw_ptr = TRY(make<T>(args...));
return adopt_shared(raw_ptr);
}
2022-12-23 09:23:13 +00:00
template <typename T> Result<SharedPtr<T>> adopt_shared_if_nonnull(T* ptr)
{
if (ptr) return adopt_shared(ptr);
else
return err(ENOMEM);
2022-12-31 11:02:15 +00:00
}
template <typename T> Result<SharedPtr<T>> adopt_shared_from_owned(OwnedPtr<T>&& other)
{
T* ptr = other.m_ptr;
other.m_ptr = nullptr;
2023-01-10 18:31:41 +00:00
const SharedPtr<T> shared_ptr = TRY(adopt_shared(ptr));
2022-12-31 11:02:15 +00:00
return shared_ptr;
2023-01-02 12:07:29 +00:00
}