Loading src/TNL/Pointers/DevicePointer.h +351 −57 Original line number Diff line number Diff line Loading @@ -20,15 +20,31 @@ #include <TNL/TypeInfo.h> #include <TNL/Cuda/MemoryHelpers.h> #include <cstring> #include <c++/8/bits/c++config.h> // std::memcpy, std::memcmp #include <cstring> // std::memcpy, std::memcmp namespace TNL { namespace Pointers { /*** * The DevicePointer is like SharedPointer, except it takes an existing host /** * \brief The DevicePointer is like SharedPointer, except it takes an existing host * object - there is no call to the ObjectType's constructor nor destructor. * * **NOTE: When using smart pointers to pass objects on GPU, one must call * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * before calling a CUDA kernel working with smart pointers.** * * \tparam Object is a type of object to be owned by the pointer. * \tparam Device is device where the object is to be allocated. The object is * always allocated on the host system as well for easier object manipulation. * * See also \ref UniquePointer and \ref SharedPointer. * * See also \ref DevicePointer< Object, Devices::Host > and \ref DevicePointer< Object, Devices::Cuda >. * * \par Example * \include Pointers/DevicePointerExample.cpp * \par Output * \include DevicePointerExample.out */ template< typename Object, typename Device = typename Object::DeviceType > Loading @@ -37,17 +53,22 @@ class DevicePointer static_assert( ! std::is_same< Device, void >::value, "The device cannot be void. You need to specify the device explicitly in your code." ); }; /**** * Specialization for Devices::Host /** * \brief Specialization of the \ref DevicePointer for the host system. * * \tparam Object is a type of object to be owned by the pointer. */ template< typename Object > class DevicePointer< 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. /** * \typedef Enabler * 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 >; Loading @@ -58,84 +79,161 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer public: typedef Object ObjectType; typedef Devices::Host DeviceType; /** * \typedef ObjectType is the type of object owned by the pointer. */ using ObjectType = Object; /** * \brief Constructor of empty pointer. * \typedef DeviceType is the type of device where the object is to be * mirrored. */ using DeviceType = Devices::Host; /** * \brief Constructor of an empty pointer. */ DevicePointer( std::nullptr_t ) : pointer( nullptr ) {} /** * \brief Constructor with an object reference. * * \param obj reference to an object to be managed by the pointer. */ explicit DevicePointer( ObjectType& obj ) : pointer( nullptr ) { this->pointer = &obj; } // this is needed only to avoid the default compiler-generated constructor DevicePointer( const DevicePointer& pointer ) /** * \brief Copy constructor. * * \param pointer is the source device pointer. */ DevicePointer( const DevicePointer& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ) { } // conditional constructor for non-const -> const data /** * \brief Copy constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ) { } // this is needed only to avoid the default compiler-generated constructor DevicePointer( DevicePointer&& pointer ) /** * \brief Move constructor. * * \param pointer is the source device pointer. */ DevicePointer( DevicePointer&& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ) { pointer.pointer = nullptr; } // conditional constructor for non-const -> const data /** * \brief Move constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ) { pointer.pointer = nullptr; } /** * \brief Arrow operator for accessing the object owned by constant smart pointer. * * \return constant pointer to the object owned by this smart pointer. */ const Object* operator->() const { return this->pointer; } /** * \brief Arrow operator for accessing the object owned by non-constant smart pointer. * * \return pointer to the object owned by this smart pointer. */ Object* operator->() { return this->pointer; } /** * \brief Dereferencing operator for accessing the object owned by constant smart pointer. * * \return constant reference to the object owned by this smart pointer. */ const Object& operator *() const { return *( this->pointer ); } /** * \brief Dereferencing operator for accessing the object owned by non-constant smart pointer. * * \return reference to the object owned by this smart pointer. */ Object& operator *() { return *( this->pointer ); } /** * \brief Conversion to boolean type. * * \return Returns true if the pointer is not empty, false otherwise. */ __cuda_callable__ operator bool() const { return this->pointer; } /** * \brief Negation operator. * * \return Returns false if the pointer is not empty, true otherwise. */ __cuda_callable__ bool operator!() const { return ! this->pointer; } /** * \brief Constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ const Object& getData() const Loading @@ -143,6 +241,16 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer return *( this->pointer ); } /** * \brief Non-constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ Object& modifyData() Loading @@ -150,40 +258,79 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer return *( this->pointer ); } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( const DevicePointer& ptr ) /** * \brief Assignment operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( const DevicePointer& ptr ) // this is needed only to avoid the default compiler-generated operator { this->pointer = ptr.pointer; return *this; } // conditional operator for non-const -> const data /** * \brief Assignment operator for compatible object types. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) // conditional operator for non-const -> const data { this->pointer = ptr.pointer; return *this; } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( DevicePointer&& ptr ) /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( DevicePointer&& ptr ) // this is needed only to avoid the default compiler-generated operator { this->pointer = ptr.pointer; ptr.pointer = nullptr; return *this; } // conditional operator for non-const -> const data /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) // conditional operator for non-const -> const data { this->pointer = ptr.pointer; ptr.pointer = nullptr; return *this; } /** * \brief Cross-device pointer synchronization. * * For the smart pointers on the host, this method does nothing. * * \return true. */ bool synchronize() { return true; Loading @@ -192,14 +339,16 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer /** * \brief Swap the owned object with another pointer. * * \param ptr2 the other shared pointer for swapping. * \param ptr2 the other device pointer for swapping. */ void swap( DevicePointer& ptr2 ) { std::swap( this->pointer, ptr2.pointer ); } /** * \brief Destructor. */ ~DevicePointer() { } Loading @@ -210,17 +359,23 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer Object* pointer; }; /**** * Specialization for CUDA /** * \brief Specialization of the \ref DevicePointer for the CUDA device. * * \tparam Object is a type of object to be owned by the pointer. */ template< typename Object > class DevicePointer< Object, Devices::Cuda > : 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. /** * \typedef Enabler * * 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 >; Loading @@ -231,8 +386,16 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer public: typedef Object ObjectType; typedef Devices::Cuda DeviceType; /** * \typedef ObjectType is the type of object owned by the pointer. */ using ObjectType = Object; /** * \typedef DeviceType is the type of device where the object is to be * mirrored. */ using DeviceType = Devices::Cuda; /** * \brief Constructor of empty pointer. Loading @@ -242,6 +405,11 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pd( nullptr ), cuda_pointer( nullptr ) {} /** * \brief Constructor with an object reference. * * \param obj is a reference on an object to be managed by the pointer. */ explicit DevicePointer( ObjectType& obj ) : pointer( nullptr ), pd( nullptr ), Loading @@ -250,8 +418,12 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->allocate( obj ); } // this is needed only to avoid the default compiler-generated constructor DevicePointer( const DevicePointer& pointer ) /** * \brief Copy constructor. * * \param pointer is the source device pointer. */ DevicePointer( const DevicePointer& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -259,10 +431,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->pd->counter += 1; } // conditional constructor for non-const -> const data /** * \brief Copy constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -270,8 +450,12 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->pd->counter += 1; } // this is needed only to avoid the default compiler-generated constructor DevicePointer( DevicePointer&& pointer ) /** * \brief Move constructor. * * \param pointer is the source device pointer. */ DevicePointer( DevicePointer&& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -281,10 +465,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pointer.cuda_pointer = nullptr; } // conditional constructor for non-const -> const data /** * \brief Move constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -294,6 +486,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pointer.cuda_pointer = nullptr; } /** * \brief Arrow operator for accessing the object owned by constant smart pointer. * * \return constant pointer to the object owned by this smart pointer. It * returns pointer to object image on the CUDA device if it is called from CUDA * kernel and pointer to host image otherwise. */ __cuda_callable__ const Object* operator->() const { Loading @@ -304,6 +503,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Arrow operator for accessing the object owned by non-constant smart pointer. * * \return pointer to the object owned by this smart pointer. It * returns pointer to object image on the CUDA device if it is called from CUDA * kernel and pointer to host image otherwise. */ __cuda_callable__ Object* operator->() { Loading @@ -315,6 +521,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Dereferencing operator for accessing the object owned by constant smart pointer. * * \return constant reference to the object owned by this smart pointer. It * returns reference to object image on the CUDA device if it is called from CUDA * kernel and reference to host image otherwise. */ __cuda_callable__ const Object& operator *() const { Loading @@ -325,6 +538,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Dereferencing operator for accessing the object owned by non-constant smart pointer. * * \return reference to the object owned by this smart pointer. It * returns reference to object image on the CUDA device if it is called from CUDA * kernel and reference to host image otherwise. */ __cuda_callable__ Object& operator *() { Loading @@ -336,18 +556,38 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Conversion to boolean type. * * \return Returns true if the pointer is not empty, false otherwise. */ __cuda_callable__ operator bool() const { return this->pd; } /** * \brief Negation operator. * * \return Returns false if the pointer is not empty, true otherwise. */ __cuda_callable__ bool operator!() const { return ! this->pd; } /** * \brief Constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ const Object& getData() const Loading @@ -362,6 +602,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *( this->cuda_pointer ); } /** * \brief Non-constant object reference getter. * * After calling this method, the object owned by the pointer might need * to be synchronized. One should not forget to call * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * before calling CUDA kernel using object from this smart pointer. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ Object& modifyData() Loading @@ -379,8 +631,15 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *( this->cuda_pointer ); } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( const DevicePointer& ptr ) /** * \brief Assignment operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( const DevicePointer& ptr ) // this is needed only to avoid the default compiler-generated operator { this->free(); this->pointer = ptr.pointer; Loading @@ -391,10 +650,19 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // conditional operator for non-const -> const data /** * \brief Assignment operator for compatible object types. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) // conditional operator for non-const -> const data { this->free(); this->pointer = ptr.pointer; Loading @@ -405,8 +673,15 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( DevicePointer&& ptr ) /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( DevicePointer&& ptr ) // this is needed only to avoid the default compiler-generated operator { this->free(); this->pointer = ptr.pointer; Loading @@ -418,10 +693,19 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // conditional operator for non-const -> const data /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) // conditional operator for non-const -> const data { this->free(); this->pointer = ptr.pointer; Loading @@ -433,6 +717,14 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } /** * \brief Cross-device pointer synchronization. * * This method is usually called by the smart pointers register when calling * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * * \return true if the synchronization was successful, false otherwise. */ bool synchronize() { if( ! this->pd ) Loading @@ -456,7 +748,7 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer /** * \brief Swap the owned object with another pointer. * * \param ptr2 the other shared pointer for swapping. * \param ptr2 the other device pointer for swapping. */ void swap( DevicePointer& ptr2 ) { Loading @@ -465,7 +757,9 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer std::swap( this->cuda_pointer, ptr2.cuda_pointer ); } /** * \brief Destructor. */ ~DevicePointer() { this->free(); Loading Loading
src/TNL/Pointers/DevicePointer.h +351 −57 Original line number Diff line number Diff line Loading @@ -20,15 +20,31 @@ #include <TNL/TypeInfo.h> #include <TNL/Cuda/MemoryHelpers.h> #include <cstring> #include <c++/8/bits/c++config.h> // std::memcpy, std::memcmp #include <cstring> // std::memcpy, std::memcmp namespace TNL { namespace Pointers { /*** * The DevicePointer is like SharedPointer, except it takes an existing host /** * \brief The DevicePointer is like SharedPointer, except it takes an existing host * object - there is no call to the ObjectType's constructor nor destructor. * * **NOTE: When using smart pointers to pass objects on GPU, one must call * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * before calling a CUDA kernel working with smart pointers.** * * \tparam Object is a type of object to be owned by the pointer. * \tparam Device is device where the object is to be allocated. The object is * always allocated on the host system as well for easier object manipulation. * * See also \ref UniquePointer and \ref SharedPointer. * * See also \ref DevicePointer< Object, Devices::Host > and \ref DevicePointer< Object, Devices::Cuda >. * * \par Example * \include Pointers/DevicePointerExample.cpp * \par Output * \include DevicePointerExample.out */ template< typename Object, typename Device = typename Object::DeviceType > Loading @@ -37,17 +53,22 @@ class DevicePointer static_assert( ! std::is_same< Device, void >::value, "The device cannot be void. You need to specify the device explicitly in your code." ); }; /**** * Specialization for Devices::Host /** * \brief Specialization of the \ref DevicePointer for the host system. * * \tparam Object is a type of object to be owned by the pointer. */ template< typename Object > class DevicePointer< 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. /** * \typedef Enabler * 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 >; Loading @@ -58,84 +79,161 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer public: typedef Object ObjectType; typedef Devices::Host DeviceType; /** * \typedef ObjectType is the type of object owned by the pointer. */ using ObjectType = Object; /** * \brief Constructor of empty pointer. * \typedef DeviceType is the type of device where the object is to be * mirrored. */ using DeviceType = Devices::Host; /** * \brief Constructor of an empty pointer. */ DevicePointer( std::nullptr_t ) : pointer( nullptr ) {} /** * \brief Constructor with an object reference. * * \param obj reference to an object to be managed by the pointer. */ explicit DevicePointer( ObjectType& obj ) : pointer( nullptr ) { this->pointer = &obj; } // this is needed only to avoid the default compiler-generated constructor DevicePointer( const DevicePointer& pointer ) /** * \brief Copy constructor. * * \param pointer is the source device pointer. */ DevicePointer( const DevicePointer& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ) { } // conditional constructor for non-const -> const data /** * \brief Copy constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ) { } // this is needed only to avoid the default compiler-generated constructor DevicePointer( DevicePointer&& pointer ) /** * \brief Move constructor. * * \param pointer is the source device pointer. */ DevicePointer( DevicePointer&& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ) { pointer.pointer = nullptr; } // conditional constructor for non-const -> const data /** * \brief Move constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ) { pointer.pointer = nullptr; } /** * \brief Arrow operator for accessing the object owned by constant smart pointer. * * \return constant pointer to the object owned by this smart pointer. */ const Object* operator->() const { return this->pointer; } /** * \brief Arrow operator for accessing the object owned by non-constant smart pointer. * * \return pointer to the object owned by this smart pointer. */ Object* operator->() { return this->pointer; } /** * \brief Dereferencing operator for accessing the object owned by constant smart pointer. * * \return constant reference to the object owned by this smart pointer. */ const Object& operator *() const { return *( this->pointer ); } /** * \brief Dereferencing operator for accessing the object owned by non-constant smart pointer. * * \return reference to the object owned by this smart pointer. */ Object& operator *() { return *( this->pointer ); } /** * \brief Conversion to boolean type. * * \return Returns true if the pointer is not empty, false otherwise. */ __cuda_callable__ operator bool() const { return this->pointer; } /** * \brief Negation operator. * * \return Returns false if the pointer is not empty, true otherwise. */ __cuda_callable__ bool operator!() const { return ! this->pointer; } /** * \brief Constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ const Object& getData() const Loading @@ -143,6 +241,16 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer return *( this->pointer ); } /** * \brief Non-constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ Object& modifyData() Loading @@ -150,40 +258,79 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer return *( this->pointer ); } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( const DevicePointer& ptr ) /** * \brief Assignment operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( const DevicePointer& ptr ) // this is needed only to avoid the default compiler-generated operator { this->pointer = ptr.pointer; return *this; } // conditional operator for non-const -> const data /** * \brief Assignment operator for compatible object types. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) // conditional operator for non-const -> const data { this->pointer = ptr.pointer; return *this; } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( DevicePointer&& ptr ) /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( DevicePointer&& ptr ) // this is needed only to avoid the default compiler-generated operator { this->pointer = ptr.pointer; ptr.pointer = nullptr; return *this; } // conditional operator for non-const -> const data /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) // conditional operator for non-const -> const data { this->pointer = ptr.pointer; ptr.pointer = nullptr; return *this; } /** * \brief Cross-device pointer synchronization. * * For the smart pointers on the host, this method does nothing. * * \return true. */ bool synchronize() { return true; Loading @@ -192,14 +339,16 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer /** * \brief Swap the owned object with another pointer. * * \param ptr2 the other shared pointer for swapping. * \param ptr2 the other device pointer for swapping. */ void swap( DevicePointer& ptr2 ) { std::swap( this->pointer, ptr2.pointer ); } /** * \brief Destructor. */ ~DevicePointer() { } Loading @@ -210,17 +359,23 @@ class DevicePointer< Object, Devices::Host > : public SmartPointer Object* pointer; }; /**** * Specialization for CUDA /** * \brief Specialization of the \ref DevicePointer for the CUDA device. * * \tparam Object is a type of object to be owned by the pointer. */ template< typename Object > class DevicePointer< Object, Devices::Cuda > : 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. /** * \typedef Enabler * * 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 >; Loading @@ -231,8 +386,16 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer public: typedef Object ObjectType; typedef Devices::Cuda DeviceType; /** * \typedef ObjectType is the type of object owned by the pointer. */ using ObjectType = Object; /** * \typedef DeviceType is the type of device where the object is to be * mirrored. */ using DeviceType = Devices::Cuda; /** * \brief Constructor of empty pointer. Loading @@ -242,6 +405,11 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pd( nullptr ), cuda_pointer( nullptr ) {} /** * \brief Constructor with an object reference. * * \param obj is a reference on an object to be managed by the pointer. */ explicit DevicePointer( ObjectType& obj ) : pointer( nullptr ), pd( nullptr ), Loading @@ -250,8 +418,12 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->allocate( obj ); } // this is needed only to avoid the default compiler-generated constructor DevicePointer( const DevicePointer& pointer ) /** * \brief Copy constructor. * * \param pointer is the source device pointer. */ DevicePointer( const DevicePointer& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -259,10 +431,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->pd->counter += 1; } // conditional constructor for non-const -> const data /** * \brief Copy constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) DevicePointer( const DevicePointer< Object_, DeviceType >& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -270,8 +450,12 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer this->pd->counter += 1; } // this is needed only to avoid the default compiler-generated constructor DevicePointer( DevicePointer&& pointer ) /** * \brief Move constructor. * * \param pointer is the source device pointer. */ DevicePointer( DevicePointer&& pointer ) // this is needed only to avoid the default compiler-generated constructor : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -281,10 +465,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pointer.cuda_pointer = nullptr; } // conditional constructor for non-const -> const data /** * \brief Move constructor. * * This is specialization for compatible object types. * * See \ref Enabler. * * \param pointer is the source device pointer. */ template< typename Object_, typename = typename Enabler< Object_ >::type > DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) DevicePointer( DevicePointer< Object_, DeviceType >&& pointer ) // conditional constructor for non-const -> const data : pointer( pointer.pointer ), pd( (PointerData*) pointer.pd ), cuda_pointer( pointer.cuda_pointer ) Loading @@ -294,6 +486,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer pointer.cuda_pointer = nullptr; } /** * \brief Arrow operator for accessing the object owned by constant smart pointer. * * \return constant pointer to the object owned by this smart pointer. It * returns pointer to object image on the CUDA device if it is called from CUDA * kernel and pointer to host image otherwise. */ __cuda_callable__ const Object* operator->() const { Loading @@ -304,6 +503,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Arrow operator for accessing the object owned by non-constant smart pointer. * * \return pointer to the object owned by this smart pointer. It * returns pointer to object image on the CUDA device if it is called from CUDA * kernel and pointer to host image otherwise. */ __cuda_callable__ Object* operator->() { Loading @@ -315,6 +521,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Dereferencing operator for accessing the object owned by constant smart pointer. * * \return constant reference to the object owned by this smart pointer. It * returns reference to object image on the CUDA device if it is called from CUDA * kernel and reference to host image otherwise. */ __cuda_callable__ const Object& operator *() const { Loading @@ -325,6 +538,13 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Dereferencing operator for accessing the object owned by non-constant smart pointer. * * \return reference to the object owned by this smart pointer. It * returns reference to object image on the CUDA device if it is called from CUDA * kernel and reference to host image otherwise. */ __cuda_callable__ Object& operator *() { Loading @@ -336,18 +556,38 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer #endif } /** * \brief Conversion to boolean type. * * \return Returns true if the pointer is not empty, false otherwise. */ __cuda_callable__ operator bool() const { return this->pd; } /** * \brief Negation operator. * * \return Returns false if the pointer is not empty, true otherwise. */ __cuda_callable__ bool operator!() const { return ! this->pd; } /** * \brief Constant object reference getter. * * No synchronization of this pointer will be performed due to calling * this method. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ const Object& getData() const Loading @@ -362,6 +602,18 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *( this->cuda_pointer ); } /** * \brief Non-constant object reference getter. * * After calling this method, the object owned by the pointer might need * to be synchronized. One should not forget to call * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * before calling CUDA kernel using object from this smart pointer. * * \tparam Device says what image of the object one want to dereference. It * can be either \ref DeviceType or Devices::Host. * \return constant reference to the object image on given device. */ template< typename Device = Devices::Host > __cuda_callable__ Object& modifyData() Loading @@ -379,8 +631,15 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *( this->cuda_pointer ); } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( const DevicePointer& ptr ) /** * \brief Assignment operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( const DevicePointer& ptr ) // this is needed only to avoid the default compiler-generated operator { this->free(); this->pointer = ptr.pointer; Loading @@ -391,10 +650,19 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // conditional operator for non-const -> const data /** * \brief Assignment operator for compatible object types. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) const DevicePointer& operator=( const DevicePointer< Object_, DeviceType >& ptr ) // conditional operator for non-const -> const data { this->free(); this->pointer = ptr.pointer; Loading @@ -405,8 +673,15 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // this is needed only to avoid the default compiler-generated operator const DevicePointer& operator=( DevicePointer&& ptr ) /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * \param ptr input pointer * \return constant reference to \ref this */ const DevicePointer& operator=( DevicePointer&& ptr ) // this is needed only to avoid the default compiler-generated operator { this->free(); this->pointer = ptr.pointer; Loading @@ -418,10 +693,19 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } // conditional operator for non-const -> const data /** * \brief Move operator. * * It assigns object owned by the pointer \ref ptr to \ref this pointer. * * See \ref Enabler. * * \param ptr input pointer * \return constant reference to \ref this */ template< typename Object_, typename = typename Enabler< Object_ >::type > const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) const DevicePointer& operator=( DevicePointer< Object_, DeviceType >&& ptr ) // conditional operator for non-const -> const data { this->free(); this->pointer = ptr.pointer; Loading @@ -433,6 +717,14 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer return *this; } /** * \brief Cross-device pointer synchronization. * * This method is usually called by the smart pointers register when calling * \ref Pointers::synchronizeSmartPointersOnDevice< Devices::Cuda >() * * \return true if the synchronization was successful, false otherwise. */ bool synchronize() { if( ! this->pd ) Loading @@ -456,7 +748,7 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer /** * \brief Swap the owned object with another pointer. * * \param ptr2 the other shared pointer for swapping. * \param ptr2 the other device pointer for swapping. */ void swap( DevicePointer& ptr2 ) { Loading @@ -465,7 +757,9 @@ class DevicePointer< Object, Devices::Cuda > : public SmartPointer std::swap( this->cuda_pointer, ptr2.cuda_pointer ); } /** * \brief Destructor. */ ~DevicePointer() { this->free(); Loading