/* Make Emacs accept this as -*- C++ -*- despite the lower case .h filename */

// This is almost, but not quite, a standards conforming implementation of
// the auto_ptr class template. What's missing is a way of silencing the
// "non-const reference to temporary" warnings. In standard C++ binding
// a temporary to a non-const reference is illegal, and the solution is
// to use a private member template struct named "auto_ptr_ref<T>", which
// refers to an original during such a conversion. As no compiler I have
// access to supports this and at the same time bans binding temporaries
// to non-const references, I cannot add the member template struct without
// introducing ambiguities in copying and assignment.
//
// Bjorn.


#ifndef AUTO_PTR_H
#define AUTO_PTR_H

#if ( __WATCOM_CPLUSPLUS__ >= 1100 )
#  define APTR_HAVE_EXPLICIT
#endif

#if defined(__GNUC__)
#  define APTR_HAVE_EXPLICIT
#  if __GNUC__ >= 2 && __GNUC_MINOR__ > 7
#    define APTR_HAVE_MEMBER_TEMPLATES
#  endif
#  if __GNUC__ >= 2 && __GNUC_MINOR__ == 7
#    define APTR_GCC_BUGGY_THROW_SPEC
#  endif
#endif

#ifdef APTR_GCC_BUGGY_THROW_SPEC
#define APTR_THROW
#else
#define APTR_THROW throw ()
#endif

#ifndef APTR_HAVE_EXPLICIT
template <class T> 
class explicit
{
public:
  explicit(T t) : value(t) {};
  operator T() const { return value; }
private:
  T value;
};
#endif

template <class T>
class auto_ptr
{
public:
#ifdef APTR_HAVE_EXPLICIT
  explicit auto_ptr(T* t = 0) throw ();
#else
  auto_ptr(explicit<T*> t=explicit<T*>(0)) throw ();
#endif
  auto_ptr(auto_ptr<T>& t) throw();
#ifdef APTR_HAVE_MEMBER_TEMPLATES
  template <class Y> auto_ptr(auto_ptr<Y>& t) throw();
#endif
 ~auto_ptr() throw ();
  auto_ptr<T>& operator=(auto_ptr<T>& t) throw ();
#ifdef APTR_HAVE_MEMBER_TEMPLATES
  template <class Y> 
    auto_ptr<T>& operator=(auto_ptr<Y>& t) throw (); 
#endif
  T& operator*() const throw ();
  T* operator->() const throw ();
  T* release() throw ();
  void reset(T* t = 0) throw ();
  T* get(void) const throw ();
private:
  T* p;
};

#ifdef APTR_HAVE_EXPLICIT
template <class T>
inline auto_ptr<T>::auto_ptr(T* ptr) APTR_THROW
  : p(ptr)
{
}
#else
template <class T>
inline auto_ptr<T>::auto_ptr(explicit<T*> ptr) throw ()
  : p(ptr)
{
}
#endif

template <class T>
inline auto_ptr<T>::auto_ptr(auto_ptr<T>& t) APTR_THROW
  : p(t.release())
{
}

#ifdef APTR_HAVE_MEMBER_TEMPLATES
template <class T> template <class Y>
inline auto_ptr<T>::auto_ptr(auto_ptr<Y>& t) throw ()
  : p(t.release())
{
}
#endif

template <class T>
inline auto_ptr<T>::~auto_ptr() APTR_THROW
{
  delete p;
}

template <class T>
inline auto_ptr<T>&
auto_ptr<T>::operator=(auto_ptr<T>& t) throw ()
{
  reset(t.release());
  return *this;
}

#ifdef APTR_HAVE_MEMBER_TEMPLATES
template <class T> template <class Y>
inline auto_ptr<T>&
auto_ptr<T>::operator=(auto_ptr<Y>& t) throw ()
{
  reset(t.release());
  return *this;
}
#endif

template <class T>
inline T& auto_ptr<T>::operator*() const throw()
{
  return *p;
}

template <class T>
inline T* auto_ptr<T>::operator->() const throw ()
{
  return p;
}

template <class T>
inline T* auto_ptr<T>::release() throw ()
{
  T* tp=p;
  p = 0;
  return tp;
}

template <class T>
inline void auto_ptr<T>::reset(T* t) throw ()
{
  if (t != p) {
    delete p;
    p = t;
  }
}

template <class T>
inline T* auto_ptr<T>::get(void) const throw ()
{
  return p;
}

#ifdef APTR_HAVE_EXPLICIT
#undef APTR_HAVE_EXPLICIT
#endif

#ifdef APTR_HAVE_MEMBER_TEMPLATES
#undef APTR_HAVE_MEMBER_TEMPLATES
#endif

#ifdef APTR_GCC_BUGGY_THROW_SPEC
#undef APTR_GCC_BUGGY_THROW_SPEC
#endif

#ifdef APTR_THROW
#undef APTR_THROW
#endif

#endif // AUTO_PTR_H

