| OLD | NEW |
| (Empty) |
| 1 //+--------------------------------------------------------------------------- | |
| 2 // | |
| 3 // Copyright ( C ) Microsoft, 2002. | |
| 4 // | |
| 5 // File: shared_any.h | |
| 6 // | |
| 7 // Contents: automatic resource management | |
| 8 // | |
| 9 // Classes: shared_any<> and various typedefs | |
| 10 // | |
| 11 // Functions: get | |
| 12 // reset | |
| 13 // valid | |
| 14 // | |
| 15 // Author: Eric Niebler ( ericne@microsoft.com ) | |
| 16 // | |
| 17 //---------------------------------------------------------------------------- | |
| 18 | |
| 19 | |
| 20 #ifndef SHARED_ANY | |
| 21 #define SHARED_ANY | |
| 22 | |
| 23 #include <cassert> | |
| 24 #include <functional> // for std::less | |
| 25 #include <algorithm> // for std::swap | |
| 26 #include "smart_any_fwd.h" | |
| 27 | |
| 28 namespace detail | |
| 29 { | |
| 30 class ref_count_allocator | |
| 31 { | |
| 32 struct node; | |
| 33 node *m_list_blocks; | |
| 34 node *m_last_alloc; | |
| 35 node *m_last_free; | |
| 36 | |
| 37 ref_count_allocator(); | |
| 38 ~ref_count_allocator(); | |
| 39 public: | |
| 40 void finalize(); | |
| 41 long volatile *alloc(); | |
| 42 long volatile *alloc( long val ); | |
| 43 void free( long volatile *refcount ); | |
| 44 | |
| 45 static ref_count_allocator instance; | |
| 46 }; | |
| 47 | |
| 48 template<typename T,class close_policy,class invalid_value,int unique> | |
| 49 struct shared_any_helper; | |
| 50 | |
| 51 template<typename Super> | |
| 52 struct shared_holder : Super | |
| 53 { | |
| 54 explicit shared_holder( typename Super::type t ) | |
| 55 : Super( t ) | |
| 56 { | |
| 57 } | |
| 58 | |
| 59 shared_holder( shared_holder const & that ) | |
| 60 : Super( that ) | |
| 61 { | |
| 62 if( Super::valid() ) | |
| 63 { | |
| 64 Super::inc_ref(); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 ~shared_holder() | |
| 69 { | |
| 70 if( Super::valid() ) | |
| 71 { | |
| 72 Super::dec_ref(); | |
| 73 } | |
| 74 } | |
| 75 }; | |
| 76 | |
| 77 template<typename T,class invalid_value_type> | |
| 78 struct intrusive | |
| 79 { | |
| 80 typedef T type; | |
| 81 | |
| 82 explicit intrusive( T t ) | |
| 83 : m_t( t ) | |
| 84 { | |
| 85 } | |
| 86 | |
| 87 bool valid() const | |
| 88 { | |
| 89 return m_t != static_cast<T>( invalid_value_type() ); | |
| 90 } | |
| 91 | |
| 92 void inc_ref() | |
| 93 { | |
| 94 m_t->AddRef(); | |
| 95 } | |
| 96 | |
| 97 void dec_ref() | |
| 98 { | |
| 99 if( 0 == m_t->Release() ) | |
| 100 { | |
| 101 m_t = static_cast<T>( invalid_value_type() ); | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 T m_t; | |
| 106 }; | |
| 107 | |
| 108 template<typename T,class close_policy,class invalid_value_type> | |
| 109 struct nonintrusive | |
| 110 { | |
| 111 typedef T type; | |
| 112 | |
| 113 explicit nonintrusive( T t ) | |
| 114 : m_t( t ), | |
| 115 m_ref( 0 ) | |
| 116 { | |
| 117 if( valid() ) | |
| 118 { | |
| 119 m_ref = ref_count_allocator::instance.alloc(1L); | |
| 120 if( ! m_ref ) | |
| 121 { | |
| 122 m_t = static_cast<T>( invalid_value_type() ); | |
| 123 throw std::bad_alloc(); | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 bool valid() const | |
| 129 { | |
| 130 return m_t != static_cast<T>( invalid_value_type() ); | |
| 131 } | |
| 132 | |
| 133 void inc_ref() | |
| 134 { | |
| 135 ::InterlockedIncrement( m_ref ); | |
| 136 } | |
| 137 | |
| 138 void dec_ref() | |
| 139 { | |
| 140 if( 0L == ::InterlockedDecrement( m_ref ) ) | |
| 141 { | |
| 142 ref_count_allocator::instance.free( m_ref ); | |
| 143 m_ref = 0; | |
| 144 close_policy::close( m_t ); | |
| 145 m_t = static_cast<T>( invalid_value_type() ); | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 typename holder<T>::type m_t; | |
| 150 long volatile *m_ref; | |
| 151 }; | |
| 152 | |
| 153 template<class close_policy> | |
| 154 struct is_close_release_com | |
| 155 { | |
| 156 static bool const value = false; | |
| 157 }; | |
| 158 template<> | |
| 159 struct is_close_release_com<close_release_com> | |
| 160 { | |
| 161 static bool const value = true; | |
| 162 }; | |
| 163 | |
| 164 // credit Rani Sharoni for showing me how to implement | |
| 165 // is_com_ptr on VC7. This is deeply magical code. | |
| 166 template<typename T> | |
| 167 struct is_com_ptr | |
| 168 { | |
| 169 private: | |
| 170 struct maybe | |
| 171 { | |
| 172 operator IUnknown*() const; | |
| 173 operator T(); | |
| 174 }; | |
| 175 | |
| 176 template<typename U> | |
| 177 static yes check(T, U); | |
| 178 static no check(IUnknown*, int); | |
| 179 static maybe get(); | |
| 180 public: | |
| 181 static bool const value = sizeof(check(get(),0)) == sizeof(yes); | |
| 182 }; | |
| 183 | |
| 184 template<> | |
| 185 struct is_com_ptr<IUnknown*> | |
| 186 { | |
| 187 static bool const value = true; | |
| 188 }; | |
| 189 } | |
| 190 | |
| 191 template<typename T,class close_policy,class invalid_value,int unique> | |
| 192 class shared_any | |
| 193 { | |
| 194 typedef detail::safe_types<T,close_policy> safe_types; | |
| 195 | |
| 196 // disallow comparison of shared_any's | |
| 197 bool operator==( detail::safe_bool ) const; | |
| 198 bool operator!=( detail::safe_bool ) const; | |
| 199 | |
| 200 public: | |
| 201 typedef typename detail::holder<T>::type element_type; | |
| 202 typedef close_policy close_policy_type; | |
| 203 typedef typename safe_types::pointer_type pointer_type; | |
| 204 typedef typename safe_types::reference_type reference_type; | |
| 205 | |
| 206 // Fix-up the invalid_value type on older compilers | |
| 207 typedef typename detail::fixup_invalid_value<invalid_value>:: | |
| 208 template rebind<T>::type invalid_value_type; | |
| 209 | |
| 210 friend struct detail::shared_any_helper<T,close_policy,invalid_value,unique>
; | |
| 211 | |
| 212 // default construct | |
| 213 shared_any() | |
| 214 : m_held( static_cast<T>( invalid_value_type() ) ) | |
| 215 { | |
| 216 } | |
| 217 | |
| 218 // construct from object. If we fail to allocate a reference count, | |
| 219 // then the T object is closed, and a bad_alloc exception is thrown. | |
| 220 explicit shared_any( T t ) | |
| 221 try : m_held( t ) | |
| 222 { | |
| 223 } | |
| 224 catch( std::bad_alloc & ) | |
| 225 { | |
| 226 close_policy::close( t ); | |
| 227 throw; | |
| 228 } | |
| 229 | |
| 230 // construct from another shared_any, incrementing ref count. | |
| 231 // Only throws if T's copy-c'tor throws, in which case, ref-count | |
| 232 // is unchanged. | |
| 233 shared_any( shared_any<T,close_policy,invalid_value,unique> const & right ) | |
| 234 : m_held( right.m_held ) | |
| 235 { | |
| 236 } | |
| 237 | |
| 238 // construct from an auto_any, taking ownership. If allocation | |
| 239 // fails, auto_any retains ownership. | |
| 240 shared_any( auto_any<T,close_policy,invalid_value,unique> & right ) | |
| 241 : m_held( get( right ) ) | |
| 242 { | |
| 243 release( right ); | |
| 244 } | |
| 245 | |
| 246 // assign from another shared_any | |
| 247 shared_any<T,close_policy,invalid_value,unique> & operator=( | |
| 248 shared_any<T,close_policy,invalid_value,unique> const & right ) | |
| 249 { | |
| 250 shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this ); | |
| 251 return *this; | |
| 252 } | |
| 253 | |
| 254 // assign from an auto_any | |
| 255 shared_any<T,close_policy,invalid_value,unique> & operator=( | |
| 256 auto_any<T,close_policy,invalid_value,unique> & right ) | |
| 257 { | |
| 258 shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this ); | |
| 259 return *this; | |
| 260 } | |
| 261 | |
| 262 operator detail::safe_bool() const | |
| 263 { | |
| 264 return m_held.valid() ? detail::safe_true : detail::safe_false; | |
| 265 } | |
| 266 | |
| 267 bool operator!() const | |
| 268 { | |
| 269 return ! m_held.valid(); | |
| 270 } | |
| 271 | |
| 272 // return pointer to class object (assume pointer) | |
| 273 pointer_type operator->() const | |
| 274 { | |
| 275 #ifdef SMART_ANY_PTS | |
| 276 // You better not be applying operator-> to a handle! | |
| 277 static detail::static_assert<!detail::is_handle<T>::value> const cannot_
dereference_a_handle; | |
| 278 #endif | |
| 279 assert( m_held.valid() ); | |
| 280 return safe_types::to_pointer( m_held.m_t ); | |
| 281 } | |
| 282 | |
| 283 #ifdef SMART_ANY_PTS | |
| 284 // if this shared_any is managing an array, we can use operator[] to index i
t | |
| 285 typename detail::deref<T>::type operator[]( int i ) const | |
| 286 { | |
| 287 static detail::static_assert<!detail::is_handle<T>::value> const cannot_
dereference_a_handle; | |
| 288 static detail::static_assert<!detail::is_delete<close_policy>::value> co
nst accessed_like_an_array_but_not_deleted_like_an_array; | |
| 289 assert( m_held.valid() ); | |
| 290 return m_held.m_t[ i ]; | |
| 291 } | |
| 292 | |
| 293 // unary operator* lets you write code like: | |
| 294 // shared_any<foo*,close_delete> pfoo( new foo ); | |
| 295 // foo & f = *pfoo; | |
| 296 reference_type operator*() const | |
| 297 { | |
| 298 static detail::static_assert<!detail::is_handle<T>::value> const cannot_
dereference_a_handle; | |
| 299 assert( m_held.valid() ); | |
| 300 return safe_types::to_reference( m_held.m_t ); | |
| 301 } | |
| 302 #endif | |
| 303 | |
| 304 private: | |
| 305 | |
| 306 void swap( shared_any<T,close_policy,invalid_value,unique> & right ) | |
| 307 { | |
| 308 using std::swap; | |
| 309 swap( m_held, right.m_held ); | |
| 310 } | |
| 311 | |
| 312 // if we are wrapping a COM object, then use COM's reference counting. | |
| 313 // otherwise, use our own reference counting. | |
| 314 typedef typename detail::select< | |
| 315 detail::is_com_ptr<T>::value && detail::is_close_release_com<close_polic
y>::value, | |
| 316 detail::intrusive<T,invalid_value_type>, | |
| 317 detail::nonintrusive<T,close_policy,invalid_value_type> >::type holder_p
olicy; | |
| 318 | |
| 319 detail::shared_holder<holder_policy> m_held; | |
| 320 }; | |
| 321 | |
| 322 namespace detail | |
| 323 { | |
| 324 template<typename T,class close_policy,class invalid_value,int unique> | |
| 325 struct shared_any_helper | |
| 326 { | |
| 327 static T get( shared_any<T,close_policy,invalid_value,unique> const & t
) | |
| 328 { | |
| 329 return t.m_held.m_t; | |
| 330 } | |
| 331 | |
| 332 static void reset( shared_any<T,close_policy,invalid_value,unique> & t,
T newT ) | |
| 333 { | |
| 334 shared_any<T,close_policy,invalid_value,unique>( newT ).swap( t ); | |
| 335 } | |
| 336 | |
| 337 static void swap( shared_any<T,close_policy,invalid_value,unique> & left
, | |
| 338 shared_any<T,close_policy,invalid_value,unique> & righ
t ) | |
| 339 { | |
| 340 left.swap( right ); | |
| 341 } | |
| 342 }; | |
| 343 } | |
| 344 | |
| 345 // return wrapped resource | |
| 346 template<typename T,class close_policy,class invalid_value,int unique> | |
| 347 inline T get( shared_any<T,close_policy,invalid_value,unique> const & t ) | |
| 348 { | |
| 349 return detail::shared_any_helper<T,close_policy,invalid_value,unique>::get(
t ); | |
| 350 } | |
| 351 | |
| 352 // return true if the shared_any contains a currently valid resource | |
| 353 template<typename T,class close_policy,class invalid_value,int unique> | |
| 354 inline bool valid( shared_any<T,close_policy,invalid_value,unique> const & t ) | |
| 355 { | |
| 356 return t; | |
| 357 } | |
| 358 | |
| 359 // destroy designated object | |
| 360 template<typename T,class close_policy,class invalid_value,int unique> | |
| 361 inline void reset( shared_any<T,close_policy,invalid_value,unique> & t ) | |
| 362 { | |
| 363 typedef typename detail::fixup_invalid_value<invalid_value>:: | |
| 364 template rebind<T>::type invalid_value_type; | |
| 365 detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, in
valid_value_type() ); | |
| 366 } | |
| 367 | |
| 368 // destroy designated object and store new resource | |
| 369 template<typename T,class close_policy,class invalid_value,int unique,typename U
> | |
| 370 inline void reset( shared_any<T,close_policy,invalid_value,unique> & t, U newT ) | |
| 371 { | |
| 372 detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, ne
wT ); | |
| 373 } | |
| 374 | |
| 375 // swap the contents of two shared_any objects | |
| 376 template<typename T,class close_policy,class invalid_value,int unique> | |
| 377 inline void swap( shared_any<T,close_policy,invalid_value,unique> & left, | |
| 378 shared_any<T,close_policy,invalid_value,unique> & right ) | |
| 379 { | |
| 380 detail::shared_any_helper<T,close_policy,invalid_value,unique>::swap( left,
right ); | |
| 381 } | |
| 382 | |
| 383 // Define some relational operators on shared_* types so they | |
| 384 // can be used in hashes and maps | |
| 385 template<typename T,class close_policy,class invalid_value,int unique> | |
| 386 inline bool operator==( | |
| 387 shared_any<T,close_policy,invalid_value,unique> const & left, | |
| 388 shared_any<T,close_policy,invalid_value,unique> const & right ) | |
| 389 { | |
| 390 return get( left ) == get( right ); | |
| 391 } | |
| 392 | |
| 393 template<typename T,class close_policy,class invalid_value,int unique> | |
| 394 inline bool operator!=( | |
| 395 shared_any<T,close_policy,invalid_value,unique> const & left, | |
| 396 shared_any<T,close_policy,invalid_value,unique> const & right ) | |
| 397 { | |
| 398 return get( left ) != get( right ); | |
| 399 } | |
| 400 | |
| 401 template<typename T,class close_policy,class invalid_value,int unique> | |
| 402 inline bool operator<( | |
| 403 shared_any<T,close_policy,invalid_value,unique> const & left, | |
| 404 shared_any<T,close_policy,invalid_value,unique> const & right ) | |
| 405 { | |
| 406 return std::less<T>( get( left ), get( right ) ); | |
| 407 } | |
| 408 | |
| 409 #endif // SHARED_ANY | |
| 410 | |
| 411 // This causes the shared_* typedefs to be defined | |
| 412 DECLARE_SMART_ANY_TYPEDEFS(shared) | |
| OLD | NEW |