// -*- C++ -*-
/*
 * Copyright (c) 1997-1999
 * Silicon Graphics Computer Systems, Inc.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Silicon Graphics makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * Copyright (c) 2005
 * Takashi Tsunakawa, Kenta Oouchida and Takashi Ninomiya
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Takashi Tsunakawa, Kenta Oouchida and
 * Takashi Ninomiya make no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 */

#ifndef __SGI_PSTL_MEMORY_H
#define __SGI_PSTL_MEMORY_H

#include "_pstl_algobase.h"
#include "_pstl_alloc.h"
#include "_pstl_construct.h"
#include "_pstl_tempbuf.h"
#include "_pstl_uninitialized.h"
#include "_pstl_raw_storage_iter.h"

__PSTL_BEGIN_NAMESPACE

#if defined(__SGI_PSTL_USE_AUTO_PTR_CONVERSIONS) &&	\
    defined(__PSTL_MEMBER_TEMPLATES)

template <class _Tp1, class _Arch> struct auto_ptr_ref {
    ptr<_Tp1, _Arch> _M_ptr;
    auto_ptr_ref(ptr<_Tp1, _Arch> __p) : _M_ptr(__p) {}
};

template <class _Tp1, class _Arch>
struct replace_pheap<auto_ptr_ref<_Tp1, _Arch> > {
    void operator()(const pheap_ptr __ph, auto_ptr_ref<_Tp1, _Arch> &__r) {
	__replace_pheap(__ph, __r._M_ptr);
    }
};

#endif

template <class _Tp, class _Arch> class auto_ptr {
private:
    ptr<_Tp, _Arch> _M_ptr;

public:
    typedef _Tp element_type;

    explicit auto_ptr(ptr<_Tp, _Arch> __p = 0) __PSTL_NOTHROW : _M_ptr(__p) {}
    auto_ptr(auto_ptr &__a) __PSTL_NOTHROW : _M_ptr(__a.release()) {}

#ifdef __PSTL_MEMBER_TEMPLATES
    template <class _Tp1, class _Arch1>
    auto_ptr(auto_ptr<_Tp1, _Arch1> &__a) __PSTL_NOTHROW
    : _M_ptr(__a.release()) {}
#endif /* __PSTL_MEMBER_TEMPLATES */

    auto_ptr &operator=(auto_ptr &__a) __PSTL_NOTHROW {
	if (__a.get().getAddress() != this->get().getAddress()) {
	    pdelete(_M_ptr);
	    _M_ptr = __a.release();
	}
	return *this;
    }

#ifdef __PSTL_MEMBER_TEMPLATES
    template <class _Tp1, class _Arch1>
    auto_ptr &operator=(auto_ptr<_Tp1, _Arch> &__a) __PSTL_NOTHROW {
	if (__a.get().getAddress() != this->get().getAddress()) {
	    pdelete(_M_ptr);
	    _M_ptr = __a.release();
	}
	return *this;
    }
#endif /* __PSTL_MEMBER_TEMPLATES */

    // Note: The C++ standard says there is supposed to be an empty throw
    // specification here, but omitting it is standard conforming.  Its 
    // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
    // this is prohibited.
    ~auto_ptr() { pdelete(_M_ptr); }

    _Tp &operator*() const __PSTL_NOTHROW {
	return *_M_ptr;
    }
    ptr<_Tp, _Arch> operator->() const __PSTL_NOTHROW {
	return _M_ptr;
    }
    ptr<_Tp, _Arch> get() const __PSTL_NOTHROW {
	return _M_ptr;
    }
    ptr<_Tp, _Arch> release() __PSTL_NOTHROW {
	ptr<_Tp, _Arch> __tmp = _M_ptr;
	_M_ptr = ptr<_Tp, _Arch>(0);
	return __tmp;
    }
    void reset(ptr<_Tp, _Arch> __p = 0) __PSTL_NOTHROW {
	if (__p.getAddress() != _M_ptr.getAddress()) {
	    pdelete(_M_ptr);
	    _M_ptr = __p;
	}
    }

    // According to the C++ standard, these conversions are required.  Most
    // present-day compilers, however, do not enforce that requirement---and, 
    // in fact, most present-day compilers do not support the language 
    // features that these conversions rely on.
  
#if defined(__SGI_PSTL_USE_AUTO_PTR_CONVERSIONS) &&	\
    defined(__PSTL_MEMBER_TEMPLATES)

public:
    auto_ptr(auto_ptr_ref<_Tp, _Arch> __ref) __PSTL_NOTHROW
    : _M_ptr(__ref._M_ptr) {}

    auto_ptr &operator=(auto_ptr_ref<_Tp, _Arch> __ref) __PSTL_NOTHROW {
	if (__ref._M_ptr.getAddress() != this->get().getAddress()) {
	    pdelete(_M_ptr);
	    _M_ptr = __ref._M_ptr;
	}
	return *this;
    }

    template <class _Tp1, class _Arch1>
    operator auto_ptr_ref<_Tp1, _Arch1>() __PSTL_NOTHROW 
	{ return auto_ptr_ref<_Tp1, _Arch1>(this->release()); }
    template <class _Tp1, class _Arch1>
    operator auto_ptr<_Tp1, _Arch1>() __PSTL_NOTHROW
	{ return auto_ptr<_Tp1, _Arch1>(this->release()); }

#endif /* auto ptr conversions && member templates */

    template <class _Obj> friend struct replace_pheap;
};

template <class _Tp, class _Arch>
struct replace_pheap<auto_ptr<_Tp, _Arch> > {
    void operator()(const pheap_ptr __ph, auto_ptr<_Tp, _Arch> &__p) {
	__replace_pheap(__ph, __p._M_ptr);
    }
};

__PSTL_END_NAMESPACE

#endif /* __SGI_PSTL_MEMORY_H */


// Local Variables:
// mode:C++
// End:
