Browse Source

Better pointers

channel
Ludovic 'Archivist' Lagouardette 3 years ago
parent
commit
b05e710bfe
2 changed files with 89 additions and 138 deletions
  1. +2
    -0
      include/gp/memory.hpp
  2. +87
    -138
      include/gp/pointers.hpp

+ 2
- 0
include/gp/memory.hpp View File

@ -2,6 +2,8 @@
#include "gp_config.hpp"
#include "gp/algorithm/move.hpp"
#include "gp/allocator/allocator.hpp"
#include "gp/exception.hpp"
#include <type_traits>

+ 87
- 138
include/gp/pointers.hpp View File

@ -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();
}
};

Loading…
Cancel
Save