template class SharedHandleTraits; class NoDestructor { }; template struct HasDestructorType : std::false_type { }; template struct HasDestructorType::DestructorType() )> : std::true_type { }; template struct GetDestructorType { using type = NoDestructor; }; template struct GetDestructorType::value>::type> { using type = typename SharedHandleTraits::DestructorType; }; template using DestructorTypeOf = typename GetDestructorType::type; template struct HasDestructor : std::integral_constant, NoDestructor>::value> { }; //===================================================================================================================== template class SharedHandle; template struct SharedHeader { SharedHeader( SharedHandle parent, Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT : parent( std::move( parent ) ) , deleter( std::move( deleter ) ) { } SharedHandle parent; Deleter deleter; }; template struct SharedHeader { SharedHeader( Deleter deleter = Deleter() ) VULKAN_HPP_NOEXCEPT : deleter( std::move( deleter ) ) {} Deleter deleter; }; //===================================================================================================================== template class ReferenceCounter { public: template ReferenceCounter( Args &&... control_args ) : m_header( std::forward( control_args )... ) { } ReferenceCounter( const ReferenceCounter & ) = delete; ReferenceCounter & operator=( const ReferenceCounter & ) = delete; public: size_t addRef() VULKAN_HPP_NOEXCEPT { // Relaxed memory order is sufficient since this does not impose any ordering on other operations return m_ref_cnt.fetch_add( 1, std::memory_order_relaxed ); } size_t release() VULKAN_HPP_NOEXCEPT { // A release memory order to ensure that all releases are ordered return m_ref_cnt.fetch_sub( 1, std::memory_order_release ); } public: std::atomic_size_t m_ref_cnt{ 1 }; HeaderType m_header{}; }; //===================================================================================================================== template > class SharedHandleBase { public: SharedHandleBase() = default; template SharedHandleBase( HandleType handle, Args &&... control_args ) : m_control( new ReferenceCounter( std::forward( control_args )... ) ), m_handle( handle ) { } SharedHandleBase( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT { o.addRef(); m_handle = o.m_handle; m_control = o.m_control; } SharedHandleBase( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT : m_control( o.m_control ) , m_handle( o.m_handle ) { o.m_handle = nullptr; o.m_control = nullptr; } SharedHandleBase & operator=( const SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT { SharedHandleBase( o ).swap( *this ); return *this; } SharedHandleBase & operator=( SharedHandleBase && o ) VULKAN_HPP_NOEXCEPT { SharedHandleBase( std::move( o ) ).swap( *this ); return *this; } ~SharedHandleBase() { // only this function owns the last reference to the control block // the same principle is used in the default deleter of std::shared_ptr if ( m_control && ( m_control->release() == 1 ) ) { // noop in x86, but does thread synchronization in ARM // it is required to ensure that last thread is getting to destroy the control block // by ordering all atomic operations before this fence std::atomic_thread_fence( std::memory_order_acquire ); ForwardType::internalDestroy( getHeader(), m_handle ); delete m_control; } } public: HandleType get() const VULKAN_HPP_NOEXCEPT { return m_handle; } HandleType operator*() const VULKAN_HPP_NOEXCEPT { return m_handle; } explicit operator bool() const VULKAN_HPP_NOEXCEPT { return bool( m_handle ); } #if defined( VULKAN_HPP_SMART_HANDLE_IMPLICIT_CAST ) operator HandleType() const VULKAN_HPP_NOEXCEPT { return m_handle; } #endif const HandleType * operator->() const VULKAN_HPP_NOEXCEPT { return &m_handle; } HandleType * operator->() VULKAN_HPP_NOEXCEPT { return &m_handle; } void reset() VULKAN_HPP_NOEXCEPT { SharedHandleBase().swap( *this ); } void swap( SharedHandleBase & o ) VULKAN_HPP_NOEXCEPT { std::swap( m_handle, o.m_handle ); std::swap( m_control, o.m_control ); } template typename std::enable_if::value, const SharedHandle> &>::type getDestructorType() const VULKAN_HPP_NOEXCEPT { return getHeader().parent; } protected: template static typename std::enable_if::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT { control.deleter.destroy( handle ); } template static typename std::enable_if::value, void>::type internalDestroy( const HeaderType & control, HandleType handle ) VULKAN_HPP_NOEXCEPT { control.deleter.destroy( control.parent.get(), handle ); } const HeaderType & getHeader() const VULKAN_HPP_NOEXCEPT { return m_control->m_header; } private: void addRef() const VULKAN_HPP_NOEXCEPT { if ( m_control ) m_control->addRef(); } protected: ReferenceCounter * m_control = nullptr; HandleType m_handle{}; }; template class SharedHandle : public SharedHandleBase, typename SharedHandleTraits::deleter>> { private: using BaseType = SharedHandleBase, typename SharedHandleTraits::deleter>>; using DeleterType = typename SharedHandleTraits::deleter; friend BaseType; public: SharedHandle() = default; template ::value>::type> explicit SharedHandle( HandleType handle, SharedHandle> parent, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT : BaseType( handle, std::move( parent ), std::move( deleter ) ) { } template ::value>::type> explicit SharedHandle( HandleType handle, DeleterType deleter = DeleterType() ) VULKAN_HPP_NOEXCEPT : BaseType( handle, std::move( deleter ) ) { } protected: using BaseType::internalDestroy; };