//  vector : headerfile for the free standard C++ library
//  
//  Copyright (C) 1999 by the free standard C++ Library Team
//                        see AUTHORS for more details
//
//  Homepage : http://www.inf.fu-berlin.de/~mkrueger/fscl/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either	
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Library General Public License for more details.
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//  version : 0.1 last modified : 17.09.99

#ifndef __CPP_VECTOR
#define __CPP_VECTOR

#include<cstddef>
#include<cstdio>
#include<algorithm>
#include<memory>

namespace std {
	
	// 23.2.4 Template class vector
	template <class T, class Allocator = allocator<T> > 
	class vector
	{
		private:
			typedef struct Vec {
				typename Allocator::pointer     offset;
				typename Allocator::size_type   size, elements;
				Allocator allocator;
		
				Vec(Allocator alloc)
				{
					size      = 1;
					elements  = 0;
					allocator = alloc;
					offset    = alloc.allocate(1);
				}

			};
			Vec vec;
			
		public:

			typedef typename Allocator::reference             reference;
			typedef typename Allocator::const_reference       const_reference;
			typedef typename Allocator::size_type             size_type;
			typedef typename Allocator::difference_type       difference_type;
			typedef T                                         value_type;
			typedef Allocator                                 allocator_type;
			typedef typename Allocator::pointer               pointer;
			typedef typename Allocator::const_pointer         const_pointer;

			typedef typename Allocator::pointer               iterator;
			typedef typename Allocator::const_pointer         const_iterator;				
			typedef std::reverse_iterator<iterator>           reverse_iterator;
			typedef std::reverse_iterator<const_iterator>     const_reverse_iterator;
							
							
			// 23.2.4.1 construct/copy/destroy:
			explicit vector(const Allocator &alloc = Allocator()) 
			: vec(alloc)
			{
					
			}
					    
			explicit vector(size_type n, const T& value = T(), const Allocator &alloc = Allocator()) 
			: vec(alloc)
			{
				insert(begin(), n , value);
			}

			template <class InputIterator>
			vector(InputIterator first, InputIterator last, const Allocator &alloc = Allocator())
			: vec(alloc)
			{
				insert(begin(), first, last);
			}

			vector(const vector<T,Allocator> &x) : vec(Allocator())
			{
				operator=(x);
			}
			
			~vector()
			{
				vec.allocator.deallocate(begin(), size());
			}

			vector<T,Allocator> &operator=(const vector<T,Allocator> &x)
			{
				vec = x.vec;
				vec.offset = vec.allocator.allocate(vec.size);
				for (size_t i = 0;i<vec.size;i++)
					vec.offset[i] = x.vec.offset[i];
				return *this;
			}

			template <class InputIterator>
			void assign(InputIterator first, InputIterator last)
			{
				vec.elements = 0;
				insert(begin(), first, last);
			}

			void assign(size_type n, const T &u = T())
			{
				vec.elements = 0;
				insert(begin(), n, u);
			}

			allocator_type get_allocator() const
			{
				return vec.allocator;
			}
			
			// iterators:
			iterator               begin()
			{
				return vec.offset;
			}			
			const_iterator         begin() const
			{
				return (const_iterator)vec.offset;
			}			
			iterator               end()
			{
				return &vec.offset[vec.elements];
			}			
			const_iterator         end() const
			{
				return (const_iterator)&vec.offset[vec.elements];
			}
			
			reverse_iterator       rbegin()
			{
				return reverse_iterator(end());
			}			
			const_reverse_iterator rbegin() const
			{
				return const_reverse_iterator(end());
			}			
			reverse_iterator       rend()
			{
				return reverse_iterator(begin());
			}
			const_reverse_iterator rend() const
			{
				return const_reverse_iterator(begin());
			}
			
			// 23.2.4.2 capacity:
			size_type size() const
			{
				return vec.elements;
			}			
			size_type max_size() const
			{
				return vec.allocator.max_size;
			}
			
			void resize(size_type sz, T c = T())
			{
				if (sz > size())
					insert(end(), sz - size(), c);
				else
				if (sz < size())
					erase(begin() + sz, end());	
			}

			size_type capacity() const
			{
				return vec.size;
			}

			bool empty() const
			{
				return vec.elements == 0;
			}

			void reserve(size_type n)
			{
				if (capacity() < n ) {
					if (vec.offset != 0)
						vec.allocator.reallocate(vec.offset, capacity(), n);
					else
						vec.offset = vec.allocator.allocate(n);
					vec.size = n;
				}
			}
			
			// element access:
			reference operator[](size_type n)
			{
				return vec.offset[n];
			}

			const_reference operator[](size_type n) const
			{
				return vec.offset[n];
			}

			const_reference at(size_type n) const
			{
				if (n >= vec.elements)
					throw out_of_range("argument out of range");

				return vec.offset[n];
			}

			reference  at(size_type n)
			{
				if (n >= vec.elements)
					throw out_of_range("argument out of range");

				return vec.offset[n];
			}

			reference  front()
			{
				return *vec.offset;
			}
			const_reference front() const
			{
				return (const_reference)*vec.offset;
			}

			reference       back()
			{
				return vec.offset[vec.elements - 1];
			}
			const_reference back() const
			{
				return (const_reference)vec.offset[vec.elements - 1];
			}

			// 23.2.4.3 modifiers:
			void push_back(const T &x)
			{
				insert(end(), x);
			}
			
			void pop_back()
			{
				erase(end() - 1); 
			}
			
			iterator insert(iterator position, const T &x = T())
			{
				size_type n = position - begin();
				insert(position, (size_type)1, x);
				return begin() + n;
			}

			void insert(iterator position, size_type n, const T& x)
			{			
				size_type st = position - begin();
								
				if (capacity() <= size() + n) 
					reserve(capacity() * 2 + n);

				for (size_type i = vec.elements; i > st; i--)
					vec.offset[i] = vec.offset[i-1];

				vec.elements += n;
				while (n--) 
					vec.offset[st++] = x;
			}

			template <class InputIterator>
			void insert(iterator position, InputIterator first, InputIterator last)
			{
				int n = last - first;

				if (capacity() <= n + size()) {
					size_type st = position - begin();
					reserve(n + size() + 1);
					position = begin() + st;
				}

				while (n--) {
					insert(position++, 1, *(first++));
				}
			}
					
			iterator erase(iterator position)
			{
				for (iterator x = position  ; x < end() - 1; x++)
					*x = *(x + 1);
		
				vec.elements--;

				return position;				
			}
			
			iterator erase(iterator first, iterator last)
			{
				for (iterator x = last  ; x < end() - 1; x++)
					*first++ = *(x + 1);
				
				vec.elements -= last - first;
				
				return last;
			}
			
			void swap(vector<T,Allocator> &x)
			{
				Vec tmp = x.vec;
				x.vec = vec;
				vec = tmp;
			}
			
			void clear()
			{
				erase(begin(), end());
			}
	};

	template <class T, class Allocator>
	inline bool operator==(const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
	}
	template <class T, class Allocator>
	inline bool operator< (const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
	}
	template <class T, class Allocator>
	inline bool operator!=(const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return !(x == y);
	}
	template <class T, class Allocator>
	inline bool operator> (const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return y < x;
	}
	template <class T, class Allocator>
	inline bool operator>=(const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return !(x < y);
	}	
	template <class T, class Allocator>
	inline bool operator<=(const vector<T,Allocator> &x, const vector<T,Allocator> &y)
	{
		return !(y < x);
	}

	// specialized algorithms:
	template <class T, class Allocator>
	inline void swap(vector<T,Allocator>  &x, vector<T,Allocator>& y)
	{
		x.swap(y);
	}
	/*
	template <class Allocator = allocator<bool> > 
	class vector<bool,Allocator> : public vector<char>
	{
		public: 
			typedef bool                                      const_reference;
			typedef bool*                                     iterator;
			typedef const bool*                               const_iterator;
			typedef typename Allocator::size_type             size_type;
			typedef typename Allocator::difference_type       difference_type;
			typedef bool                                      value_type;
			typedef Allocator                                 allocator_type;
			typedef typename Allocator::pointer               pointer;
			typedef typename Allocator::const_pointer         const_pointer;
			typedef std::reverse_iterator<iterator>           reverse_iterator;
			typedef std::reverse_iterator<const_iterator>     const_reverse_iterator;
			
			class reference {
					friend class vector;
					reference();
				public:
					~reference();
					operator bool() const;
					reference& operator=(const bool x);
					reference& operator=(const reference& x);
					void flip();
			};
			
			// construct / copy / destroy
			explicit vector(const Allocator& = Allocator());
			explicit vector(size_type n, const bool& value = bool(), const Allocator& = Allocator());
			
			template <class InputIterator>
			vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
			
			vector(const vector<bool,Allocator>& x);
			~vector();
			vector<bool,Allocator>& operator=(const vector<bool,Allocator>& x);
			
			template <class InputIterator>
			void assign(InputIterator first, InputIterator last);
			
			void assign(size_type n, const T& t = T());
			
			allocator_type get_allocator() const;
			
			// iterators
			iterator               begin();
			const_iterator         begin() const;
			iterator               end();
			const_iterator         end() const;
			reverse_iterator       rbegin();
			const_reverse_iterator rbegin() const;
			reverse_iterator       rend();
			const_reverse_iterator rend() const;

			// capacity:
			size_type  size() const;
			size_type  max_size() const;
			void       resize(size_type sz, bool c = false);
			size_type  capacity() const;
			bool       empty() const;
			void       reserve(size_type n);

			// element access:
			reference       operator[](size_type n);
			const_reference operator[](size_type n) const;
			const_reference at(size_type n) const;
			reference       at(size_type n);
			reference       front();
			const_reference front() const;
			reference       back();
			const_reference back() const;

			// modifiers:
			void push_back(const bool& x);
			void pop_back();
			iterator insert(iterator position, const bool& x = bool());
			void     insert(iterator position, size_type n, const bool& x);
			
			template <class InputIterator>
			void insert (iterator position, InputIterator first, InputIterator last);
			
			iterator erase(iterator position);
			iterator erase(iterator first, iterator last);
			void swap(vector<bool,Allocator>& x);
			static void swap(reference x, reference y);
			void flip();  // flips all bits
			void clear();
	}; 

	template <class Allocator>
	inline bool operator==(const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return x.size() == y.size() && equal(x.begin(),x.end(),y.begin());
	}
	template <class Allocator>
	inline bool operator< (const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
	}
	template <class Allocator>
	inline bool operator!=(const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return !(x == y);
	}	
	template <class Allocator>
	inline bool operator> (const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return y < x;
	}
	template <class Allocator>
	inline bool operator>=(const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return !(x < y);
	}
	template <class Allocator>
	inline bool operator<=(const vector<bool,Allocator> &x, const vector<bool,Allocator> &y)
	{
		return !(y < x);
	}

	// specialized algorithms:
	template <class Allocator>
	inline void swap(vector<bool,Allocator> &x, vector<bool,Allocator> &y)
	{
		x.swap(y);
	}*/
}	

#endif
