#ifndef AUTO_ARRAY__
#define AUTO_ARRAY__ 1

namespace mem
{
  template <typename element_type_>
  struct auto_array_ref
  {
    element_type_ *data_;

    explicit
    auto_array_ref (element_type_ *data) throw() : data_ (data) {  }
  };

  template <typename element_type_>
    class auto_array
    {
    private:
      element_type_ *data_;

    public:
      typedef element_type_ element_type;

      explicit
      auto_array(element_type *data = 0) throw() : data_(data) { }

      auto_array(auto_array &aa) throw() : data_ (aa.release()) { }

      template<typename other_element_type_>
	auto_array(auto_array<other_element_type_> &aa) throw() : data_ (aa.release()) { }

      auto_array&
      operator=(auto_array &aa) throw()
      {
	reset(aa.release());
	return *this;
      }

      template <typename other_element_type_>
	auto_array &
	operator= (auto_array<other_element_type_> &aa) throw()
	{
	  reset(aa.release());
	  return *this;
	}

      ~auto_array ()
      {
	delete[] data_;
      }

      element_type&
      operator* () const throw()
      {
	return *this->data_;
      }

      element_type*
      operator-> () const throw()
      {
	return this->data_;
      }

      element_type*
      get() const throw()
      {
	return this->data_;
      }

      element_type*
      release() throw()
      {
	element_type* data = this->data_;
	this->data_ = 0;
	return data;
      }

      void
      reset(element_type* data = 0) throw()
      {
	if (data != this->data_)
	  {
	    delete[] this->data_;
	    this->data_ = data;
	  }
      }

      auto_array (auto_array_ref<element_type> ref) throw()
      : data_(ref.data_) {  }

      auto_array&
      operator= (auto_array_ref<element_type> ref) throw()
      {
	if (ref.data_ != this->get ())
	  {
	    delete[] this->data_;
	    this->data_ = ref.data_;
	  }
	return *this;
      }

      template<typename type_>
	operator auto_array_ref<type_> () throw()
	{ return auto_array_ref<type_> (this->release ()); }

      template<typename type_>
	operator auto_array<type_> () throw()
	{ return auto_array<type_> (this->release()); }
  };
} // namespace mem


#endif /* AUTO_ARRAY__ */
