From 4c276b1b1b946e4b08eb7b92a24d30bdc55106fd Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 4 May 2024 12:56:21 +0200 Subject: wip bptr --- compat/borrowed-ptr.cpp | 41 +++++++++++++ compat/borrowed-ptr.hpp | 49 ++++++++++++++++ compat/borrowed-ptr.inl | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 compat/borrowed-ptr.cpp create mode 100644 compat/borrowed-ptr.hpp create mode 100644 compat/borrowed-ptr.inl 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; +template class bptr; + +} // 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 class bptr; +template bptr static_pointer_cast(const bptr& p); + +template +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 static_pointer_cast(const bptr& p); + +public: + template + requires std::is_constructible_v + 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 requires std::is_convertible_v bptr(const bptr&) noexcept; + template requires std::is_convertible_v bptr(bptr&&) noexcept; + template requires std::is_convertible_v bptr& operator=(const bptr&) noexcept; + template requires std::is_convertible_v bptr& operator=(bptr&&) 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 constexpr bptr::bptr(std::nullptr_t) noexcept: ptr{nullptr}, blk{nullptr} {} +template constexpr bptr::bptr() noexcept: bptr{nullptr} {} + + +template bptr(T* ptr) -> bptr; + +} // 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 +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 +control_block::control_block(T* ptr) noexcept: + control_block_{ptr} +{ + fm_debug_assert(ptr); +} + +template +void control_block::free() noexcept +{ + delete static_cast(_ptr); +} + +template +control_block_* control_block::create(T* ptr) noexcept +{ + return ptr ? new control_block{ptr} : nullptr; +} + +} // namespace floormat::detail_borrowed_ptr + +namespace floormat { + +template +template +requires std::is_constructible_v +bptr::bptr(InPlaceInitT, Ts&&... args) noexcept: +bptr{ new T{ forward(args...) } } +{ +} + +template +bptr::bptr(T* ptr) noexcept: + ptr{ptr}, + blk{detail_borrowed_ptr::control_block::create(ptr)} +{ +} + +template +bptr::~bptr() noexcept +{ + if (blk) + blk->decr(); + //blk = reinterpret_cast(-1); +} + +template +template +requires std::is_convertible_v +bptr::bptr(const bptr& other) noexcept: + ptr{other.ptr}, blk{other.blk} +{ + static_assert(std::is_convertible_v); + if (blk) + blk->incr(); + else + fm_debug_assert(!ptr); +} + +template +template +requires std::is_convertible_v +bptr::bptr(bptr&& other) noexcept: ptr{other.ptr}, blk{other.blk} +{ + other.ptr = nullptr; + other.blk = nullptr; +} + +template +template +requires std::is_convertible_v +bptr& bptr::operator=(const bptr& other) noexcept +{ + static_assert(std::is_convertible_v); + 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 +template +requires std::is_convertible_v +bptr& bptr::operator=(bptr&& other) noexcept +{ + ptr = other.ptr; + blk = other.blk; + other.ptr = nullptr; + other.blk = nullptr; + return *this; +} + +template +bptr static_pointer_cast(const bptr& p) +{ + auto ret = bptr{}; + ret.blk = p.blk; + if (ret.blk) [[likely]] + ret.blk->incr(); + ret.ptr = static_cast(p.ptr); + return ret; +} + +} // namespace floormat -- cgit v1.2.3