// -*- C++ -*-
/***************************************************************************
 *
 * _autoptr.h - definition of the class template auto_ptr
 *
 * This is an internal header file used to implement the C++ Standard
 * Library. It should never be #included directly by a program.
 *
 * $Id: _autoptr.h 448928 2006-09-22 13:43:18Z faridz $
 *
 ***************************************************************************
 *
 * Licensed to the Apache Software  Foundation (ASF) under one or more
 * contributor  license agreements.  See  the NOTICE  file distributed
 * with  this  work  for  additional information  regarding  copyright
 * ownership.   The ASF  licenses this  file to  you 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the  License is distributed on an  "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
 * implied.   See  the License  for  the  specific language  governing
 * permissions and limitations under the License.
 *
 * Copyright 1994-2006 Rogue Wave Software.
 * 
 **************************************************************************/

#ifndef _RWSTD_RW_AUTOPTR_H_INCLUDED
#define _RWSTD_RW_AUTOPTR_H_INCLUDED

#ifndef _RWSTD_RW_DEFS_H_INCLUDED
#  include <rw/_defs.h>
#endif   // _RWSTD_RW_DEFS_H_INCLUDED


_RWSTD_NAMESPACE (__rw) { 


template <class _TypeT>
struct __rw_nonvoid_ref
{
    typedef _TypeT& _C_ref;
};


_RWSTD_SPECIALIZED_CLASS
struct __rw_nonvoid_ref<void>
{
    // makes the declaration of auto_ptr<void>::operator*() well-formed
    // (the function definition itself may still be ill-formed and must
    // not be instantiated)
    typedef void _C_ref;
};

#ifndef _RWSTD_NO_CV_VOID_SPECIALIZATIONS

_RWSTD_SPECIALIZED_CLASS
struct __rw_nonvoid_ref<const void>
{
    typedef void _C_ref;
};

_RWSTD_SPECIALIZED_CLASS
struct __rw_nonvoid_ref<volatile void>
{
    typedef void _C_ref;
};

_RWSTD_SPECIALIZED_CLASS
struct __rw_nonvoid_ref<const volatile void>
{
    typedef void _C_ref;
};

#endif  // _RWSTD_NO_CV_VOID_SPECIALIZATIONS

}   // namespace __rw


_RWSTD_NAMESPACE (std) { 


// 20.4.5 - Template class auto_ptr

template <class _TypeT>
class auto_ptr;


// 20.4.5, p2 (defined outside of auto_ptr<> according to the proposed
// resolution of lwg issue 127)
template <class _TypeT>
class auto_ptr_ref 
{
#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    template <class _TypeU>
    friend class auto_ptr;

    // implicit conversion from auto_ptr<U> available only
    // if U* is implicitly convertible to T* (via inheritance)
    template <class _TypeU>
    auto_ptr_ref (auto_ptr<_TypeU>& __rhs, const _TypeU* = 0) _THROWS (())
        : _C_ptr (_RWSTD_REINTERPRET_CAST (auto_ptr<_TypeT>&, __rhs)) { }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

public:

    // useless, auto_ptr_ref necessary only for auto_ptr conversions
    auto_ptr_ref (auto_ptr<_TypeT>& __rhs, const _TypeT* = 0) _THROWS (())
        : _C_ptr (__rhs) { }

#endif   // _RWSTD_NO_MEMBER_TEMPLATES

    // reference to the owning auto_ptr object
    auto_ptr<_TypeT>& _C_ptr;
};


template<class _TypeT>
class auto_ptr
{
public:
    typedef _TypeT element_type;

    // 20.4.5.1, p1
    _EXPLICIT auto_ptr (element_type* __p = 0) _THROWS (())
     : _C_ptr (__p) { }

    // 20.4.5.1, p2
    auto_ptr (auto_ptr& __rhs) _THROWS (())
     : _C_ptr (__rhs.release ()) { }

    // 20.4.5.1, p7
    auto_ptr& operator= (auto_ptr& __rhs) _THROWS (()) { 
        reset (__rhs.release ());
        return *this;
    }

    // 20.4.5.1, p13
    ~auto_ptr () _THROWS (()) {
        delete _C_ptr;
    }

#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    // 20.4.5.1, p4
    template <class _TypeU>
    auto_ptr (auto_ptr<_TypeU>& __rhs) _THROWS (())
    : _C_ptr (__rhs.release ()) { }

    // 20.4.5.1, p10
    template <class _TypeU>
    auto_ptr& operator= (auto_ptr<_TypeU>& __rhs)  _THROWS (()) { 
        reset (__rhs.release ());
        return *this;
    }

    // 20.4.5.3, p3
    template <class _TypeU>
    operator auto_ptr_ref<_TypeU>() _THROWS (()) {
        // convertible only if T* is implicitly convertible to U*
        return auto_ptr_ref<_TypeU>(*this, _C_ptr);
    }

    // 20.4.5.3, p4
    template <class _TypeU> 
    operator auto_ptr<_TypeU>() _THROWS (()) {
        return auto_ptr<_TypeU>(release ());
    }

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    // 20.4.5.3, p3 (limited to T == U)
    operator auto_ptr_ref<_TypeT>() _THROWS (()) {
        return auto_ptr_ref<_TypeT>(*this, _C_ptr);
    }

#endif   // _RWSTD_NO_MEMBER_TEMPLATES

    // 20.4.5.2, p1
    _TYPENAME _RW::__rw_nonvoid_ref<element_type>::_C_ref
    operator* () const _THROWS (()) {
        _RWSTD_ASSERT (0 != get ());
        return *get (); 
    }

#ifndef _RWSTD_NO_NONCLASS_ARROW_RETURN

    // 20.4.5.2, p3
    element_type* operator->() const _THROWS (()) {
        // avoid using the _RWSTD_OPERATOR_ARROW() helper macro
        // (defined in terms of operator*()) in order to permit
        // auto_ptr<void>::operator->() to be instantiated
        return _C_ptr;
    }

#endif   // _RWSTD_NO_NONCLASS_ARROW_RETURN

    // 20.4.5.2, p4
    element_type* get () const _THROWS (()) {
        return _C_ptr;
    }

    // 20.4.5.2, p5
    element_type* release () _THROWS (()) { 
        element_type* __tmp = _C_ptr;
        _C_ptr = 0;
        return __tmp; 
    }

    // 20.4.5.2, p7
    void reset (element_type* __p = 0) _THROWS (()) { 
        if (_C_ptr != __p) {
            delete _C_ptr;
            _C_ptr = __p;
        }
    }

    // 20.4.5.3, p1
    auto_ptr (auto_ptr_ref<element_type> __r) _THROWS (())
    : _C_ptr (__r._C_ptr.release ()) { }

    // 20.4.5.3, p? - follows lwg issue 127
    auto_ptr& operator= (auto_ptr_ref<element_type> __rhs) _THROWS (()) {
        reset (__rhs._C_ptr.release ());
        return *this;
    }

private:
    element_type* _C_ptr;
};


}   // namespace std


#endif   // _RWSTD_RW_AUTOPTR_H_INCLUDED
