From b05e710bfee12e3c81a44582a228572707391b76 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 31 Mar 2021 17:02:23 +0200 Subject: [PATCH] Better pointers --- include/gp/memory.hpp | 2 + include/gp/pointers.hpp | 225 ++++++++++++++++------------------------ 2 files changed, 89 insertions(+), 138 deletions(-) diff --git a/include/gp/memory.hpp b/include/gp/memory.hpp index db28980..1a9b13b 100644 --- a/include/gp/memory.hpp +++ b/include/gp/memory.hpp @@ -2,6 +2,8 @@ #include "gp_config.hpp" +#include "gp/algorithm/move.hpp" +#include "gp/allocator/allocator.hpp" #include "gp/exception.hpp" #include diff --git a/include/gp/pointers.hpp b/include/gp/pointers.hpp index 38afae1..73dd08a 100644 --- a/include/gp/pointers.hpp +++ b/include/gp/pointers.hpp @@ -5,183 +5,132 @@ #include "gp/buffer.hpp" #include "gp/function.hpp" -template -class unique_ptr; + template -class unique_ptr { - T* ptr; - gp::function deallocator; -public: - unique_ptr() - : ptr{nullptr} - {} +class unique_ptr { + T* data; + gp::allocator const& owner; - template - unique_ptr(T* _ptr, deal func) - : ptr{_ptr} - , deallocator{func} + unique_ptr(T* _data, gp::allocator const& _owner) + : data(data) + , owner(_owner) {} - unique_ptr(unique_ptr&) = delete; - - unique_ptr(unique_ptr&& oth) - : ptr{oth.ptr} - , deallocator{oth.deallocator} - { - oth.ptr = nullptr; - } - - void operator=(unique_ptr&) = delete; - - void operator=(unique_ptr&& oth) { - ptr = oth.ptr; - deallocator = oth.deallocator; - oth.ptr = nullptr; - } - - operator bool() { - return ptr != nullptr; - } - - T* operator->() { - return ptr; - } - - T* operator*() { - return ptr; - } - - ~unique_ptr() { - if(ptr) { - ptr->~T(); - gp_config::assertion(deallocator(ptr), "freeing unique_ptr failed"); + void dirty_clear() { + if(data) { + data->~T(); + owner.deallocate(data); } } -}; - -template -class unique_ptr>{ - T* ptr; - gp::reference_wrapper ref; public: - unique_ptr() - : ptr{nullptr} - {} + template + unique_ptr make(gp::allocator& owner, U&&... args) { + auto ptr = owner.allocate(sizeof(T)); + return unique_ptr(new(ptr) T(gp::forward(args)...), owner); + } - template - unique_ptr(Args ...args, allocator& _ref) - : ref{_ref} { - auto p = ref.get().allocate(sizeof(T)); - if(p) - { - ptr = new(p) T(args...); - } else { - ptr = nullptr; - } + T& operator->() { + return *data; } - unique_ptr(T* _ptr, allocator& _ref) - : ptr{_ptr} - , ref{_ref} - {} + T& operator*() { + return *data; + } unique_ptr(unique_ptr&) = delete; - + unique_ptr(unique_ptr&& oth) - : ptr{oth.ptr} - , ref{oth.ref} + : data(oth.data) + , owner(oth.owner) { - oth.ptr = nullptr; - } - - void operator=(unique_ptr&) = delete; - - void operator=(unique_ptr&& oth) { - ptr = oth.ptr; - ref = oth.ref; - oth.ptr = nullptr; + oth.data = nullptr; } - operator bool() { - return ptr != nullptr; - } - - T* operator->() { - return ptr; - } + unique_ptr& operator=(unique_ptr&) = delete; - T* operator*() { - return ptr; + unique_ptr& operator=(unique_ptr&& oth) { + dirty_clear(); + data = oth.data; + owner = oth.owner; } ~unique_ptr() { - if(ptr) { - ptr->~T(); - gp_config::assertion(ref.get().deallocate(ptr), "freeing unique_ptr failed"); - } + dirty_clear(); } }; -template -class unique_ptr{ - T* ptr; - allocator alloc; -public: - unique_ptr() - : ptr{nullptr} - {} - - unique_ptr(T* _ptr, allocator _alloc = allocator{}) - : ptr{_ptr} - , alloc{_alloc} +template +class shared_ptr { + T* data; + std::atomic_int* refcounter; + gp::allocator const& owner; + + shared_ptr(T* _data, gp::allocator const& _owner) + : data(data) + , owner(_owner) {} - template - unique_ptr(Args ...args, allocator _alloc = allocator{}) - : alloc{_alloc} { - auto p = alloc.allocate(sizeof(T)); - if(p) - { - ptr = new(p) T(args...); - } else { - ptr = nullptr; + void dirty_clear() { + if(!refcounter) return; + if(refcounter->fetch_sub(1, std::memory_order::acq_rel) == 0) { + if(data) { + data->~T(); + owner.deallocate(refcounter); + owner.deallocate(data); + } } } +public: + template + shared_ptr make(gp::allocator& owner, U&&... args) { + auto ptr = owner.allocate(sizeof(T)); + auto shared_atomic = owner.allocate(sizeof(std::atomic_int)); + refcounter = new(shared_atomic) std::atomic_int(); + refcounter->store(1); + return shared_ptr(new(ptr) T(gp::forward(args)...), owner); + } - unique_ptr(unique_ptr&) = delete; - - unique_ptr(unique_ptr&& oth) - : ptr{oth.ptr} - , alloc{oth.alloc} - { - oth.ptr = nullptr; + T& operator->() { + return *data; } - void operator=(unique_ptr&) = delete; + T& operator*() { + return *data; + } - void operator=(unique_ptr&& oth) { - ptr = oth.ptr; - alloc = oth.alloc; - oth.ptr = nullptr; + shared_ptr(shared_ptr& oth) { + oth.refcounter->fetch_add(1, std::memory_order::acquire); + + data = oth.data; + refcounter = oth.refcounter; + owner = oth.owner; } - operator bool() { - return ptr != nullptr; + shared_ptr(shared_ptr&& oth) + : data(oth.data) + , owner(oth.owner) + { + oth.data = nullptr; + oth.refcounter = nullptr; } - T* operator->() { - return ptr; + shared_ptr& operator=(shared_ptr& oth) { + dirty_clear(); + (*oth.refcounter)++; + + data = oth.data; + refcounter = oth.refcounter; + owner = oth.owner; } - T* operator*() { - return ptr; + shared_ptr& operator=(shared_ptr&& oth) { + dirty_clear(); + data = oth.data; + owner = oth.owner; } - ~unique_ptr() { - if(ptr) { - ptr->~T(); - gp_config::assertion(alloc.deallocate(ptr), "freeing unique_ptr failed"); - } + ~shared_ptr() { + dirty_clear(); } }; \ No newline at end of file