lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
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