PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/omaha/third_party/smartany/shared_any.h

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