#pragma once #include "borrowed-ptr.hpp" #include "compat/assert.hpp" #define FM_BPTR_DEBUG #ifdef __CLION_IDE__ #define fm_bptr_assert(...) (void(__VA_ARGS__)) #elif defined FM_BPTR_DEBUG && !defined FM_NO_DEBUG #define fm_bptr_assert(...) fm_assert(__VA_ARGS__) #else #define fm_bptr_assert(...) void() #endif #ifdef __GNUG__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #endif namespace floormat::detail_bptr { #ifdef __GNUG__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" #endif struct control_block { bptr_base* _ptr; uint32_t _count; static void decrement(control_block*& blk) noexcept; }; #ifdef __GNUG__ #pragma GCC diagnostic pop #endif } // namespace floormat::detail_bptr namespace floormat { template template requires std::is_constructible_v, Ts&&...> bptr::bptr(InPlaceInitT, Ts&&... args) noexcept: bptr{ new std::remove_const_t{ forward(args)... } } {} template bptr::bptr(std::nullptr_t) noexcept: blk{nullptr} {} template bptr::bptr() noexcept: bptr{nullptr} {} template bptr::bptr(T* ptr) noexcept requires std::is_convertible_v: blk{ptr ? new detail_bptr::control_block{const_cast*>(ptr), 1} : nullptr} {} template bptr::~bptr() noexcept { if (blk) blk->decrement(blk); } template template Y> bptr::bptr(const bptr& other) noexcept: blk{other.blk} { if (blk) ++blk->_count; } template template Y> bptr& bptr::operator=(const bptr& other) noexcept { if (blk != other.blk) { if (blk) blk->decrement(blk); blk = other.blk; if (blk) ++blk->_count; } return *this; } template template Y> bptr::bptr(bptr&& other) noexcept: blk{other.blk} { other.blk = nullptr; } template template Y> bptr& bptr::operator=(bptr&& other) noexcept { if (blk) blk->decrement(blk); blk = other.blk; other.blk = nullptr; return *this; } template void bptr::reset() noexcept { if (blk) blk->decrement(blk); } template void bptr::destroy() noexcept { if (!blk) return; delete blk->_ptr; blk->_ptr = nullptr; } template bptr& bptr::operator=(std::nullptr_t) noexcept { reset(); return *this; } template T* bptr::get() const noexcept { if (blk) [[likely]] return static_cast(blk->_ptr); else return nullptr; } template T* bptr::operator->() const noexcept { auto* ret = get(); fm_bptr_assert(ret); return ret; } template T& bptr::operator*() const noexcept { return *operator->(); } template bptr::operator bool() const noexcept { return blk && blk->_ptr; } template bool bptr::operator==(const bptr>& other) const noexcept { return get() == other.get(); } template bool bptr::operator==(const bptr>& other) const noexcept { return get() == other.get(); } template bool bptr::operator==(const std::nullptr_t&) const noexcept { return !blk || !blk->_ptr; } template void bptr::swap(bptr& other) noexcept { floormat::swap(blk, other.blk); } template uint32_t bptr::use_count() const noexcept { if (blk && blk->_ptr) [[likely]] return blk->_count; else return 0; } } // namespace floormat #ifdef __GNUG__ #pragma GCC diagnostic pop #endif