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 |