lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
resource_ptr.h
00001 /*****************************************************/
00002 /* lean Smart                   (c) Tobias Zirr 2011 */
00003 /*****************************************************/
00004 
00005 #ifndef LEAN_SMART_RESOURCE_PTR
00006 #define LEAN_SMART_RESOURCE_PTR
00007 
00008 #include "../cpp0x.h"
00009 #include "../functional/variadic.h"
00010 
00011 namespace lean
00012 {
00013 namespace smart
00014 {
00015 
00016 // Prototypes
00017 template <class Counter, class Allocator>
00018 class ref_counter;
00019 
00021 template <class Resource>
00022 LEAN_INLINE void destroy_resource(Resource *resource)
00023 {
00024     delete resource;
00025 }
00026 
00028 template <class Resource, bool Critical = false>
00029 class resource_ptr
00030 {
00031     template <class Resource>
00032     friend class weak_resource_ptr;
00033 
00034 private:
00035     Resource *m_resource;
00036 
00038     template <class Counter, class Allocator>
00039     static Resource* acquire(Resource *resource, const ref_counter<Counter, Allocator>& refCounter)
00040     {
00041         return (resource && refCounter.increment_checked())
00042             ? resource
00043             : nullptr;
00044     }
00045 
00047     static Resource* acquire(Resource *resource)
00048     {
00049         if (resource)
00050             resource->ref_counter().increment();
00051 
00052         return resource;
00053     }
00054 
00056     static void release(Resource *resource)
00057     {
00058         // Clean up, if this is the last reference
00059         if (resource && !resource->ref_counter().decrement())
00060             destroy_resource(resource);
00061     }
00062 
00063 protected:
00065     template <class Counter, class Allocator>
00066     resource_ptr(Resource *resource, const ref_counter<Counter, Allocator>& refCounter)
00067         : m_resource( acquire(resource, refCounter) ) { };
00068 
00069 public:
00071     typedef Resource resource_type;
00073     typedef Resource* value_type;
00074 
00076     resource_ptr(resource_type *resource = nullptr)
00077         : m_resource( acquire(resource) ) { };
00079     template <class Resource2>
00080     resource_ptr(Resource2 *resource)
00081         : m_resource( acquire(resource) ) { };
00082 
00084     enum bind_reference_t
00085     {
00086         bind_reference 
00087     };
00089     resource_ptr(Resource *resource, bind_reference_t)
00090         : m_resource(resource) { };
00091 
00093     resource_ptr(const resource_ptr &right)
00094         : m_resource( acquire(right.m_resource) ) { };
00096     template <class Resource2, bool Critical2>
00097     resource_ptr(const resource_ptr<Resource2, Critical2> &right)
00098         : m_resource( acquire(right.get()) ) { };
00099 
00100 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00101 
00102     template <class Resource2, bool Critical2>
00103     resource_ptr(resource_ptr<Resource2, Critical2> &&right)
00104         : m_resource(right.unbind()) { }
00105 #endif
00106 
00108     ~resource_ptr() throw()
00109     {
00110         release(m_resource);
00111     }
00112 
00114     static LEAN_INLINE resource_ptr<resource_type, true> bind(resource_type *resource)
00115     {
00116         return resource_ptr<resource_type, true>(resource, resource_ptr<resource_type, true>::bind_reference);
00117     }
00119     resource_type* unbind()
00120     {
00121         Resource *prevResource = m_resource;
00122         m_resource = nullptr;
00123         return prevResource;
00124     }
00126     resource_ptr<resource_type, true> transfer()
00127     {
00128         // Visual C++ won't inline delegating function calls
00129         return resource_ptr<resource_type, true>(unbind(), resource_ptr<resource_type, true>::bind_reference);
00130     }
00131 
00133     resource_ptr& operator =(resource_type *resource)
00134     {
00135         if (m_resource != resource)
00136         {
00137             Resource *prevResource = m_resource;
00138             m_resource = acquire(resource);
00139             release(prevResource);
00140         }
00141 
00142         return *this;
00143     }
00144 
00146     resource_ptr& operator =(const resource_ptr &right)
00147     {
00148         return (*this = right.m_resource);
00149     }
00151     template <class Resource2, bool Critical2>
00152     resource_ptr& operator =(const resource_ptr<Resource2, Critical2> &right)
00153     {
00154         return (*this = right.get());
00155     }
00156 
00157 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00158 
00159     template <class Resource2, bool Critical2>
00160     resource_ptr& operator =(resource_ptr<Resource2, Critical2> &&right)
00161     {
00162         // Self-assignment would be wrong
00163         if (addressof(right) != static_cast<void*>(this))
00164         {
00165             Resource *prevResource = m_resource;
00166             m_resource = right.unbind();
00167             release(prevResource);
00168         }
00169 
00170         return *this;
00171     }
00172 #endif
00173 
00175     LEAN_INLINE resource_type *const & get(void) const { return m_resource; };
00176 
00178     LEAN_INLINE resource_type& operator *() const { return *get(); };
00180     LEAN_INLINE resource_type* operator ->() const { return get(); };
00181 
00183     LEAN_INLINE operator resource_type*() const
00184     {
00185         LEAN_STATIC_ASSERT_MSG_ALT(!Critical,
00186             "Cannot implicitly cast critical reference, use unbind() for (insecure) storage.",
00187             Cannot_implicitly_cast_critical_reference__use_unbind_for_insecure_storage);
00188         return get();
00189     }
00190 };
00191 
00193 template <class Resource>
00194 LEAN_INLINE resource_ptr<Resource, true> bind_resource(Resource *resource)
00195 {
00196     // Visual C++ won't inline delegating function calls
00197     return resource_ptr<Resource, true>(resource, resource_ptr<Resource, true>::bind_reference);
00198 }
00199 
00201 template <class Resource>
00202 LEAN_INLINE resource_ptr<Resource, true> secure_resource(Resource *resource)
00203 {
00204     // Visual C++ won't inline delegating function calls
00205     return resource_ptr<Resource, true>(resource);
00206 }
00207 
00208 #ifdef DOXYGEN_READ_THIS
00209 
00210     template <class Resource>
00211     resource_ptr<Resource, true> new_resource(...);
00212 #else
00213     #define LEAN_NEW_RESOURCE_FUNCTION_TPARAMS class Resource
00214     #define LEAN_NEW_RESOURCE_FUNCTION_DECL inline resource_ptr<Resource, true> new_resource
00215     #define LEAN_NEW_RESOURCE_FUNCTION_BODY(call) { return resource_ptr<Resource, true>( new Resource##call, resource_ptr<Resource, true>::bind_reference ); }
00216     LEAN_VARIADIC_PERFECT_FORWARDING_T(LEAN_NEW_RESOURCE_FUNCTION_DECL, LEAN_NEW_RESOURCE_FUNCTION_TPARAMS, LEAN_NOTHING, LEAN_NEW_RESOURCE_FUNCTION_BODY)
00217 #endif
00218 
00219 } // namespace
00220 
00221 using smart::resource_ptr;
00222 using smart::bind_resource;
00223 using smart::secure_resource;
00224 using smart::new_resource;
00225 
00226 } // namespace
00227 
00228 #endif