PageRenderTime 53ms CodeModel.GetById 32ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 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
 28namespace 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
191template<typename T,class close_policy,class invalid_value,int unique>
192class 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
200public:
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::smartany_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 it
285    typename detail::deref<T>::type operator[]( int i ) const
286    {
287        static detail::smartany_static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
288        static detail::smartany_static_assert<!detail::is_delete<close_policy>::value> const 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::smartany_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
304private:
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_policy>::value,
316        detail::intrusive<T,invalid_value_type>,
317        detail::nonintrusive<T,close_policy,invalid_value_type> >::type holder_policy;
318
319    detail::shared_holder<holder_policy> m_held;
320};
321
322namespace 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> & right )
339        {
340            left.swap( right );
341        }
342    };
343}
344
345// return wrapped resource
346template<typename T,class close_policy,class invalid_value,int unique>
347inline 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
353template<typename T,class close_policy,class invalid_value,int unique>
354inline bool valid( shared_any<T,close_policy,invalid_value,unique> const & t )
355{
356    return t;
357}
358
359// destroy designated object
360template<typename T,class close_policy,class invalid_value,int unique>
361inline 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, invalid_value_type() );
366}
367
368// destroy designated object and store new resource
369template<typename T,class close_policy,class invalid_value,int unique,typename U>
370inline 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, newT );
373}
374
375// swap the contents of two shared_any objects
376template<typename T,class close_policy,class invalid_value,int unique>
377inline 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
385template<typename T,class close_policy,class invalid_value,int unique>
386inline 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
393template<typename T,class close_policy,class invalid_value,int unique>
394inline 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
401template<typename T,class close_policy,class invalid_value,int unique>
402inline 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
412DECLARE_SMART_ANY_TYPEDEFS(shared)