// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.


#ifndef __HOLDER_H_
#define __HOLDER_H_

#include <wincrypt.h>
#include "cor.h"
#include "staticcontract.h"
#include "volatile.h"
#include "palclr.h"

#ifdef PAL_STDCPP_COMPAT
#include <utility>
#include <type_traits>
#else
#include "clr_std/utility"
#include "clr_std/type_traits"
#endif

#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
#include <Activation.h>
#include <Inspectable.h>
#endif

// Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic
// contracts depends on holders. You can't use static contracts because they include the function name as a string,
// and the template names in this file are just too long, so you get a compiler error.
//
// All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss.

#ifdef _MSC_VER
// Make sure we can recurse deep enough for FORCEINLINE
#pragma inline_recursion(on)
#pragma inline_depth(16)
#pragma warning(disable:4714)
#endif  // _MSC_VER

//------------------------------------------------------------------------------------------------
// Declare but do not define methods that would normally be automatically generated by the
// compiler. This will produce a link-time error if they are used. This is involved in object
// initialization and operator eliding; see
// http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source
// for the intricate details.

#ifdef __GNUC__
// GCC checks accessibility of the copy ctor before performing elision optimization, so
// it must be declared as public. VC does not, so we can declare it private to give an
// earlier error message.
#define HIDE_GENERATED_METHODS(_NAME)                                                       \
    public:                                                                                 \
        _NAME(_NAME const &);                                                               \
    private:                                                                                \
        _NAME & operator=(_NAME const &);
#else
#define HIDE_GENERATED_METHODS(_NAME)                                                       \
    private:                                                                                \
        _NAME(_NAME const &);                                                               \
        _NAME & operator=(_NAME const &);
#endif

#ifdef _DEBUG

//------------------------------------------------------------------------------------------------
// This is used to make Visual Studio autoexp.dat work sensibly with holders again.
// The problem is that certain codebases (particulary Fusion) implement key data structures
// using a class but refer to it using a holder to an interface type. This combination prevents
// autoexp rules from working as desired.
//
// Example: Take this useful autoexp rule for CAssemblyName.
//
//   CAssemblyName=<_rProp._rProp[3].asStr>
//
// To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder,
// add these companion rules.
//
//    HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr>
//    HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr>
//
//------------------------------------------------------------------------------------------------
struct AutoExpVisibleValue
{
  private:
    union
    {
        const void                                          *_pPreventEmptyUnion;
    };
};
#endif //_DEBUG

//-----------------------------------------------------------------------------
// Holder is the base class of all holder objects.  Any backout object should derive from it.
// (Eventually some additional bookkeeping and exception handling code will be placed in this
// base class.)
//
// There are several ways to use this class:
//  1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base.  This is necessary
//      if you need to add more state to your holder.
//  2. Instantiate the Holder template with your type and functions.
//  3. Instantiate the Wrapper template with your type and functions.  The Wrapper adds some additional
//      operator overloads to provide "smart pointer" like behavior
//  4. Use a prebaked Holder.  This is ALWAYS the preferable strategy.  It is expected that
//      the general design patter is that Holders will be provided as part of a typical data abstraction.
//      (See Crst for an example of this.)
//-----------------------------------------------------------------------------



//-----------------------------------------------------------------------------
// HolderBase defines the base holder functionality. You can subtype and plug in
// a different base if you need to add more members for access during
// acquire & release
//-----------------------------------------------------------------------------
template <typename TYPE>
class HolderBase
{
    friend class ClrDataAccess;

  protected:
    TYPE    m_value;

    HolderBase(TYPE value)
      : m_value(value)
    {
#ifdef _DEBUG
        m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value);
#endif //_DEBUG
    }

    void DoAcquire()
    {
        // Insert any global or thread bookkeeping here
    }

    void DoRelease()
    {
        // Insert any global or thread bookkeeping here
    }

#ifdef _DEBUG
 private:
    // NOT DEAD CODE: This field is not referenced in the source code but it is not a dead field. See comments above "class AutoExpVisibleValue" for why this field exists.
    // Note: What we really want is for m_value and m_pAutoExpVisibleValue to be members of a union. But the compiler won't let you build that
    //       since it can't prove that "TYPE" doesn't have a non-trivial constructor.
    const AutoExpVisibleValue *m_pAutoExpVisibleValue;  // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code.
#endif //_DEBUG

};  // class HolderBase<>

#ifndef _PREFAST_ // Work around an ICE error in EspX.dll

template <typename TYPE>
BOOL CompareDefault(TYPE value, TYPE defaultValue)
{
    STATIC_CONTRACT_SUPPORTS_DAC;
    return value == defaultValue;
}

#else

template <typename TYPE>
BOOL CompareDefault(TYPE value, TYPE defaultValue)
{
    return FALSE;
}

#endif


template <typename TYPE>
BOOL NoNull(TYPE value, TYPE defaultValue)
{
    return FALSE;
}

// Used e.g. for retail version of code:SyncAccessHolder
template <typename TYPE>
class NoOpBaseHolder
{
  public:
    FORCEINLINE NoOpBaseHolder()
    {
    }
    FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE)
    {
    }
    FORCEINLINE ~NoOpBaseHolder()
    {
    }
    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
    {
    }
    FORCEINLINE void Acquire()
    {
    }
    FORCEINLINE void Release()
    {
    }
    FORCEINLINE void Clear()
    {
    }
    FORCEINLINE void SuppressRelease()
    {
    }
    FORCEINLINE TYPE Extract()
    {
    }
    FORCEINLINE TYPE GetValue()
    {
    }
    FORCEINLINE BOOL IsNull() const
    {
        return FALSE;
    }

  private:
    NoOpBaseHolder& operator=(NoOpBaseHolder const &);
    NoOpBaseHolder(NoOpBaseHolder const &);
};  // NoOpBaseHolder<>


template
    <
        typename TYPE,
        typename BASE,
        UINT_PTR DEFAULTVALUE = 0,
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>
    >
class BaseHolder : protected BASE
{
    friend class ClrDataAccess;
  protected:
    BOOL    m_acquired;      // Have we acquired the resource?

    static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/),
                  "DEFAULTVALUE must be NULL for pointer holders and wrappers.");

  public:
    FORCEINLINE BaseHolder()
      : BASE(TYPE(DEFAULTVALUE)),
        m_acquired(FALSE)
    {
    }
    FORCEINLINE BaseHolder(TYPE value)
      : BASE(value),
        m_acquired(FALSE)
    {
        if (!IsNull())
            Acquire();
    }
    FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership)
      : BASE(value),
        m_acquired(FALSE)
    {
        if (takeOwnership)
            Acquire();
    }
    FORCEINLINE ~BaseHolder()
    {
        Release();
    }
    // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE.
    FORCEINLINE void Assign(TYPE value)
    {
        Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE)));
    }
    // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE.
    FORCEINLINE void Assign(TYPE value, BOOL takeOwnership)
    {
        Release();
        this->m_value = value;
        if (takeOwnership)
            Acquire();
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        _ASSERTE(!m_acquired);

        if (!IsNull())
        {
            this->DoAcquire();
            m_acquired = TRUE;
        }
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            _ASSERTE(!IsNull());
            this->DoRelease();
            m_acquired = FALSE;
        }
    }

    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        Assign(TYPE(DEFAULTVALUE), FALSE);
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }
    FORCEINLINE TYPE Extract()
    {
        STATIC_CONTRACT_WRAPPER;
        SuppressRelease();
        return GetValue();
    }
    FORCEINLINE TYPE GetValue()
    {
        STATIC_CONTRACT_LEAF;
        return this->m_value;
    }
    FORCEINLINE BOOL IsNull() const
    {
        STATIC_CONTRACT_WRAPPER;
        return IS_NULL(this->m_value, TYPE(DEFAULTVALUE));
    }

    HIDE_GENERATED_METHODS(BaseHolder)
};  // BaseHolder<>

template <void (*ACQUIRE)(), void (*RELEASEF)()>
class StateHolder
{
  private:
    BOOL    m_acquired;      // Have we acquired the state?

  public:
    FORCEINLINE StateHolder(BOOL take = TRUE)
      : m_acquired(FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        if (take)
            Acquire();
    }
    FORCEINLINE ~StateHolder()
    {
        STATIC_CONTRACT_WRAPPER;
        Release();
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookkeeping here

        _ASSERTE(!m_acquired);

        ACQUIRE();
        m_acquired = TRUE;
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookkeeping here

        if (m_acquired)
        {
            RELEASEF();
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            RELEASEF();
        }

        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }

    HIDE_GENERATED_METHODS(StateHolder)
};  // class StateHolder<>

// Holder for the case where the acquire function can fail.
template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value)>
class ConditionalStateHolder
{
  private:
    VALUE   m_value;
    BOOL    m_acquired;      // Have we acquired the state?

  public:
    FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE)
      : m_value(value), m_acquired(FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        if (take)
            Acquire();
    }
    FORCEINLINE ~ConditionalStateHolder()
    {
        STATIC_CONTRACT_WRAPPER;
        Release();
    }
    FORCEINLINE BOOL Acquire()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookkeeping here

        _ASSERTE(!m_acquired);

        m_acquired = ACQUIRE(m_value);

        return m_acquired;
    }
    FORCEINLINE void Release()
    {
        STATIC_CONTRACT_WRAPPER;
        // Insert any global or thread bookkeeping here

        if (m_acquired)
        {
            RELEASEF(m_value);
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_acquired)
        {
            RELEASEF(m_value);
        }

        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        STATIC_CONTRACT_LEAF;
        m_acquired = FALSE;
    }
    FORCEINLINE BOOL Acquired()
    {
        STATIC_CONTRACT_LEAF;

        return m_acquired;
    }

    HIDE_GENERATED_METHODS(ConditionalStateHolder)
};  // class ConditionalStateHolder<>


// Making the copy constructor private produces a warning about "can't generate copy
// constructor" on all holders (duh, that's the point.)
#ifdef _MSC_VER
#pragma warning(disable:4511)
#endif  // _MSC_VER

//-----------------------------------------------------------------------------
// BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains,
// using operator overloads.  Use this when you want a holder to expose the functionality of
// the value it contains.
//-----------------------------------------------------------------------------
template <typename TYPE, typename BASE,
          UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>>
class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL>
{
    typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL> BaseT;


#ifdef __GNUC__
//#pragma GCC visibility push(hidden)
#endif // __GNUC__
    // This temporary object takes care of the case where we are initializing
    // a holder's contents by passing it as an out parameter.  The object is
    // guaranteed to live longer than the call it is passed to, hence we should
    // properly acquire the object on return
    friend class AddressInitHolder;
    class AddressInitHolder
    {
      protected:
        BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder;

      public:
        FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder)
          : m_holder(holder)
        {
            //
            // We must clear the value, to avoid the following scenario:
            //
            //      ReleaseHolder<MyType> pMyType;
            //      hr = MyFunction(&pMyType, ...);
            //      <do something with pMyType>
            //      hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return.
            //
            // If the second call to MyFunction were to fail and return without updating the
            // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on
            // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes
            // out of scope, ReleaseHolder will cause a double-release of pMyType.
            //
            // By calling Clear, then the call to Acquire in the dtor will not set m_acquired
            // to true since IsNull(m_holder.m_value) will return true.
            //
            m_holder.Clear();
        }
        FORCEINLINE ~AddressInitHolder()
        {
            m_holder.Acquire();
        }

        // It's not optimal to have to declare these casting operators.  But if we don't,
        // people cannot cast the result of &holder to these values.  (The C++ compiler won't
        // automatically use the TYPE * cast as an intermediate value.)  So we put them here,
        // rather than forcing callers to double cast in these common cases.

        FORCEINLINE operator IUnknown **()
        {
            IUnknown *unknown;
            // Typesafe check.  This will fail at compile time if
            // m_holder.m_value can't be converted to an IUnknown *.
            unknown = static_cast<IUnknown*>(m_holder.m_value);
            // do the cast with an unsafe cast
            return (IUnknown **)(&m_holder.m_value);
        }

#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
        FORCEINLINE operator IInspectable **()
        {
            IInspectable *inspectable;
            // Typesafe check.  This will fail at compile time if
            // m_holder.m_value can't be converted to an IInspectable *.
            inspectable = static_cast<IInspectable *>(m_holder.m_value);
            return (IInspectable **)(&m_holder.m_value);

        }
#endif // FEATURE_COMINTEROP

        FORCEINLINE operator void **()
        {
            return (void **)(&m_holder.m_value);
        }
        FORCEINLINE operator void *()
        {
            return (void *)(&m_holder.m_value);
        }
    };

    // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or
    // void ** cast operator.
    friend class TypedAddressInitHolder;
    class TypedAddressInitHolder : public AddressInitHolder
    {
      public:
        FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder)
          : AddressInitHolder(holder)
        {
        }

        FORCEINLINE operator TYPE *()
        {
            return static_cast<TYPE *>(&this->m_holder.m_value);
        }
    };
#ifdef __GNUC__
//#pragma GCC visibility pop
#endif // __GNUC__

  public:
    FORCEINLINE BaseWrapper()
        : BaseT(TYPE(DEFAULTVALUE), FALSE)
    {
    }
    FORCEINLINE BaseWrapper(TYPE value)
        : BaseT(value)
    {
    }
    FORCEINLINE BaseWrapper(TYPE value, BOOL take)
        : BaseT(value, take)
    {
    }
    FORCEINLINE BaseWrapper& operator=(TYPE value)
    {
        BaseT::Assign(value);
        return *this;
    }
    FORCEINLINE operator TYPE() const
    {
        return this->m_value;
    }
    FORCEINLINE TypedAddressInitHolder operator&()
    {
        return TypedAddressInitHolder(*this);
    }
    template <typename T>
    FORCEINLINE bool operator==(T const & value) const
    {
        return !!(this->m_value == TYPE(value));
    }
    template <typename T>
    FORCEINLINE bool operator!=(T const & value) const
    {
        return !!(this->m_value != TYPE(value));
    }

    // This handles the NULL value that is an int and the
    // compiler doesn't want to convert int to a pointer.
    FORCEINLINE bool operator==(int value) const
    {
        return !!(this->m_value == TYPE((void*)(SIZE_T)value));
    }
    FORCEINLINE bool operator!=(int value) const
    {
        return !!(this->m_value != TYPE((void*)(SIZE_T)value));
    }

    FORCEINLINE const TYPE &operator->() const
    {
        return this->m_value;
    }
    FORCEINLINE int operator!() const
    {
        return this->IsNull();
    }

  private:
    HIDE_GENERATED_METHODS(BaseWrapper)
};  // class BaseWrapper<>

//-----------------------------------------------------------------------------
// Generic templates to use to wrap up acquire/release functionality for Holder
//-----------------------------------------------------------------------------

template <typename TYPE>
FORCEINLINE void DoNothing(TYPE value)
{
    // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed
    // Search by prefast, and remove them when prefast is ready
}

FORCEINLINE void DoNothing()
{
}

// Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently
// prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change
// everything here. When prefast works, remove the following functions
struct ConnectionCookie;
FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p)
{
}

class ComCallWrapper;
FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p)
{
}


FORCEINLINE void DispParamHolderDoNothing(VARIANT* p)
{
}

FORCEINLINE void VariantPtrDoNothing(VARIANT* p)
{
}

FORCEINLINE void VariantDoNothing(VARIANT)
{
}

FORCEINLINE void ZeroDoNothing(VOID* p)
{
}

class CtxEntry;
FORCEINLINE void CtxEntryDoNothing(CtxEntry* p)
{
}

struct RCW;
FORCEINLINE void NewRCWHolderDoNothing(RCW*)
{
}

// Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration
FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
{
}


//-----------------------------------------------------------------------------
// Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of
// function pointers
//-----------------------------------------------------------------------------

template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE)>
class FunctionBase : protected HolderBase<TYPE>
{
    friend class ClrDataAccess;
  protected:

    FORCEINLINE FunctionBase(TYPE value)
      : HolderBase<TYPE>(value)
    {
    }

    FORCEINLINE void DoAcquire()
    {
        ACQUIREF(this->m_value);
    }

    void DoRelease()
    {
        RELEASEF(this->m_value);
    }
};  // class Function<>

template
    <
        typename TYPE,
        void (*ACQUIREF)(TYPE),
        void (*RELEASEF)(TYPE),
        UINT_PTR DEFAULTVALUE = 0,
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
        // operates on static or global value instead.
        bool DEFAULT_CTOR_ACQUIRE = true
    >
class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
                                 DEFAULTVALUE, IS_NULL>
{
    typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
                                 DEFAULTVALUE, IS_NULL> BaseT;

  public:
    FORCEINLINE Holder()
        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder(TYPE value)
        : BaseT(value)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder(TYPE value, BOOL takeOwnership)
        : BaseT(value, takeOwnership)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Holder& operator=(TYPE p)
    {
        STATIC_CONTRACT_WRAPPER;
        BaseT::operator=(p);
        return *this;
    }

    HIDE_GENERATED_METHODS(Holder)
};

//---------------------------------------------------------------------------------------
//
template
    <
        typename TYPE,
        void (*ACQUIREF)(TYPE),
        void (*RELEASEF)(TYPE),
        UINT_PTR DEFAULTVALUE = 0,
        BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
        // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
        // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
        // operates on static or global value instead.
        bool DEFAULT_CTOR_ACQUIRE = true
    >
class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
                                   DEFAULTVALUE, IS_NULL>
{
    typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF>,
                                   DEFAULTVALUE, IS_NULL> BaseT;

  public:
    FORCEINLINE Wrapper()
        : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper(TYPE value)
        : BaseT(value)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership)
        : BaseT(value, takeOwnership)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    FORCEINLINE Wrapper& operator=(TYPE const & value)
    {
        STATIC_CONTRACT_WRAPPER;
        BaseT::operator=(value);
        return *this;
    }

    HIDE_GENERATED_METHODS(Wrapper)
};  // Wrapper<>

//---------------------------------------------------------------------------------------
// - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way
#if defined(_DEBUG)
#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x
#else
#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x)
#endif

template <typename _TYPE, void (*_RELEASEF)(_TYPE*)>
class SpecializedWrapper : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>
{
    using BaseT = Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>;
public:
    FORCEINLINE SpecializedWrapper() : BaseT(NULL, FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
    }
    FORCEINLINE SpecializedWrapper(_TYPE* value) : BaseT(value)
    {
        STATIC_CONTRACT_WRAPPER;
        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
    }
    FORCEINLINE SpecializedWrapper(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership)
    {
        STATIC_CONTRACT_WRAPPER;
        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
    }
    FORCEINLINE ~SpecializedWrapper()
    {
    }

    SpecializedWrapper(SpecializedWrapper const &) = delete;
    SpecializedWrapper & operator=(SpecializedWrapper const &) = delete;

    FORCEINLINE SpecializedWrapper& operator=(_TYPE * value)
    {
        STATIC_CONTRACT_WRAPPER;
        BaseT::operator=(value);
        return *this;
    }

    FORCEINLINE SpecializedWrapper(SpecializedWrapper && other)
    : BaseT(NULL, FALSE)
    {
        STATIC_CONTRACT_WRAPPER;
        INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;)
        *this = std::move(other);
    }

    FORCEINLINE SpecializedWrapper& operator=(SpecializedWrapper && other)
    {
        BaseT::m_value = std::move(other.BaseT::m_value);
        BaseT::m_acquired = std::move(other.BaseT::m_acquired);
        other.BaseT::m_value = nullptr;
        other.BaseT::m_acquired = FALSE;
        return *this;
    }

    /* Since operator& is overloaded we need a way to get a type safe this pointer. */
    FORCEINLINE SpecializedWrapper* GetAddr()
    {
        STATIC_CONTRACT_LEAF;
        return this;
    }
    private:
    /* m_ppValue: Do not use from source code: Only for convenient use from debugger */
    /*     watch windows - saves five mouseclicks when inspecting holders. */
    INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;)
};

//-----------------------------------------------------------------------------
// NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!!
//  WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!!
//  USE SafeComHolder
//
// ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances
//                  which do not need preemptive Relesae)
//
// Usage example:
//
//  {
//      ReleaseHolder<IFoo> foo;
//      hr = FunctionToGetRefOfFoo(&foo);
//      // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0).
//  } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!)
//
//-----------------------------------------------------------------------------

template <typename TYPE>
FORCEINLINE void DoTheRelease(TYPE *value)
{
    if (value)
    {
        value->Release();
    }
}

template<typename _TYPE>
using DoNothingHolder = SpecializedWrapper<_TYPE, DoNothing<_TYPE*>>;

template<typename _TYPE>
using ReleaseHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>;

template<typename _TYPE>
using NonVMComHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>;


//-----------------------------------------------------------------------------
// StubHolder : holder for stubs
//
// Usage example:
//
//  {
//      StubHolder<Stub> foo;
//      foo = new Stub();
//      foo->AddRef();
//      // Note StubHolder doesn't call AddRef for you.
//  } // foo->DecRef() on out of scope
//
//-----------------------------------------------------------------------------

template<typename _TYPE>
class ExecutableWriterHolderNoLog;

class ExecutableAllocator;

template <typename TYPE, typename LOGGER=ExecutableAllocator>
FORCEINLINE void StubRelease(TYPE* value)
{
    if (value)
    {
#ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS
#ifdef TARGET_UNIX
        LOGGER::LogUsage(__FILE__, __LINE__, __PRETTY_FUNCTION__);
#else
        LOGGER::LogUsage(__FILE__, __LINE__, __FUNCTION__);
#endif
#endif // LOG_EXECUTABLE_ALLOCATOR_STATISTICS
        ExecutableWriterHolderNoLog<TYPE> stubWriterHolder(value, sizeof(TYPE));
        stubWriterHolder.GetRW()->DecRef();
    }
}

template<typename _TYPE>
using StubHolder = SpecializedWrapper<_TYPE, StubRelease<_TYPE>>;

//-----------------------------------------------------------------------------
// CoTaskMemHolder : CoTaskMemAlloc allocated memory holder
//
//  {
//      CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo));
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE>
FORCEINLINE void DeleteCoTaskMem(TYPE *value)
{
    if (value)
        CoTaskMemFree(value);
}

template<typename _TYPE>
using CoTaskMemHolder = SpecializedWrapper<_TYPE, DeleteCoTaskMem<_TYPE>>;

//-----------------------------------------------------------------------------
// NewHolder : New'ed memory holder
//
//  {
//      NewHolder<Foo> foo = new Foo ();
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE>
FORCEINLINE void Delete(TYPE *value)
{
    STATIC_CONTRACT_LEAF;

    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value,
                  "Must use NewArrayHolder (not NewHolder) for strings.");
    static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value,
                  "Must use NewArrayHolder (not NewHolder) for strings.");

    delete value;
}

template<typename _TYPE>
using NewHolder = SpecializedWrapper<_TYPE, Delete<_TYPE>>;

 //-----------------------------------------------------------------------------
// NewExecutableHolder : New'ed memory holder for executable memory.
//
//  {
//      NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num];
//  } // delete foo on out of scope
//-----------------------------------------------------------------------------
// IJW
template<class T> void DeleteExecutable(T *p);

template<typename _TYPE>
using NewExecutableHolder = SpecializedWrapper<_TYPE, DeleteExecutable<_TYPE>>;

//-----------------------------------------------------------------------------
// NewArrayHolder : New []'ed pointer holder
//  {
//      NewArrayHolder<Foo> foo = new Foo [30];
//  } // delete [] foo on out of scope
//-----------------------------------------------------------------------------

template <typename TYPE>
FORCEINLINE void DeleteArray(TYPE *value)
{
    STATIC_CONTRACT_WRAPPER;
    delete [] value;
    value = NULL;
}

template<typename _TYPE>
using NewArrayHolder = SpecializedWrapper<_TYPE, DeleteArray<_TYPE>>;
typedef NewArrayHolder<CHAR>  AStringHolder;
typedef NewArrayHolder<WCHAR> WStringHolder;

//-----------------------------------------------------------------------------
// A special array holder that expects its contents are interface pointers,
// and will call Release() on them.
//
// NOTE: You may ONLY use this if you've determined that it is SAFE to call
// Release() on the contained interface pointers (e.g., as opposed to SafeRelease)
//
template <typename INTERFACE>
class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *>
{
public:
    NewInterfaceArrayHolder() :
        NewArrayHolder<INTERFACE *>(),
        m_cElements(0)
    {
        STATIC_CONTRACT_WRAPPER;
    }

    NewInterfaceArrayHolder& operator=(INTERFACE ** value)
    {
        STATIC_CONTRACT_WRAPPER;
        NewArrayHolder<INTERFACE *>::operator=(value);
        return *this;
    }

    void SetElementCount(ULONG32 cElements)
    {
        STATIC_CONTRACT_LEAF;
        m_cElements = cElements;
    }

    ~NewInterfaceArrayHolder()
    {
        STATIC_CONTRACT_LEAF;
        for (ULONG32 i=0; i < m_cElements; i++)
        {
            if (this->m_value[i] != NULL)
                this->m_value[i]->Release();
        }
    }

protected:
    ULONG32 m_cElements;
};


//-----------------------------------------------------------------------------
// ResetPointerHolder : pointer which needs to be set to NULL
//  {
//      ResetPointerHolder<Foo> holder = &pFoo;
//  } // "*pFoo=NULL" on out of scope
//-----------------------------------------------------------------------------
#ifdef __GNUC__
// With -fvisibility-inlines-hidden, the Invoke methods below
// get hidden, which causes warnings when visible classes expose them.
#define VISIBLE __attribute__ ((visibility("default")))
#else
#define VISIBLE
#endif // __GNUC__

namespace detail
{
    template <typename T>
    struct ZeroMem
    {
        static VISIBLE void Invoke(T * pVal)
        {
            ZeroMemory(pVal, sizeof(T));
        }
    };

    template <typename T>
    struct ZeroMem<T*>
    {
        static VISIBLE void Invoke(T ** pVal)
        {
            *pVal = NULL;
        }
    };

}
#undef VISIBLE

template<typename _TYPE>
using ResetPointerHolder = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>;
template<typename _TYPE>
using FieldNuller = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>;

//-----------------------------------------------------------------------------
// Wrap win32 functions using HANDLE
//-----------------------------------------------------------------------------

FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); }
// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); }
FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); }
FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); }

template <typename TYPE>
FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); }

// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
//@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent).
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder;
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder;
typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder;

typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder;

#ifdef WszDeleteFile
// Deletes a file with the specified path.  Do not use if you care about failures
// deleting the file, as failures are ignored by VoidDeleteFile.
FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); }
typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder;
#endif // WszDeleteFile


//-----------------------------------------------------------------------------
// Misc holders
//-----------------------------------------------------------------------------

// A holder for HMODULE.
FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); }

typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder;

template <typename T> FORCEINLINE
void DoLocalFree(T* pMem)
{
#ifdef HOST_WINDOWS
    (LocalFree)((void*)pMem);
#else
    (free)((void*)pMem);
#endif
}

template<typename _TYPE>
using LocalAllocHolder = SpecializedWrapper<_TYPE, DoLocalFree<_TYPE>>;

inline void BoolSet( _Out_ bool * val ) { *val = true; }
inline void BoolUnset( _Out_ bool * val ) { *val = false; }

typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder;

//
// We need the following methods to have volatile arguments, so that they can accept
// raw pointers in addition to the results of the & operator on Volatile<T>.
//

FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);};
FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);};

typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>> CounterHolder;


#ifdef HOST_WINDOWS
FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);};
typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder;
#endif // HOST_WINDOWS

class ErrorModeHolder
{
    UINT m_oldMode;
public:
    ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);};
    ~ErrorModeHolder(){SetErrorMode(m_oldMode);};
    UINT OldMode() {return m_oldMode;};
};

#ifdef HOST_WINDOWS
//-----------------------------------------------------------------------------
// HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit.
//
//  {
//      HKEYHolder hFoo = NULL;
//      WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo);
//
//  } // close key on out of scope via RegCloseKey.
//-----------------------------------------------------------------------------

class HKEYHolder
{
public:
    HKEYHolder()
    {
        STATIC_CONTRACT_LEAF;
        m_value = 0;
    }

    ~HKEYHolder()
    {
        STATIC_CONTRACT_WRAPPER;
        if (m_value != NULL)
            ::RegCloseKey(m_value);
    }

    FORCEINLINE void operator=(HKEY p)
    {
        STATIC_CONTRACT_LEAF;
        if (p != 0)
            m_value = p;
    }

    FORCEINLINE operator HKEY()
    {
        STATIC_CONTRACT_LEAF;
        return m_value;
    }

    FORCEINLINE operator HKEY*()
    {
        STATIC_CONTRACT_LEAF;
        return &m_value;
    }

    FORCEINLINE HKEY* operator&()
    {
        STATIC_CONTRACT_LEAF;
        return &m_value;
    }

private:
    HKEY m_value;
};
#endif // HOST_WINDOWS

//----------------------------------------------------------------------------
//
// External data access does not want certain holder implementations
// to be active as locks should not be taken and so on.  Provide
// a no-op in that case.
//
//----------------------------------------------------------------------------

#ifndef DACCESS_COMPILE

#define DacHolder Holder

#else

template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE>
class DacHolder
{
  protected:
    TYPE    m_value;

  private:
    BOOL    m_acquired;      // Have we acquired the resource?

  public:
    FORCEINLINE DacHolder()
      : m_value(TYPE(DEFAULTVALUE)),
        m_acquired(FALSE)
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
    }

    // construct a new instance of DacHolder
    // Arguments:
    //     input:  value - the resource held
    //             take  - indicates whether the lock should be taken--the default is true. See Notes:
    // Note: In DAC builds, the Acquire function does not actually take the lock, instead
    //       it determines whether the lock is held (by the LS). If it is, the locked data
    //       is assumed to be inconsistent and the Acquire function will throw.
    FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE)
      : m_value(value),
        m_acquired(FALSE)
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
        if (take)
            Acquire();

    }
    FORCEINLINE ~DacHolder()
    {
        STATIC_CONTRACT_SUPPORTS_DAC;
    }
    // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE.
    FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
    {
        m_value = value;
    }
    FORCEINLINE void Acquire()
    {
        STATIC_CONTRACT_SUPPORTS_DAC;

        if (!IsNull())
        {
            m_acquired = TRUE;
            // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call
            // where it logically belongs, the compiler flags it as "unreachable code."
            ACQUIRE(this->m_value);
        }
    }
    FORCEINLINE void Release()
    {
        // Insert any global or thread bookkeeping here

        if (m_acquired)
        {
            m_acquired = FALSE;
        }
    }
    FORCEINLINE void Clear()
    {
        m_value = TYPE(DEFAULTVALUE);
        m_acquired = FALSE;
    }
    FORCEINLINE void SuppressRelease()
    {
        m_acquired = FALSE;
    }
    FORCEINLINE TYPE GetValue()
    {
        return m_value;
    }
    FORCEINLINE BOOL IsNull() const
    {
        return IS_NULL(m_value, TYPE(DEFAULTVALUE));
    }

  private:
    FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
    {
    }

    FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
    {
    }
};

#endif // #ifndef DACCESS_COMPILE

// Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions.
namespace clr
{
    // Copied from utilcode.h. We can't include the header directly because there
    // is circular reference.
    // Forward declare the overload which is used by 'SafeAddRef' below.
    template <typename ItfT>
    static inline
    typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
    SafeAddRef(ItfT pItf);

    template < typename ItfT > __checkReturn
    ItfT *
    SafeAddRef(ReleaseHolder<ItfT> & pItf)
    {
        STATIC_CONTRACT_LIMITED_METHOD;
        //@TODO: Would be good to add runtime validation that the return value is used.
        return SafeAddRef(pItf.GetValue());
    }

    namespace detail
    {
        template <typename T>
        char IsHolderHelper(HolderBase<T>*);
        int  IsHolderHelper(...);

        template <typename T>
        struct IsHolder : public std::conditional<
            sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char),
            std::true_type,
            std::false_type>::type
        {};
    }

    template < typename T >
    typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type
    SafeRelease(T& arg)
    {
        STATIC_CONTRACT_LIMITED_METHOD;
        return arg.Release();
    }
}

#endif  // __HOLDER_H_
