//  memory : 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_MEMORY
#define __CPP_MEMORY

#include<cstddef>
#include<new>

#include<utility>
#include<iterator>

namespace std {

	// 20.4.1, the default allocator : 
	template <class T>
	class allocator
	{
		public:
			typedef size_t    size_type;
			typedef ptrdiff_t difference_type;
			typedef T*        pointer;
			typedef const T*  const_pointer;
			typedef T&        reference;
			typedef const T&  const_reference;
			typedef T         value_type;
			
			template <class U>
			struct rebind {
				typedef allocator<U> other; 
			};
		
			allocator() throw()
			{
			}
			
			allocator(const allocator& alloc) throw()
			{
			}
			
			template <class U>
			allocator(const allocator<U>& alloc) throw()
			{
			}

			~allocator() throw()
			{
			}
		
			pointer address(reference x) const
			{
				return &x;
			}
		
			const_pointer address(const_reference x) const
			{
				return &x;
			}
		
			// const void* should be : typename allocator<void>::const_pointer
			pointer allocate(size_type n, const void* hint = 0)	
			{
				return new T[n];
			}
			
			void deallocate(pointer p, size_type n)
			{
				delete [] p;
			}
			
			// NOT STANDARD, BUT USEFUL
			// NEWLY ALLOCATED OBJECTS AREN'T INITIALIZED
			// OLD OBJECTS AREN'T DESTROYED.
			void reallocate(pointer &p, size_type o, size_type n)
			{
				pointer tmp = new T[n];
				for (size_type x = 0;x < o ;x++)
					tmp[x] = p[x];
				delete [] p;
				p = tmp;
			}

			size_type max_size() const throw(); // TODO 
		
			// ONLY 1 ARGUMENT 
			// NOT STANDARD !!! second argument should be : const T& val
			void construct(pointer p)
			{
				p = new T();
			}
			
			void construct(pointer p, const T& val)
			{
				p = new T(val);
			}


			void destroy(pointer p)
			{
				((T*)p)->~T();
			}

	};
		
	template <> 
	class allocator<void>
	{
		public:
			typedef void*       pointer;
			typedef const void* const_pointer;
			typedef void        value_type;
			
			template <class U> 
			struct rebind 
			{ 
				typedef allocator<U> other; 
			};  		
	};

	template <class T, class U>
	inline bool operator==(const allocator<T> &x, const allocator<U> &y) throw()
	{
		return true;
	}
	
	template <class T, class U>
	inline bool operator!=(const allocator<T> &x, const allocator<U> &y) throw()
	{
		return !(x == y);
	}

	// 20.4.2, raw storage iterator
	
	template <class OutputIterator, class T> 
	class raw_storage_iterator : public iterator<output_iterator_tag, void, void, void, void>
	{
		public:
		
			explicit raw_storage_iterator(OutputIterator x) : out(x)
			{
			}
			
			raw_storage_iterator<OutputIterator,T>& operator*()
			{
				return *this;
			}
			
			raw_storage_iterator<OutputIterator,T> &operator=(const T& element)
			{  
				T* pp = &*out;
				new (pp) T(element);
				return p;
			}
			
			raw_storage_iterator<OutputIterator,T> &operator++()
			{
				return ++p;
			}
			
			raw_storage_iterator<OutputIterator,T>  operator++(int)
			{
				return p++;
			}
		private:
			OutputIterator out;
	};
	
	// 20.4.3, temporaty buffers :
	template <class T>
	pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n)
	{
		T *p;
		for (p = 0; 0 < n; n /= 2)
			if ((p = (T *)operator new (n * sizeof (T), nothrow)) != 0)
				break;
		return pair<T*,ptrdiff_t>(p, n);
	}
	
	template <class T>
	void return_temporary_buffer(T* p)
	{
		delete [] p;
	}
	
	// 20.4.4, specialized algorithms: 
	template <class InputIterator, class ForwardIterator>
	ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)
	{
		while (first != last)
			new (static_cast<void *>(&*result++)) typename iterator_traits<ForwardIterator>::value_type (*first++);
		return result;
	}
	
	template <class ForwardIterator, class T>
	void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x)
	{
		while (first != last)
			new (static_cast<void *>(&*first++)) typename iterator_traits<ForwardIterator>::value_type(x);
	}
	
	template <class ForwardIterator, class Size, class T>
	void uninitialized_fill_n(ForwardIterator first, Size n, const T& x) 
	{
		while (n--)
			new (static_cast<void *>(&*first++)) typename iterator_traits<ForwardIterator>::value_type(x);
	}

	// 20.4.5, pointers:
	template<class X> 
	class auto_ptr
	{
		template <class Y>
		struct auto_ptr_ref
		{
			auto_ptr<Y>& ref;
			
			auto_ptr_ref(auto_ptr<Y>& x)
			{
				ref = x;
			}
		};
		
		public:
			typedef X element_type;

			// 20.4.5.1 construct / copy / destroy :
			explicit auto_ptr(X* p = 0) throw() 
			: ptr(p) 
			{
			}

			auto_ptr(const auto_ptr& y) throw()
			{
				ptr = y.release();
			}

			template<class Y>
			auto_ptr(const auto_ptr<Y> &y) throw()
			{
				ptr = (X*) y.release();
			}

			auto_ptr& operator=(const auto_ptr& y) throw()
			{
				reset(y.release());
				return *this;
			}

			template<class Y> 
			auto_ptr& operator=(const auto_ptr<Y>& y) throw()
			{
				reset((X*)y.release());
				return *this;
			}

			~auto_ptr() throw()
			{
				if (get() != 0)
					delete get();
			}

			// 20.4.5.2 members: 
			X& operator*() const throw()
			{
				return *get();
			}

			X* operator->() const throw()
			{
				return get();
			}

			X* get() const throw()
			{
				return ptr;
			}

			X* release() const throw()
			{
				X* tmp = ptr;
				ptr = 0;
				return tmp;
			}

			void reset(X* p = 0) throw()
			{
				if (get() != p) {
					delete get();
					ptr = p;
				}
			}

			// 20.4.5.3 conversions:
			auto_ptr(auto_ptr_ref<X> r) throw()
			{
				ptr = r.ref.release();
			}

			template<class Y>
			operator auto_ptr_ref<Y>() throw()
			{
				return auto_ptr_ref<Y>(*this);
			}

			template<class Y>
			operator auto_ptr<Y>() throw()
			{
				auto_ptr_ref<Y> aptr(*this);
				release();
				return aptr;
			}
	 	private:
			X* ptr;
	};
}

#endif
