#pragma once
#include "nstd_prefix.h"

namespace nstd {

	///////////////////////////////////////////////////////////////////////////////////////////////
	template< typename _Tx, typename _Ty > 
	inline void ConstructIt( _Tx* _ptr, _Ty const& _val ) {
		::new (_ptr) _Tx( _val );
	}
	template<class _Ty> 
	inline void DestroyIt( _Ty* _ptr ) { (_ptr)->~_Ty(); }

	template<> inline void DestroyIt( char* ) {}
	template<> inline void DestroyIt( wchar_t* ) {}
	template<> inline void DestroyIt( int* ) {}
	template<> inline void DestroyIt( unsigned* ) {}



	///////////////////////////////////////////////////////////////////////////////////////////////
	template< typename T > struct Array {
		T *mBegin, *mEnd;
		typedef T* iterator;
		typedef T* const_iterator;
		
		Array( T* theBegin, T* theEnd ) : mBegin(theBegin), mEnd(theEnd) {}
		Array( T* theBegin, size_t theSize ) : mBegin(theBegin), mEnd(theBegin+theSize) {}
		
		size_t size() const { return (mEnd-mBegin); }
		iterator begin() const { return mBegin; }
		iterator end() const { return mEnd; }
		iterator cbegin() const { return mBegin; }
		iterator cend() const { return mEnd; }
		
		T & operator[]( unsigned i ) { ASSERT(i<size()); return mBegin[i]; }
		T const& operator[]( unsigned i ) const { ASSERT(i<size()); return mBegin[i]; }
	};

    ///////////////////////////////////////////////////////////////////////////////////////////////
	template< typename T > 
	struct ArrayNC : public Array<T> {
		ArrayNC( T* theBegin, T* theEnd ) : Array(theBegin,theEnd) {}
		ArrayNC( T* theBegin, size_t theSize ) : Array(theBegin,theSize) {}
		
		template<typename _Ty> void push_back( _Ty const& _val ) {
			ConstructIt( mEnd++, _val );
		}
	};
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class _Ty> 
	struct _Allocator_base { typedef _Ty value_type; };
	template<class _Ty> 
	struct _Allocator_base<const _Ty> { typedef _Ty value_type; };

	template < typename _Ty, int N > 
	class FixedAllocator : public _Allocator_base<_Ty> {
		enum { nRawSize_ = sizeof( _Ty )*N };
		char pRawBuffer_[ nRawSize_ ]; int nAllocated_;
	public:
		typedef _Allocator_base<_Ty> _Mybase;
		typedef typename _Mybase::value_type value_type;
		typedef value_type* pointer;
		typedef value_type& reference;
		typedef const value_type*const_pointer;
		typedef const value_type& const_reference;

		typedef size_t size_type;
		typedef ptrdiff_t difference_type;

		template<class _Other> struct rebind { typedef FixedAllocator<_Other,N> other; };

		FixedAllocator() : nAllocated_( 0 ) {}

		FixedAllocator(const FixedAllocator<_Ty,N>&) : nAllocated_( 0 ) {}
		FixedAllocator(const char*) : nAllocated_( 0 ) {}

		template<class _Other>
		FixedAllocator(const FixedAllocator<_Other,N>&) {}

		template<class _Other>
		FixedAllocator<_Ty,N>& operator=(const FixedAllocator<_Other,N>&) {return (*this); }

		static pointer address( reference _val ) { return (&_val); }
		static const_pointer address( const_reference _val ) { return (&_val); }

		void deallocate( pointer _ptr, size_type theCount ) { 
			int aSize = (int)( theCount*sizeof(_Ty) );
			ASSERT( _ptr==(void const*)(&pRawBuffer_[ nAllocated_ - aSize ] ) ); 
			nAllocated_-=aSize; 
		}
		pointer allocate( size_type theCount ) { 
			ASSERT( theCount*sizeof( _Ty ) + nAllocated_<=nRawSize_ );
			void* aPtr = &pRawBuffer_[ nAllocated_ ]; 
			nAllocated_ += (int)( theCount*sizeof( _Ty ) );
			return (_Ty*)( aPtr );
		}

		pointer allocate( size_type theCount, const void* ) { return allocate( theCount ); }
		static void construct( pointer _ptr, _Ty const& _val ) { ConstructIt( _ptr, _val ); }
		static void destroy( pointer _ptr ) { DestroyIt( _ptr ); }
		static size_t max_size() { return (size_t)(nRawSize_)/sizeof(_Ty); }
		bool operator==( FixedAllocator const& ) const { return true; }
		bool operator!=( FixedAllocator const& ) const { return false; }
	};

    ///////////////////////////////////////////////////////////////////////////////////////////////
	template < class T, int N > 
    class FixedVector : public vector< T, FixedAllocator< T, N > > {
	public:	
		FixedVector() { this->reserve(N); }
	};

	
}

