Skip to content
Snippets Groups Projects
SharedPointerHost.h 6.81 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***************************************************************************
                              SharedPointerHost.h  -  description
                                 -------------------
        begin                : Aug 22, 2018
        copyright            : (C) 2018 by Tomas Oberhuber et al.
        email                : tomas.oberhuber@fjfi.cvut.cz
     ***************************************************************************/
    
    /* See Copyright Notice in tnl/Copyright */
    
    // Implemented by: Tomas Oberhuber, Jakub Klinkovsky
    
    #pragma once
    
    
    #include "SharedPointer.h"
    
    
    #include <TNL/Devices/CudaCallable.h>
    
    #include <cstddef>  // std::nullptr_t
    
    
    namespace Pointers {
    
    class SharedPointer< Object, Devices::Host > : public SmartPointer
    
    {
       private:
          // Convenient template alias for controlling the selection of copy- and
          // move-constructors and assignment operators using SFINAE.
          // The type Object_ is "enabled" iff Object_ and Object are not the same,
          // but after removing const and volatile qualifiers they are the same.
          template< typename Object_ >
          using Enabler = std::enable_if< ! std::is_same< Object_, Object >::value &&
                                          std::is_same< typename std::remove_cv< Object >::type, Object_ >::value >;
    
          // friend class will be needed for templated assignment operators
          template< typename Object_, typename Device_ >
          friend class SharedPointer;
    
       public:
    
          typedef Object ObjectType;
          typedef Devices::Host DeviceType;
          typedef SharedPointer<  Object, Devices::Host > ThisType;
    
    
          SharedPointer( std::nullptr_t )
          : pd( nullptr )
    
          template< typename... Args >
          explicit  SharedPointer( Args... args )
          : pd( nullptr )
          {
    #ifdef TNL_DEBUG_SHARED_POINTERS
             std::cerr << "Creating shared pointer to " << demangle(typeid(ObjectType).name()) << std::endl;
    #endif
             this->allocate( args... );
          }
    
          // this is needed only to avoid the default compiler-generated constructor
          SharedPointer( const ThisType& pointer )
          : pd( (PointerData*) pointer.pd )
          {
             this->pd->counter += 1;
          }
    
          // conditional constructor for non-const -> const data
          template< typename Object_,
                    typename = typename Enabler< Object_ >::type >
          SharedPointer( const SharedPointer<  Object_, DeviceType >& pointer )
          : pd( (PointerData*) pointer.pd )
          {
             this->pd->counter += 1;
          }
    
          // this is needed only to avoid the default compiler-generated constructor
          SharedPointer( ThisType&& pointer )
          : pd( (PointerData*) pointer.pd )
          {
             pointer.pd = nullptr;
          }
    
          // conditional constructor for non-const -> const data
          template< typename Object_,
                    typename = typename Enabler< Object_ >::type >
          SharedPointer( SharedPointer<  Object_, DeviceType >&& pointer )
          : pd( (PointerData*) pointer.pd )
          {
             pointer.pd = nullptr;
          }
    
          template< typename... Args >
          bool recreate( Args... args )
          {
    #ifdef TNL_DEBUG_SHARED_POINTERS
             std::cerr << "Recreating shared pointer to " << demangle(typeid(ObjectType).name()) << std::endl;
    #endif
             if( ! this->counter )
                return this->allocate( args... );
    
             if( *this->pd->counter == 1 )
             {
                /****
                 * The object is not shared -> recreate it in-place, without reallocation
                 */
                this->pd->data.~ObjectType();
                new ( this->pd->data ) ObjectType( args... );
                return true;
             }
    
             // free will just decrement the counter
             this->free();
    
             return this->allocate( args... );
          }
    
          const Object* operator->() const
          {
             return &this->pd->data;
          }
    
          Object* operator->()
          {
             return &this->pd->data;
          }
    
          const Object& operator *() const
          {
             return this->pd->data;
          }
    
          Object& operator *()
          {
             return this->pd->data;
          }
    
          __cuda_callable__
          operator bool() const
          {
             return this->pd;
          }
    
          __cuda_callable__
          bool operator!() const
          {
             return ! this->pd;
          }
    
          template< typename Device = Devices::Host >
          __cuda_callable__
          const Object& getData() const
          {
             return this->pd->data;
    
          template< typename Device = Devices::Host >
          __cuda_callable__
          Object& modifyData()
          {
             return this->pd->data;
          }
    
          // this is needed only to avoid the default compiler-generated operator
          const ThisType& operator=( const ThisType& ptr )
          {
             this->free();
             this->pd = (PointerData*) ptr.pd;
             this->pd->counter += 1;
             return *this;
          }
    
          // conditional operator for non-const -> const data
          template< typename Object_,
                    typename = typename Enabler< Object_ >::type >
          const ThisType& operator=( const SharedPointer<  Object_, DeviceType >& ptr )
          {
             this->free();
             this->pd = (PointerData*) ptr.pd;
             this->pd->counter += 1;
             return *this;
          }
    
          // this is needed only to avoid the default compiler-generated operator
          const ThisType& operator=( ThisType&& ptr )
          {
             this->free();
             this->pd = (PointerData*) ptr.pd;
             ptr.pd = nullptr;
             return *this;
          }
    
          // conditional operator for non-const -> const data
          template< typename Object_,
                    typename = typename Enabler< Object_ >::type >
          const ThisType& operator=( SharedPointer<  Object_, DeviceType >&& ptr )
          {
             this->free();
             this->pd = (PointerData*) ptr.pd;
             ptr.pd = nullptr;
             return *this;
          }
    
          bool synchronize()
          {
             return true;
          }
    
          void swap( ThisType& ptr2 )
          {
             std::swap( this->pd, ptr2.pd );
          }
          
    
          ~SharedPointer()
          {
             this->free();
          }
    
    
       protected:
    
          struct PointerData
          {
             Object data;
             int counter;
    
             template< typename... Args >
             explicit PointerData( Args... args )
             : data( args... ),
               counter( 1 )
             {}
          };
    
          template< typename... Args >
          bool allocate( Args... args )
          {
             this->pd = new PointerData( args... );
             return this->pd;
          }
    
          void free()
          {
             if( this->pd )
             {
                if( ! --this->pd->counter )
                {
                   delete this->pd;
                   this->pd = nullptr;
                }
             }
    
          }
    
          PointerData* pd;
    };
    
    
    } // namespace Pointers