// Replacement for SGI auto_ptr<T>
// This version is closer to FDIS. It has been tested with egcs 1.1.2.
// Pablo Halpern, 7/28/1998 (Modified from Usenet comp.std.c++ post).
// This code may be used, modified and redistributed freely.

#ifndef autoptr_dot_h_
#define autoptr_dot_h_

namespace std
{

template <class Y>
struct auto_ptr_ref_y {
  Y* py;
  auto_ptr_ref_y(Y* p) : py(p) {}
};

template<class X> struct auto_ptr {

private:
  
  X* px;

  typedef auto_ptr_ref_y<X> auto_ptr_ref;

public:
  typedef X element_type;

  // Explicit and default constructor
  explicit auto_ptr(X* p =0) throw() : px(p) {}

  // Copy constructor. Note that r is non-const.
  auto_ptr(auto_ptr& r) throw() : px(r.release()) {}

#ifdef __STL_MEMBER_TEMPLATES
  // Conversion copy
  template<typename Y> auto_ptr(auto_ptr<Y>& r) throw() : px(r.release())
    {}
#endif

  // Assignment operator
  auto_ptr& operator=(auto_ptr& r) throw() { 
    reset(r.release()); 
    return *this;
  }
#ifdef __STL_MEMBER_TEMPLATES
  // Conversion assignment
  template<typename Y> auto_ptr& operator=(auto_ptr<Y>& r) throw() { 
    reset(r.release()); 
    return *this;
  }
#endif

  ~auto_ptr() { delete px; }

  X& operator*() const throw() { return *px; }
  X* operator->() const throw() { return px; }
  X* get() const throw() { return px; }
  X* release() throw() { X* p=px; px=0; return p; }
  void reset(X* p=0) throw() { if (px != p) delete px, px = p; }

  auto_ptr(auto_ptr_ref r) throw() : px(r.py) {}
  auto_ptr& operator=(auto_ptr_ref r) throw() { reset(r.py); return *this; }
#ifdef __STL_MEMBER_TEMPLATES
  // Convert to intermediate reference type.
  // This allows a temporary auto_ptr to initialize an auto_ptr function arg.
  template<typename Y> operator auto_ptr_ref_y<Y>() throw() {
    return auto_ptr_ref_y<Y>(release()); 
  }
#else
  // Convert to intermediate reference type.
  // This allows a temporary auto_ptr to initialize an auto_ptr function arg.
  operator auto_ptr_ref() throw() {
    return auto_ptr_ref(release()); 
  }
#endif
  
#if 0
  // This seems wrong. It would create an ambigous choice of conversion
  // between auto_ptr<A> and auto_ptr<B>
  template<typename Y> operator auto_ptr<Y>() throw() { 
    return auto_ptr<Y>(release());
  }
#endif
};

} // end namespace std 

#endif // autoptr_dot_h_
