Skip to content

Commit

Permalink
memory: implement a unique pointer
Browse files Browse the repository at this point in the history
this unique pointer differs from the STL, because it allows weak pointers to it, which cannot be lock()ed.

under the hood, it's just a SP that cannot be referenced.
  • Loading branch information
vaxerski committed Jan 23, 2025
1 parent 59414c4 commit 423c69d
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 115 deletions.
119 changes: 119 additions & 0 deletions include/hyprutils/memory/ImplBase.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#pragma once

#include <memory>

namespace Hyprutils {
namespace Memory {
namespace Impl_ {
class impl_base {
public:
virtual ~impl_base() {};

virtual void inc() noexcept = 0;
virtual void dec() noexcept = 0;
virtual void incWeak() noexcept = 0;
virtual void decWeak() noexcept = 0;
virtual unsigned int ref() noexcept = 0;
virtual unsigned int wref() noexcept = 0;
virtual void destroy() noexcept = 0;
virtual bool destroying() noexcept = 0;
virtual bool dataNonNull() noexcept = 0;
virtual bool lockable() noexcept = 0;
virtual void* getData() noexcept = 0;
};

template <typename T>
class impl : public impl_base {
public:
impl(T* data, bool lock = true) noexcept : _data(data), _lockable(lock) {
;
}

/* strong refcount */
unsigned int _ref = 0;
/* weak refcount */
unsigned int _weak = 0;
/* if this is lockable (shared) */
bool _lockable = true;

T* _data = nullptr;

friend void swap(impl*& a, impl*& b) {
impl* tmp = a;
a = b;
b = tmp;
}

/* if the destructor was called,
creating shared_ptrs is no longer valid */
bool _destroying = false;

void _destroy() {
if (!_data || _destroying)
return;

// first, we destroy the data, but keep the pointer.
// this way, weak pointers will still be able to
// reference and use, but no longer create shared ones.
_destroying = true;
__deleter(_data);
// now, we can reset the data and call it a day.
_data = nullptr;
_destroying = false;
}

std::default_delete<T> __deleter{};

//
virtual void inc() noexcept {
_ref++;
}

virtual void dec() noexcept {
_ref--;
}

virtual void incWeak() noexcept {
_weak++;
}

virtual void decWeak() noexcept {
_weak--;
}

virtual unsigned int ref() noexcept {
return _ref;
}

virtual unsigned int wref() noexcept {
return _weak;
}

virtual void destroy() noexcept {
_destroy();
}

virtual bool destroying() noexcept {
return _destroying;
}

virtual bool lockable() noexcept {
return _lockable;
}

virtual bool dataNonNull() noexcept {
return _data != nullptr;
}

virtual void* getData() noexcept {
return _data;
}

virtual ~impl() {
destroy();
}
};
}
}

}
113 changes: 4 additions & 109 deletions include/hyprutils/memory/SharedPtr.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>
#include "ImplBase.hpp"

/*
This is a custom impl of std::shared_ptr.
Expand All @@ -17,109 +15,6 @@

namespace Hyprutils {
namespace Memory {
namespace CSharedPointer_ {
class impl_base {
public:
virtual ~impl_base() {};

virtual void inc() noexcept = 0;
virtual void dec() noexcept = 0;
virtual void incWeak() noexcept = 0;
virtual void decWeak() noexcept = 0;
virtual unsigned int ref() noexcept = 0;
virtual unsigned int wref() noexcept = 0;
virtual void destroy() noexcept = 0;
virtual bool destroying() noexcept = 0;
virtual bool dataNonNull() noexcept = 0;
virtual void* getData() noexcept = 0;
};

template <typename T>
class impl : public impl_base {
public:
impl(T* data) noexcept : _data(data) {
;
}

/* strong refcount */
unsigned int _ref = 0;
/* weak refcount */
unsigned int _weak = 0;

T* _data = nullptr;

friend void swap(impl*& a, impl*& b) {
impl* tmp = a;
a = b;
b = tmp;
}

/* if the destructor was called,
creating shared_ptrs is no longer valid */
bool _destroying = false;

void _destroy() {
if (!_data || _destroying)
return;

// first, we destroy the data, but keep the pointer.
// this way, weak pointers will still be able to
// reference and use, but no longer create shared ones.
_destroying = true;
__deleter(_data);
// now, we can reset the data and call it a day.
_data = nullptr;
_destroying = false;
}

std::default_delete<T> __deleter{};

//
virtual void inc() noexcept {
_ref++;
}

virtual void dec() noexcept {
_ref--;
}

virtual void incWeak() noexcept {
_weak++;
}

virtual void decWeak() noexcept {
_weak--;
}

virtual unsigned int ref() noexcept {
return _ref;
}

virtual unsigned int wref() noexcept {
return _weak;
}

virtual void destroy() noexcept {
_destroy();
}

virtual bool destroying() noexcept {
return _destroying;
}

virtual bool dataNonNull() noexcept {
return _data != nullptr;
}

virtual void* getData() noexcept {
return _data;
}

virtual ~impl() {
destroy();
}
};
};

template <typename T>
class CSharedPointer {
Expand All @@ -132,7 +27,7 @@ namespace Hyprutils {
/* creates a new shared pointer managing a resource
avoid calling. Could duplicate ownership. Prefer makeShared */
explicit CSharedPointer(T* object) noexcept {
impl_ = new CSharedPointer_::impl<T>(object);
impl_ = new Impl_::impl<T>(object);
increment();
}

Expand All @@ -158,7 +53,7 @@ namespace Hyprutils {
}

/* allows weakPointer to create from an impl */
CSharedPointer(CSharedPointer_::impl_base* implementation) noexcept {
CSharedPointer(Impl_::impl_base* implementation) noexcept {
impl_ = implementation;
increment();
}
Expand Down Expand Up @@ -246,7 +141,7 @@ namespace Hyprutils {
return impl_ ? impl_->ref() : 0;
}

CSharedPointer_::impl_base* impl_ = nullptr;
Impl_::impl_base* impl_ = nullptr;

private:
/*
Expand Down
Loading

0 comments on commit 423c69d

Please sign in to comment.