/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ //+--------------------------------------------------------------------------- // // File: auto_any.h // // Contents: automatic resource management, a-la std::auto_ptr // // Classes: auto_any<> and various typedefs // // Functions: get // reset // release // valid // address // //---------------------------------------------------------------------------- #ifndef AUTO_ANY #define AUTO_ANY #include #include "smart_any_fwd.h" #pragma warning(push) // 4284 warning for operator-> returning non-pointer; // compiler issues it even if -> is not used for the specific instance #pragma warning(disable: 4284) namespace detail { // friend function definitions go in auto_any_helper template struct auto_any_helper; } // proxy reference for auto_any copying template struct auto_any_ref { // construct from compatible auto_any auto_any_ref( auto_any & that ) : m_that( that ) { } // reference to constructor argument auto_any & m_that; private: auto_any_ref * operator=( auto_any_ref const & ); }; // wrap a resource to enforce strict ownership and ensure proper cleanup template class auto_any { typedef detail::safe_types safe_types; // disallow comparison of auto_any's bool operator==( detail::safe_bool ) const; bool operator!=( detail::safe_bool ) const; public: typedef typename detail::holder::type element_type; typedef close_policy close_policy_type; typedef typename safe_types::pointer_type pointer_type; typedef typename safe_types::reference_type reference_type; // Fix-up the invalid_value type on older compilers typedef typename detail::fixup_invalid_value:: template rebind::type invalid_value_type; friend struct detail::auto_any_helper; // construct from object pointer explicit auto_any( T t = invalid_value_type() ) : m_t( t ) { } // construct by assuming pointer from right auto_any auto_any( auto_any & right ) : m_t( release( right ) ) { } // construct by assuming pointer from right auto_any_ref auto_any( auto_any_ref right ) : m_t( release( right.m_that ) ) { } // convert to compatible auto_any_ref operator auto_any_ref() { return auto_any_ref( *this ); } // assign compatible right auto_any & operator=( auto_any & right ) { reset( *this, release( right ) ); return *this; } // assign compatible right.ref auto_any & operator=( auto_any_ref right ) { reset( *this, release( right.m_that ) ); return *this; } // destroy the object ~auto_any() { if( valid() ) { close_policy::close( m_t ); } } // return pointer to class object (assume pointer) pointer_type operator->() const { #ifdef SMART_ANY_PTS // You better not be applying operator-> to a handle! static detail::static_assert::value> const cannot_dereference_a_handle; #endif assert( valid() ); return safe_types::to_pointer( m_t ); } // for use when auto_any appears in a conditional operator detail::safe_bool() const { return valid() ? detail::safe_true : detail::safe_false; } // for use when auto_any appears in a conditional bool operator!() const { return ! valid(); } #ifdef SMART_ANY_PTS // if this auto_any is managing an array, we can use operator[] to index it typename detail::deref::type operator[]( int i ) const { static detail::static_assert::value> const cannot_dereference_a_handle; static detail::static_assert::value> const accessed_like_an_array_but_not_deleted_like_an_array; assert( valid() ); return m_t[ i ]; } // unary operator* lets you write code like: // auto_any pfoo( new foo ); // foo & f = *pfoo; reference_type operator*() const { static detail::static_assert::value> const cannot_dereference_a_handle; assert( valid() ); return safe_types::to_reference( m_t ); } #endif private: bool valid() const { // see if the managed resource is in the invalid state. return m_t != static_cast( invalid_value_type() ); } // the wrapped object element_type m_t; }; namespace detail { // friend function definitions go in auto_any_helper template struct auto_any_helper { // return wrapped pointer static T get( auto_any const & t ) { return t.m_t; } // return wrapped pointer and give up ownership static T release( auto_any & t ) { // Fix-up the invalid_value type on older compilers typedef typename detail::fixup_invalid_value:: template rebind::type invalid_value_type; T tmpT = t.m_t; t.m_t = static_cast( invalid_value_type() ); return tmpT; } // destroy designated object and store new pointer static void reset( auto_any & t, T newT ) { if( t.m_t != newT ) { if( t.valid() ) { close_policy::close( t.m_t ); } t.m_t = newT; } } typedef typename auto_any::element_type element_type; // return the address of the wrapped pointer static element_type* address( auto_any & t ) { // check to make sure the wrapped object is in the invalid state assert( !t.valid() ); return address_of( t.m_t ); } }; } // return wrapped resource template inline T get( auto_any const & t ) { return detail::auto_any_helper::get( t ); } // return true if the auto_any contains a currently valid resource template inline bool valid( auto_any const & t ) { return t; } // return wrapped resource and give up ownership template inline T release( auto_any & t ) { return detail::auto_any_helper::release( t ); } // destroy designated object and store new resource template inline void reset( auto_any & t ) { typedef typename detail::fixup_invalid_value:: template rebind::type invalid_value_type; detail::auto_any_helper::reset( t, invalid_value_type() ); } // destroy designated object and store new resource template inline void reset( auto_any & t, U newT ) { detail::auto_any_helper::reset( t, newT ); } // swap the contents of two shared_any objects template void swap( auto_any & left, auto_any & right ) { auto_any tmp( left ); left = right; right = tmp; } // return the address of the wrapped resource // WARNING: this will assert if the value of the resource is // anything other than invalid_value. template inline typename auto_any::element_type* address( auto_any & t ) { return detail::auto_any_helper::address( t ); } #pragma warning(pop) #endif // This causes the auto_* typedefs to be defined DECLARE_SMART_ANY_TYPEDEFS(auto) #if defined(_OBJBASE_H_) & !defined(AUTO_ANY_CO_INIT) # define AUTO_ANY_CO_INIT typedef auto_any auto_co_close; // Helper class for balancing calls to CoInitialize and CoUninitialize struct auto_co_init { explicit auto_co_init( DWORD dwCoInit = COINIT_APARTMENTTHREADED ) : m_hr( smart_co_init_helper( dwCoInit ) ) { } HRESULT hresult() const { return get(m_hr); } auto_co_close const m_hr; private: auto_co_init & operator=( auto_co_init const & ); }; #endif