|
|
@ -5,183 +5,132 @@ |
|
|
|
#include "gp/buffer.hpp"
|
|
|
|
#include "gp/function.hpp"
|
|
|
|
|
|
|
|
template<typename T, typename allocator_t = void> |
|
|
|
class unique_ptr; |
|
|
|
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
class unique_ptr<T, void> { |
|
|
|
T* ptr; |
|
|
|
gp::function<bool(T*)> deallocator; |
|
|
|
public: |
|
|
|
unique_ptr() |
|
|
|
: ptr{nullptr} |
|
|
|
{} |
|
|
|
class unique_ptr { |
|
|
|
T* data; |
|
|
|
gp::allocator const& owner; |
|
|
|
|
|
|
|
template<typename deal> |
|
|
|
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<typename T, typename allocator> |
|
|
|
class unique_ptr<T, gp::reference_wrapper<allocator>>{ |
|
|
|
T* ptr; |
|
|
|
gp::reference_wrapper<allocator> ref; |
|
|
|
public: |
|
|
|
unique_ptr() |
|
|
|
: ptr{nullptr} |
|
|
|
{} |
|
|
|
template<typename ...U> |
|
|
|
unique_ptr make(gp::allocator& owner, U&&... args) { |
|
|
|
auto ptr = owner.allocate(sizeof(T)); |
|
|
|
return unique_ptr(new(ptr) T(gp::forward<U>(args)...), owner); |
|
|
|
} |
|
|
|
|
|
|
|
template<typename ...Args> |
|
|
|
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<typename T, typename allocator> |
|
|
|
class unique_ptr{ |
|
|
|
T* ptr; |
|
|
|
allocator alloc; |
|
|
|
public: |
|
|
|
unique_ptr() |
|
|
|
: ptr{nullptr} |
|
|
|
{} |
|
|
|
|
|
|
|
unique_ptr(T* _ptr, allocator _alloc = allocator{}) |
|
|
|
: ptr{_ptr} |
|
|
|
, alloc{_alloc} |
|
|
|
template<typename T> |
|
|
|
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<typename ...Args> |
|
|
|
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<typename ...U> |
|
|
|
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<U>(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(); |
|
|
|
} |
|
|
|
}; |