Extended CUDA Library (ecuda)  2.0
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
shared_ptr.hpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2014-2016, Scott Zuyderduyn
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 
8 1. Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation
12  and/or other materials provided with the distribution.
13 
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 
25 The views and conclusions contained in the software and documentation are those
26 of the authors and should not be interpreted as representing official policies,
27 either expressed or implied, of the FreeBSD Project.
28 */
29 
30 //----------------------------------------------------------------------------
31 // ptr/shared_ptr.hpp
32 //
33 // A managed, reference-counted pointer to device memory.
34 //
35 // Author: Scott D. Zuyderduyn, Ph.D. (scott.zuyderduyn@utoronto.ca)
36 //----------------------------------------------------------------------------
37 
38 #ifndef ECUDA_PTR_SHARED_PTR_HPP
39 #define ECUDA_PTR_SHARED_PTR_HPP
40 
41 #include <iostream>
42 
43 #include "../global.hpp"
44 #include "common.hpp"
45 #include "../algorithm.hpp"
46 
47 //
48 // Implementation is the approach used by boost::shared_ptr.
49 //
50 // \todo STL contains means to use a custom allocator to allocate memory for the internal counter
51 // but this hasn't been done here (things are overengineered enough atm!) - if a programmer
52 // were to take the approach of allocating a lot of individual shared_ptr managing many
53 // different objects, there is a potential performance benefit from allowing a task-optimized
54 // custom allocator
55 //
56 
57 namespace ecuda {
58 
60 namespace detail {
61 
62 struct sp_counter_base
63 {
64  std::size_t owner_count;
65  sp_counter_base() : owner_count(1) {}
66  virtual ~sp_counter_base() {}
67  virtual void dispose( void* ) = 0;
68  virtual void* get_deleter() { return 0; }
69 };
70 
71 template<typename T>
72 struct sp_counter_impl_p : sp_counter_base
73 {
74  sp_counter_impl_p() : sp_counter_base() {}
75  virtual void dispose( void* p ) { if( p ) ecuda::default_device_delete<void>()(p); } // cudaFree( p );
76 };
77 
78 template<typename T,class Deleter>
79 struct sp_counter_impl_pd : sp_counter_base
80 {
81  Deleter deleter;
82  sp_counter_impl_pd( Deleter deleter ) : sp_counter_base(), deleter(deleter) {}
83  virtual void dispose( void* p ) { if( p ) deleter(p); }
84  //virtual void* get_deleter() { return deleter; }
85  virtual void* get_deleter() { return reinterpret_cast<void*>(&deleter); }
86 };
87 
88 } // namespace detail
90 
121 template<typename T>
123 {
124 
125 public:
126  typedef T element_type;
127 
128 private:
129  void* current_ptr;
130  detail::sp_counter_base* counter;
131 
132  template<typename U> friend class shared_ptr;
133 
134 public:
135 
139  __HOST__ __DEVICE__ __CONSTEXPR__ shared_ptr() __NOEXCEPT__ : current_ptr(NULL), counter(NULL) {}
140 
149  template<typename U>
150  __HOST__ __DEVICE__ explicit shared_ptr( U* ptr ) : current_ptr(detail::void_cast<T*>()(ptr)), counter(NULL)
151  {
152  #ifndef __CUDA_ARCH__
153  if( ptr ) counter = new detail::sp_counter_impl_p<T>();
154  #endif
155  }
156 
166  template<typename U,class Deleter>
167  __HOST__ __DEVICE__ shared_ptr( U* ptr, Deleter deleter ) : current_ptr(detail::void_cast<T*>()(ptr)), counter(NULL)
168  {
169  #ifndef __CUDA_ARCH__
170  if( ptr ) counter = new detail::sp_counter_impl_pd<T,Deleter>( deleter );
171  #endif
172  }
173 
189  template<typename U>
190  __HOST__ __DEVICE__ shared_ptr( const shared_ptr<U>& src, T* ptr ) __NOEXCEPT__ : current_ptr(ptr), counter(src.counter)
191  {
192  #ifndef __CUDA_ARCH__
193  ++(counter->owner_count);
194  #endif
195  }
196 
205  __HOST__ __DEVICE__ shared_ptr( const shared_ptr& src ) __NOEXCEPT__ : current_ptr(src.current_ptr), counter(src.counter)
206  {
207  #ifndef __CUDA_ARCH__
208  if( counter ) ++(counter->owner_count);
209  #endif
210  }
211 
222  template<typename U>
223  __HOST__ __DEVICE__ shared_ptr( const shared_ptr<U>& src ) __NOEXCEPT__ : current_ptr(src.current_ptr), counter(src.counter)
224  {
225  #ifndef __CUDA_ARCH__
226  if( counter ) ++(counter->owner_count);
227  #endif
228  }
229 
230  #ifdef ECUDA_CPP11_AVAILABLE
231  __HOST__ __DEVICE__ shared_ptr( shared_ptr&& src ) __NOEXCEPT__ : current_ptr(std::move(src.current_ptr)), counter(std::move(src.counter))
240  {
241  //src.current_ptr = NULL;
242  //src.counter = NULL;
243  }
244 
254  template<typename U>
255  __HOST__ __DEVICE__ shared_ptr( shared_ptr<U>&& src ) __NOEXCEPT__ : current_ptr(std::move(src.current_ptr)), counter(std::move(src.counter))
256  {
257  //src.current_ptr = NULL;
258  //src.counter = NULL;
259  }
260 
270  template<typename U,class Deleter>
271  __HOST__ __DEVICE__ shared_ptr( ecuda::unique_ptr<U,Deleter>&& src ) : current_ptr(detail::void_cast<T*>()(src.release()))
272  {
273  counter = current_ptr ? new detail::sp_counter_impl_pd<T,Deleter>( src.get_deleter() ) : NULL;
274  }
275  #endif
276 
286  {
287  #ifndef __CUDA_ARCH__
288  if( counter ) {
289  --(counter->owner_count);
290  if( counter->owner_count == 0 ) {
291  counter->dispose( current_ptr );
292  delete counter;
293  counter = NULL;
294  }
295  }
296  #endif
297  }
298 
307  __HOST__ __DEVICE__ inline shared_ptr& operator=( const shared_ptr& src ) __NOEXCEPT__
308  {
309  shared_ptr(src).swap(*this);
310  return *this;
311  }
312 
322  template<typename U> __HOST__ __DEVICE__ inline shared_ptr& operator=( const shared_ptr<U>& src ) __NOEXCEPT__ { shared_ptr(src).swap(*this); return *this; }
323 
324  #ifdef ECUDA_CPP11_AVAILABLE
325  __HOST__ __DEVICE__ inline shared_ptr& operator=( shared_ptr&& src ) __NOEXCEPT__ { shared_ptr(move(src)).swap(*this); return *this; }
334 
344  template<typename U> __HOST__ __DEVICE__ inline shared_ptr& operator=( shared_ptr<U>&& src ) __NOEXCEPT__ { shared_ptr(move(src)).swap(*this); return *this; }
345 
355  template<typename U,class Deleter> __HOST__ __DEVICE__ inline shared_ptr& operator=( unique_ptr<U,Deleter>&& src ) __NOEXCEPT__ { shared_ptr(move(src)).swap(*this); return *this; }
356  #endif
357 
363  __HOST__ __DEVICE__ inline void reset() __NOEXCEPT__ { shared_ptr().swap( *this ); }
364 
374  template<typename U> __HOST__ __DEVICE__ inline void reset( U* ptr ) { shared_ptr( ptr ).swap( *this ); }
375 
386  template<typename U,class Deleter> __HOST__ __DEVICE__ inline void reset( U* ptr, Deleter d ) { shared_ptr( ptr, d ).swap( *this ); }
387 
393  __HOST__ __DEVICE__ inline void swap( shared_ptr& other ) __NOEXCEPT__
394  {
395  ::ecuda::swap( current_ptr, other.current_ptr );
396  ::ecuda::swap( counter, other.counter );
397  }
398 
406  __HOST__ __DEVICE__ inline T* get() const __NOEXCEPT__ { return reinterpret_cast<T*>(current_ptr); }
407 
416  __DEVICE__ inline typename ecuda::add_lvalue_reference<T>::type operator*() const __NOEXCEPT__ { return *reinterpret_cast<T*>(current_ptr); }
417 
423  __HOST__ __DEVICE__ inline T* operator->() const __NOEXCEPT__ { return reinterpret_cast<T*>(current_ptr); }
424 
433  __HOST__ __DEVICE__ inline std::size_t use_count() const __NOEXCEPT__ { return counter ? counter->owner_count : 0; }
434 
442  __HOST__ __DEVICE__ inline bool unique() const __NOEXCEPT__ { return use_count() == 1; }
443 
444  #ifdef ECUDA_CPP11_AVAILABLE
445  __HOST__ __DEVICE__ explicit operator bool() const __NOEXCEPT__ { return get() != NULL; }
451  #else
452  __HOST__ __DEVICE__ operator bool() const __NOEXCEPT__ { return get() != NULL; }
458  #endif
459 
472  template<typename U>
473  __HOST__ __DEVICE__ inline bool owner_before( const shared_ptr<U>& other ) const { return counter < other.counter; }
474 
475  template<typename T2> __HOST__ __DEVICE__ bool operator==( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() == other.get(); }
476  template<typename T2> __HOST__ __DEVICE__ bool operator!=( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() != other.get(); }
477  template<typename T2> __HOST__ __DEVICE__ bool operator< ( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() < other.get(); }
478  template<typename T2> __HOST__ __DEVICE__ bool operator> ( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() > other.get(); }
479  template<typename T2> __HOST__ __DEVICE__ bool operator<=( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() <= other.get(); }
480  template<typename T2> __HOST__ __DEVICE__ bool operator>=( const shared_ptr<T2>& other ) const __NOEXCEPT__ { return get() >= other.get(); }
481 
491  template<typename U,typename V>
492  friend std::basic_ostream<U,V>& operator<<( std::basic_ostream<U,V>& out, const shared_ptr& ptr )
493  {
494  out << ptr.get();
495  return out;
496  }
497 
498 };
499 
500 } // namespace ecuda
501 
502 #endif
A smart pointer that retains shared ownership of an object in device memory.
Definition: shared_ptr.hpp:122
__HOST__ __DEVICE__ bool unique() const __NOEXCEPT__
Checks if this is the only shared_ptr instance managing the current object.
Definition: shared_ptr.hpp:442
__HOST__ __DEVICE__ T * operator->() const __NOEXCEPT__
Dereferences pointer to the managed object.
Definition: shared_ptr.hpp:423
The default destruction policy used by smart pointers to device memory.
Definition: common.hpp:64
__HOST__ __DEVICE__ shared_ptr(const shared_ptr< U > &src, T *ptr) __NOEXCEPT__
The aliasing constructor.
Definition: shared_ptr.hpp:190
__HOST__ __DEVICE__ ~shared_ptr()
Destructor.
Definition: shared_ptr.hpp:285
__HOST__ __DEVICE__ void reset(U *ptr, Deleter d)
Replaces the managed object with another.
Definition: shared_ptr.hpp:386
#define __CONSTEXPR__
Definition: global.hpp:141
A smart pointer that retains sole ownership of an object.
Definition: unique_ptr.hpp:84
__DEVICE__ ecuda::add_lvalue_reference< T >::type operator*() const __NOEXCEPT__
Dereferences pointer to the managed object.
Definition: shared_ptr.hpp:416
__HOST__ __DEVICE__ bool owner_before(const shared_ptr< U > &other) const
Definition: shared_ptr.hpp:473
__HOST__ __DEVICE__ shared_ptr & operator=(const shared_ptr &src) __NOEXCEPT__
Replaces the managed object.
Definition: shared_ptr.hpp:307
__HOST__ __DEVICE__ bool operator>=(const shared_ptr< T2 > &other) const __NOEXCEPT__
Definition: shared_ptr.hpp:480
#define __NOEXCEPT__
Definition: global.hpp:140
#define __HOST__
Definition: global.hpp:150
__HOST__ __DEVICE__ bool operator==(const shared_ptr< T2 > &other) const __NOEXCEPT__
Definition: shared_ptr.hpp:475
__HOST__ __DEVICE__ void swap(T &a, T &b) __NOEXCEPT__
Definition: algorithm.hpp:54
__HOST__ __DEVICE__ bool operator!=(const shared_ptr< T2 > &other) const __NOEXCEPT__
Definition: shared_ptr.hpp:476
__HOST__ __DEVICE__ void reset() __NOEXCEPT__
Releases ownership of the managed object.
Definition: shared_ptr.hpp:363
__HOST__ __DEVICE__ shared_ptr(U *ptr)
Constructs a shared_ptr with a pointer to the managed object.
Definition: shared_ptr.hpp:150
__HOST__ __DEVICE__ shared_ptr & operator=(const shared_ptr< U > &src) __NOEXCEPT__
Replaces the managed object.
Definition: shared_ptr.hpp:322
T element_type
type of the managed object
Definition: shared_ptr.hpp:126
__HOST__ __DEVICE__ std::size_t use_count() const __NOEXCEPT__
Returns the number of smart pointers managing the current object.
Definition: shared_ptr.hpp:433
__HOST__ __DEVICE__ void swap(shared_ptr &other) __NOEXCEPT__
Exchanges the contents of *this and other.
Definition: shared_ptr.hpp:393
__HOST__ __DEVICE__ bool operator>(const shared_ptr< T2 > &other) const __NOEXCEPT__
Definition: shared_ptr.hpp:478
#define __DEVICE__
Definition: global.hpp:151
__HOST__ __DEVICE__ shared_ptr(const shared_ptr &src) __NOEXCEPT__
Copy constructor.
Definition: shared_ptr.hpp:205
__HOST__ __DEVICE__ shared_ptr(U *ptr, Deleter deleter)
Constructs a shared_ptr with a pointer to the managed object.
Definition: shared_ptr.hpp:167
__HOST__ __DEVICE__ shared_ptr(const shared_ptr< U > &src) __NOEXCEPT__
Copy constructor.
Definition: shared_ptr.hpp:223
__HOST__ __DEVICE__ __CONSTEXPR__ shared_ptr() __NOEXCEPT__
Default constructor constructs a shared_ptr with no managed object.
Definition: shared_ptr.hpp:139
__HOST__ __DEVICE__ void reset(U *ptr)
Replaces the managed object with another.
Definition: shared_ptr.hpp:374