/* Copyright (c) 1997-2004
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/

#ifndef _POLYMAKE_VECTOR_H
#define _POLYMAKE_VECTOR_H "$Project: polymake $$Id: Vector.h,v 1.47 2005/09/22 17:12:11 gawrilow Exp $"

#ifndef _POLYMAKE_GENERIC_VECTOR_H
#  include <GenericVector.h>
#endif
#ifndef _POLYMAKE_SHARED_OBJECT_H
#  include <shared_object.h>
#endif

namespace pm {

template <typename E>
class Vector : public GenericVector<Vector<E>, E> {
protected:
   shared_array<E> data;

public:
   typedef E value_type;
   typedef E& reference;
   typedef const E& const_reference;

   /// Vector of size 0.
   Vector() { }

   /// Vector with $n$ elements initialized with their default constructor.
   explicit Vector(int n) : data(n) { }

   /// Vector with $n$ elements initialized with a given value.
   Vector(int n, const E& init) : data(n, constant(init).begin()) { }

   /// Vector with $n$ elements initialized from an input sequence.
   template <typename Iterator>
   Vector(int n, Iterator src) : data(n,src) { }

#if 0
   /// Vector with elements initialized from an input sequence.
   template <typename Iterator>
   Vector(Iterator first, Iterator last) : data(distance(first,last),first) { }
#endif

   /// Copy of a disguised Vector object.
   Vector(const GenericVector<Vector>& v) : data(v.top().data) { }

   template <typename Vector2>
   Vector(const GenericVector<Vector2,E>& v)
      : data(v.dim(), ensure(v.top(), (dense*)0).begin()) { }

   template <typename Vector2, typename E2>
   explicit Vector(const GenericVector<Vector2,E2>& v)
      : data(v.dim(), ensure(attach_converter<E>(v.top()), (dense*)0).begin()) { }

   template <int _size>
   Vector(const E (&a)[_size]) : data(_size, a+0) { }

   template <typename E2, int _size>
   explicit Vector(const E2 (&a)[_size])
      : data(_size, attach_converter<E>(array2container(a)).begin()) { }

   int size() const { return data.size(); }
   bool empty() const { return size()==0; }

   /// Truncate to zero size
   void clear() { data.clear(); }

   /// Change the size, initialize appended elements with default constructor
   void resize(int n) { data.resize(n); }

   Vector& operator= (const Vector& v)
   {
      assign(v);
      return *this;
   }

   template <typename E2>
   void assign(int n, const E2& x)
   {
      data.assign(n, constant(x).begin());
   }

   using Vector::generic_type::operator=;

   void swap(Vector& v) { data.swap(v.data); }

   friend void relocate(Vector* from, Vector* to)
   {
      pm::relocate(&from->data, &to->data);
   }

   E& operator[] (int i)
   {
      INDEX_CHECK((i<0 || i>=this->dim()), "operator[] - index out of range");
      return (*data)[i];
   }

   const E& operator[] (int i) const
   {
      INDEX_CHECK((i<0 || i>=this->dim()), "operator[] - index out of range");
      return (*data)[i];
   }

   typedef E* iterator;
   typedef const E* const_iterator;

   iterator begin() { return *data; }
   iterator end() { return *data+size(); }
   const_iterator begin() const { return *data; }
   const_iterator end() const { return *data+size(); }

   typedef std::reverse_iterator<iterator> reverse_iterator;
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

   reverse_iterator rbegin() { return reverse_iterator(end()); }
   reverse_iterator rend() { return reverse_iterator(begin()); }
   const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
   const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }

   reference front() { return begin()[0]; }
   const_reference front() const { return begin()[0]; }
   reference back() { return end()[-1]; }
   const_reference back() const { return end()[-1]; }

   template <typename Vector2> inline
   Vector& operator|= (const GenericVector<Vector2,E>& v)
   {
      if (data.has_aliases())
	 *this = const_cast<const Vector&>(*this) | v;
      else
	 data.append(v.dim(), ensure(v.top(), (dense*)0).begin());
      return *this;
   }

   Vector& operator|= (const E& r)
   {
      data.append(1, &r);
      return *this;
   }

protected:
   friend class GenericVector<Vector>;
   friend class alias_to_shared<Vector>;

   bool is_shared() const { return data.is_shared(); }

   void assign(const GenericVector<Vector>& v) { data=v.top().data; }

   template <typename Vector2>
   void assign(const GenericVector<Vector2>& v)
   {
      data.assign(v.dim(), ensure(v.top(), (dense*)0).begin());
   }

   template <typename E2, int _size>
   void assign(const E2 (&a)[_size])
   {
      data.assign(_size, a+0);
   }

   template <typename E2>
   void _fill(const E2& x, dense*)
   {
      data.assign(data.size(), constant(x).begin());
   }

   const shared_array<E>& data_member() const { return data; }
};

template <typename E>
class alias_ptr< Vector<E> > : public alias_to_shared< Vector<E> > {
public:
   alias_ptr(const Vector<E>* ptr_arg) : alias_to_shared< Vector<E> >(ptr_arg) { }
};

} // end namespace pm

namespace polymake {
   using pm::Vector;
}

namespace std {
   template <typename E> inline
   void swap(pm::Vector<E>& v1, pm::Vector<E>& v2) { v1.swap(v2); }
}

#endif // _POLYMAKE_VECTOR_H

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