summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-05-04 12:56:21 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-05-05 03:31:18 +0200
commit4c276b1b1b946e4b08eb7b92a24d30bdc55106fd (patch)
tree981ef0a821714edcb7e11543fb952b41be2d1ec6
parent88f6fe2b4c51fd318a1ce8994d7affb35696d418 (diff)
wip bptr
-rw-r--r--compat/borrowed-ptr.cpp41
-rw-r--r--compat/borrowed-ptr.hpp49
-rw-r--r--compat/borrowed-ptr.inl152
3 files changed, 242 insertions, 0 deletions
diff --git a/compat/borrowed-ptr.cpp b/compat/borrowed-ptr.cpp
new file mode 100644
index 00000000..8c05b751
--- /dev/null
+++ b/compat/borrowed-ptr.cpp
@@ -0,0 +1,41 @@
+#include "borrowed-ptr.inl"
+#include "compat/assert.hpp"
+
+namespace floormat::detail_borrowed_ptr {
+
+control_block_::control_block_(void* ptr) noexcept: _ptr{ptr}, _count{1}
+{
+ fm_debug_assert(ptr);
+}
+
+void control_block_::incr() noexcept
+{
+ auto val = ++_count;
+ (void)val;
+ fm_debug_assert(val > 1);
+}
+
+void control_block_::decr() noexcept
+{
+ auto val = --_count;
+ fm_debug_assert(val != (uint32_t)-1);
+ if (val == 0)
+ {
+ free();
+ _ptr = nullptr;
+ }
+}
+
+control_block_::~control_block_() noexcept { decr(); }
+uint32_t control_block_::count() const noexcept { return _count; }
+
+} // namespace floormat::detail_borrowed_ptr
+
+namespace floormat {
+
+namespace { struct Foo {}; }
+
+template struct detail_borrowed_ptr::control_block<Foo>;
+template class bptr<Foo>;
+
+} // namespace floormat
diff --git a/compat/borrowed-ptr.hpp b/compat/borrowed-ptr.hpp
new file mode 100644
index 00000000..f649cae3
--- /dev/null
+++ b/compat/borrowed-ptr.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+namespace floormat::detail_borrowed_ptr {
+struct control_block_;
+} // namespace floormat::detail_borrowed_ptr
+
+namespace floormat {
+template<typename T> class bptr;
+template<typename T> bptr<T> static_pointer_cast(const bptr<T>& p);
+
+template<typename T>
+class bptr final // NOLINT(*-special-member-functions)
+{
+ T* ptr; // todo add simple_bptr that doesn't allow casting. should only have the control block element.
+ detail_borrowed_ptr::control_block_* blk;
+
+ friend bptr<T> static_pointer_cast<T>(const bptr<T>& p);
+
+public:
+ template<typename... Ts>
+ requires std::is_constructible_v<T, Ts&&...>
+ explicit bptr(InPlaceInitT, Ts&&... args) noexcept;
+
+ constexpr bptr(std::nullptr_t) noexcept; // NOLINT(*-explicit-conversions)
+ constexpr bptr() noexcept;
+ explicit bptr(T* ptr) noexcept;
+ ~bptr() noexcept;
+
+ template<typename Y> requires std::is_convertible_v<Y*, T*> bptr(const bptr<Y>&) noexcept;
+ template<typename Y> requires std::is_convertible_v<Y*, T*> bptr(bptr<Y>&&) noexcept;
+ template<typename Y> requires std::is_convertible_v<Y*, T*> bptr& operator=(const bptr<Y>&) noexcept;
+ template<typename Y> requires std::is_convertible_v<Y*, T*> bptr& operator=(bptr<Y>&&) noexcept;
+
+ void swap() noexcept;
+ T* get() noexcept;
+ const T* get() const noexcept;
+ T& operator*() const noexcept;
+ T* operator->() const noexcept;
+ uint32_t use_count() const noexcept;
+ explicit operator bool() const noexcept;
+};
+
+template<typename T> constexpr bptr<T>::bptr(std::nullptr_t) noexcept: ptr{nullptr}, blk{nullptr} {}
+template<typename T> constexpr bptr<T>::bptr() noexcept: bptr{nullptr} {}
+
+
+template<typename T> bptr(T* ptr) -> bptr<T>;
+
+} // namespace floormat
diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl
new file mode 100644
index 00000000..1d0ac7b6
--- /dev/null
+++ b/compat/borrowed-ptr.inl
@@ -0,0 +1,152 @@
+#pragma once
+#include "compat/assert.hpp"
+#include "borrowed-ptr.hpp"
+
+namespace floormat::detail_borrowed_ptr {
+
+#ifdef __GNUG__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+struct control_block_
+{
+ explicit control_block_(void* ptr) noexcept;
+ ~control_block_() noexcept;
+ void incr() noexcept;
+ void decr() noexcept;
+ uint32_t count() const noexcept;
+
+ void* _ptr; // todo maybe add directly embeddable objects?
+ uint32_t _count;
+
+private:
+ virtual void free() noexcept = 0;
+};
+
+#ifdef __GNUG__
+#pragma GCC diagnostic pop
+#endif
+
+template<typename T>
+struct control_block final: control_block_
+{
+ void free() noexcept override;
+ [[nodiscard]] static control_block_* create(T* ptr) noexcept;
+
+protected:
+ explicit control_block(T* ptr) noexcept;
+};
+
+template <typename T>
+control_block<T>::control_block(T* ptr) noexcept:
+ control_block_{ptr}
+{
+ fm_debug_assert(ptr);
+}
+
+template <typename T>
+void control_block<T>::free() noexcept
+{
+ delete static_cast<T*>(_ptr);
+}
+
+template <typename T>
+control_block_* control_block<T>::create(T* ptr) noexcept
+{
+ return ptr ? new control_block<T>{ptr} : nullptr;
+}
+
+} // namespace floormat::detail_borrowed_ptr
+
+namespace floormat {
+
+template<typename T>
+template<typename... Ts>
+requires std::is_constructible_v<T, Ts&&...>
+bptr<T>::bptr(InPlaceInitT, Ts&&... args) noexcept:
+bptr{ new T{ forward<Ts...>(args...) } }
+{
+}
+
+template<typename T>
+bptr<T>::bptr(T* ptr) noexcept:
+ ptr{ptr},
+ blk{detail_borrowed_ptr::control_block<T>::create(ptr)}
+{
+}
+
+template<typename T>
+bptr<T>::~bptr() noexcept
+{
+ if (blk)
+ blk->decr();
+ //blk = reinterpret_cast<T*>(-1);
+}
+
+template<typename T>
+template<typename Y>
+requires std::is_convertible_v<Y*, T*>
+bptr<T>::bptr(const bptr<Y>& other) noexcept:
+ ptr{other.ptr}, blk{other.blk}
+{
+ static_assert(std::is_convertible_v<Y*, T*>);
+ if (blk)
+ blk->incr();
+ else
+ fm_debug_assert(!ptr);
+}
+
+template<typename T>
+template<typename Y>
+requires std::is_convertible_v<Y*, T*>
+bptr<T>::bptr(bptr<Y>&& other) noexcept: ptr{other.ptr}, blk{other.blk}
+{
+ other.ptr = nullptr;
+ other.blk = nullptr;
+}
+
+template<typename T>
+template<typename Y>
+requires std::is_convertible_v<Y*, T*>
+bptr<T>& bptr<T>::operator=(const bptr<Y>& other) noexcept
+{
+ static_assert(std::is_convertible_v<Y*, T*>);
+ auto* const newblk = other.blk;
+ if (blk != newblk)
+ {
+ CORRADE_ASSUME(this != &other);
+ ptr = other.ptr;
+ if (blk)
+ blk->decr();
+ blk = newblk;
+ if (newblk)
+ newblk->incr();
+ }
+ return *this;
+}
+
+template<typename T>
+template<typename Y>
+requires std::is_convertible_v<Y*, T*>
+bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept
+{
+ ptr = other.ptr;
+ blk = other.blk;
+ other.ptr = nullptr;
+ other.blk = nullptr;
+ return *this;
+}
+
+template<typename T, typename U>
+bptr<T> static_pointer_cast(const bptr<U>& p)
+{
+ auto ret = bptr<T>{};
+ ret.blk = p.blk;
+ if (ret.blk) [[likely]]
+ ret.blk->incr();
+ ret.ptr = static_cast<T*>(p.ptr);
+ return ret;
+}
+
+} // namespace floormat