/* 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_STD_VECTOR
#define _POLYMAKE_STD_VECTOR "$Project: polymake $$Id: vector,v 1.15 2004/06/22 16:22:42 gawrilow Exp $"

#include_next <vector>
#include <cstring>

#ifndef _POLYMAKE_OPERATIONS_H
# include <operations.h>
#endif

namespace pm {

template <typename Value, typename Alloc>
struct spec_object_traits< std::vector<Value,Alloc> >
   : spec_object_traits<is_container> { };

template <typename Value, typename Alloc> inline
void relocate(std::vector<Value,Alloc>* from, std::vector<Value,Alloc>* to)
{
   std::memcpy(to, from, sizeof(*from));
}

#ifdef __INTEL_COMPILER
namespace std_nested_iterators {
   enum { vector=5, vector_alloc=6, vector__alloc=7 };
   typedef char (&_vector)[vector];
   typedef char (&_vector_alloc)[vector_alloc];
   typedef char (&_vector__alloc)[vector__alloc];

   template <typename Iterator>
   typename if_else< derived_from<typename std::vector<bool>::iterator, Iterator>::answer,
		     _vector, _unmatched >::result
   f(Iterator*, bool*, typename std::vector<bool>::const_iterator*);

   template <typename Iterator>
   typename if_else< derived_from<typename std::vector<bool, alloc>::iterator, Iterator>::answer,
		     _vector_alloc, _unmatched >::result
   f(Iterator*, bool*, typename std::vector<bool, alloc>::const_iterator*);

   template <typename Iterator>
   typename if_else< derived_from<typename std::vector<bool, std::__allocator<bool,raw_alloc> >::iterator, Iterator>::answer,
		     _vector__alloc, _unmatched >::result
   f(Iterator*, bool*, typename std::vector<bool, std::__allocator<bool,raw_alloc> >::const_iterator*);

   template <typename Iterator>
   struct extractor<Iterator, bool, vector> {
      typedef typename std::vector<bool>::iterator iterator;
      typedef typename std::vector<bool>::const_iterator const_iterator;
   };

   template <typename Iterator>
   struct extractor<Iterator, bool, vector_alloc> {
      typedef typename std::vector<bool, alloc>::iterator iterator;
      typedef typename std::vector<bool, alloc>::const_iterator const_iterator;
   };

   template <typename Iterator>
   struct extractor<Iterator, bool, vector__alloc> {
      typedef typename std::vector<bool, std::__allocator<bool,raw_alloc> >::iterator iterator;
      typedef typename std::vector<bool, std::__allocator<bool,raw_alloc> >::const_iterator const_iterator;
   };
}
#endif // __INTEL_COMPILER

template <typename IteratorRef, typename Container>
struct random_iterator_assoc_adapter {
   typedef IteratorRef argument_type;
   typedef iterator_traits<typename deref<IteratorRef>::type> it_traits;
   typedef std::pair<typename it_traits::difference_type, typename it_traits::reference> result_type;

   random_iterator_assoc_adapter() : c(0) { }

   random_iterator_assoc_adapter(const Container& c_arg)
      : c(&c_arg) { }

   template <typename IteratorRef2>
   random_iterator_assoc_adapter(const random_iterator_assoc_adapter<IteratorRef2,Container>& op)
      : c(op.c) { }

   result_type operator() (argument_type it) const
   {
      return result_type(it-c->begin(), *it);
   }

protected:
   const Container* c;
   template <typename, typename> friend class random_iterator_assoc_adapter;
};

template <typename Container>
struct Build_random_iterator_assoc_adapter { };

template <typename Container, typename Iterator, typename ElemRef>
struct unary_op_builder<Build_random_iterator_assoc_adapter<Container>, Iterator, ElemRef> {
   typedef random_iterator_assoc_adapter<const Iterator&, Container> operation;
   static operation create(const Build_random_iterator_assoc_adapter<Container>& c)
   {
      return reinterpret_cast<const Container&>(c);
   }
   static const operation& create(const operation& op) { return op; }

   typedef typename if_else<attrib<ElemRef>::is_const,
			    const random_iterator_assoc_adapter<typename attrib<ElemRef>::minus_const, Container>, operation>::result
      alt_operation;
   static operation create(alt_operation& op) { return operation(op); }
};

template <typename Value>
class vector_as_property_map
   : public modified_container_impl< vector_as_property_map<Value>,
               cons< Container< std::vector<Value> >,
		     Accessor< Build_random_iterator_assoc_adapter< std::vector<Value> > > >
            > {
   typedef modified_container_impl<vector_as_property_map> _super;
public:
   typedef typename _super::container vec_type;
   typedef int key_type;
   typedef Value data_type;
   typedef typename vec_type::reference reference;
   typedef typename vec_type::const_reference const_reference;

   vec_type& get_container() { return vec; }
   const vec_type& get_container() const { return vec; }
   const typename _super::accessor& get_accessor() const
   {
      return reinterpret_cast<const typename _super::accessor&>(vec);
   }

   typedef pair<int, Value> value_type;

   explicit vector_as_property_map(size_t expected_size=0)
      : def_val()
   {
      if (expected_size) vec.reserve(expected_size);
   }

   reference operator() (size_t k)
   {
      if (k >= vec.size()) vec.resize(k+1, def_val);
      return vec[k];
   }

   const_reference operator() (size_t k) const
   {
      if (k < vec.size()) return vec[k];
      return def_val;
   }

   reference operator[] (size_t k) { return vec[k]; }
   const_reference operator[] (size_t k) const { return vec[k]; }

   pair<typename _super::iterator, bool> insert(int k, typename function_argument<Value>::type v)
   {
      if ((size_t)k >= vec.size() || vec[k]==def_val) {
	 (*this)(k)=v;
	 return std::make_pair(typename _super::iterator(vec.begin()+k), true);
      }
      return std::make_pair(typename _super::iterator(vec.begin()+k), false);
   }

   void set_default_value(typename function_argument<Value>::type default_value)
   {
      def_val=default_value;
   }

   void clear() { vec.clear(); }
protected:
   vec_type vec;
   Value def_val;
};

} // end namespace pm

#endif // _POLYMAKE_STD_VECTOR

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