//
// Copyright (C) 2008, 2009 Francesco Salvestrini
//
// 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 of the License, or
// (at your option) any later version.
//
// 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.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

#ifndef ELKLIB_LIBCXX_MEMORY
#define ELKLIB_LIBCXX_MEMORY

#include "elklib.h"
#include "libc++/new"

namespace ktl {
	template <class T> class allocator;

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

	template <class T> class allocator {
	public:
		typedef T         value_type;
		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;

		pointer       address(reference r) const       { return &r; }
		const_pointer address(const_reference r) const { return &r; }

		allocator() throw() { }
		template <class U> allocator(const allocator<U> &) throw();
		~allocator() throw() { }

		pointer allocate(size_type n,
				 typename allocator<void>::const_pointer = 0) {
			return (T *)(::operator new(n * sizeof(T)));
		}

		void deallocate(pointer p,
				size_type) {
			::operator delete(p);
		}

		void construct(pointer   p,
			       const T & val) {
			new((void*) p) T(val);
		}

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

		size_type max_size() const throw();

		template<class U> struct rebind {
			typedef allocator<U> other;
		};
	};

	template <class T> class auto_ptr {
	private:
		T * object;

	public:
		typedef T element_type;

		explicit auto_ptr(T * p=0) throw() : object(p) {
		}

		auto_ptr(const auto_ptr & p) throw() : object(p.release()) {
		}

		template<class Y> auto_ptr(const auto_ptr<Y> & p) throw() :
			object(p.release()) {
		}

		auto_ptr & operator=(const auto_ptr & p) throw() {
			if (&p == this) {
				return *this;
			}
			delete get();
			object = p.release();
			return *this;
		}

		template<class Y> auto_ptr &
		operator=(const auto_ptr<Y> & p) throw() {
			if (&p == this) {
				return *this;
			}
			delete get();
			object = p.release();
			return *this;
		}

		~auto_ptr() {
			delete get();
		}

		T & operator*() const throw() {
			return *get();
		}

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

		T * get() const throw() {
			return object;
		}

		T * release() const throw() {
			T * temp(object);
			object = 0;
			return temp;
		}

		void reset(T * p = 0) throw() {
			if (p != object) {
				delete object;
				object = p;
			}
		}
	};
}

#endif // ELKLIB_LIBCXX_MEMORY
