From bd4b05e534e629bd6f0980f75a93f8e85ee184e2 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 23 Dec 2022 10:23:13 +0100 Subject: [PATCH] Add OwnedPtr and SharedPtr --- luna/include/luna/OwnedPtr.h | 61 ++++++++++++++++++++ luna/include/luna/SharedPtr.h | 104 ++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 luna/include/luna/OwnedPtr.h create mode 100644 luna/include/luna/SharedPtr.h diff --git a/luna/include/luna/OwnedPtr.h b/luna/include/luna/OwnedPtr.h new file mode 100644 index 00000000..cc147f24 --- /dev/null +++ b/luna/include/luna/OwnedPtr.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include + +template class OwnedPtr +{ + public: + OwnedPtr(T* ptr) + { + m_ptr = ptr; + } + + ~OwnedPtr() + { + if (m_ptr) delete m_ptr; + } + + OwnedPtr(const OwnedPtr& other) = delete; + + OwnedPtr(OwnedPtr&& other) + { + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + } + + T* ptr() const + { + return m_ptr; + } + + T* operator->() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + private: + T* m_ptr; +}; + +template Result> make_owned(Args... args) +{ + T* raw = TRY(make(args...)); + return OwnedPtr { raw }; +} + +template OwnedPtr adopt_owned(T* ptr) +{ + return OwnedPtr { ptr }; +} + +template Result> adopt_owned_if_nonnull(T* ptr) +{ + if (ptr) return OwnedPtr { ptr }; + else + return err(ENOMEM); +} \ No newline at end of file diff --git a/luna/include/luna/SharedPtr.h b/luna/include/luna/SharedPtr.h new file mode 100644 index 00000000..08c09931 --- /dev/null +++ b/luna/include/luna/SharedPtr.h @@ -0,0 +1,104 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace __detail +{ + struct RefCount + { + void ref() + { + m_ref_count++; + } + + bool unref() + { + m_ref_count--; + return m_ref_count == 0; + } + + private: + Atomic m_ref_count { 1 }; + }; +} + +template class SharedPtr +{ + using RefCount = __detail::RefCount; + + public: + SharedPtr(T* ptr, RefCount* ref_count) : m_ptr(ptr), m_ref_count(ref_count) + { + } + + SharedPtr(const SharedPtr& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) + { + m_ref_count->ref(); + } + + SharedPtr(SharedPtr&& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) + { + other.m_ptr = nullptr; + other.m_ref_count = nullptr; + } + + ~SharedPtr() + { + if (m_ref_count && m_ref_count->unref()) + { + delete m_ref_count; + delete m_ptr; + } + } + + T* ptr() const + { + return m_ptr; + } + + T* operator->() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + private: + T* m_ptr; + RefCount* m_ref_count; +}; + +template Result> make_shared(Args... args) +{ + using RefCount = __detail::RefCount; + + RefCount* ref_count = TRY(make()); + auto guard = make_scope_guard([&] { delete ref_count; }); + + T* ptr = TRY(make(args...)); + guard.deactivate(); + + return SharedPtr { ptr, ref_count }; +} + +template Result> adopt_shared(T* ptr) +{ + using RefCount = __detail::RefCount; + + RefCount* ref_count = TRY(make()); + + return SharedPtr { ptr, ref_count }; +} + +template Result> adopt_shared_if_nonnull(T* ptr) +{ + if (ptr) return adopt_shared(ptr); + else + return err(ENOMEM); +} \ No newline at end of file