
/*!
@author d金魚
@since 2003/9/26
@note
参考サイト:<br>
http://www.nantekotta.com/<br>
*/
#ifndef _dkutil_allocator__
#define _dkutil_allocator__




#define DKUTIL_BAKAMON "ERROR:バカﾓﾝ！NULLのポインタを渡して開放しようとするな！"




namespace dkutil{

template<class T>
struct dkutil_allocator_base{
	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 Tt_> 
	Tt_ * _Allocate( size_type size, Tt_ * )
	{
		//if( size < 0 ) size = 0;
		Tt_ * pT = ( Tt_ * ) operator new( size * sizeof( Tt_ ) );
		return pT;
	}
	void _Deallocate( pointer p, size_type n = 0)
	{
		operator delete(p);
	}

	T *allocate_base(size_type n, const void *hint)
	{
		return (pointer)(operator new(n * sizeof(T)));
	}
	

	template<class T1, class T2>
	void _Construct( T1 * pT1, const T2 & rT2 )
	{
		new ( ( void * ) pT1 ) T1( rT2 );
	}

	char * _Charalloc( size_type size )
	{
		T * pT = _Allocate( size, ( char * ) 0 );
		return pT;
	}

	template<class Ty_>
	void _Destroy( Ty_ *p )	{		p->~Ty_(); 	}

};


/*!
後々、機能強化が図られる予定です。
(例えば、メモリリークチェック機能とか。<br>
まぁ、メモリリークチェックはしょぼいが、
MemoryLeakCheckAllocator() (STLに対応していない)がある。
(あまりお勧めできないなぁ)、
*/


template <class T > 
class dkutil_allocator : public dkutil_allocator_base<T>{
public:

  template <class U>
		struct rebind { typedef dkutil_allocator<U> other; };
	
		pointer       address(reference x) const
    { return &x; }
  const_pointer address(const_reference x) const
    { return &x; }
  pointer       allocate(size_type n, const void* hint = 0) {
    //cout << "allocate " << n << " of " << typeid(T).name() << endl;
    //return a.allocate(n * sizeof(value_type));//new(n * sizeof(value_type));
		
		//dkutil_allocator_base
		return _Allocate(n, ( pointer ) 0 );
		
	}
  void deallocate(pointer p, size_type n = 0) {
    //cout << "deallocate " << n << " of " << typeid(T).name() << endl;
    //if( (p == 0) == (n == 0) ) MB("WHAT!!! deallocate error");
		if(p==NULL){
			
			//DEBUGASSERT(!DKUTIL_BAKAMON);
			//DEBUGMB("WHAT!!! deallocate error please break.!!");
		}
		_Deallocate(p);
    //a.deallocate(p);
  }
  size_type max_size() const
    { return (size_t)-1 / sizeof(T); }
  void construct(pointer p, const T& val) {
    //cout << "construct " << typeid(T).name()<< '(' << val << ')' << endl;
    new ((void*)p) T(val);
  }
  void destroy(pointer p) {
   // cout << "destroy " << typeid(T).name() << endl;
		((T*)p)->~T();
  }


	//STLPort用

	///私の環境ではSTLPort4.5.3ではこれが必要です。
	template <class _Tp1, class _Tp2>
		inline dkutil_allocator<_Tp2>& __stl_alloc_rebind(dkutil_allocator<_Tp1>& __a, const _Tp2*) 
	{
		return (dkutil_allocator<_Tp2>&)(__a);
	}
	///STLPortではこれも必要だと思います。
	template <class _Tp1, class _Tp2>
	inline dkutil_allocator<_Tp2> __stl_alloc_create(
			const dkutil_allocator<_Tp1>&, const _Tp2*
	){ 
		return dkutil_allocator<_Tp2>(); 
	}


};



//template <class T, class U>
//bool operator!=(const my_allocator<T>& a,const my_allocator<U>& b);


template<class T>
class throw_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 throw_allocator<U> other; };

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

	throw_allocator(){}
	throw_allocator(const throw_allocator<T> &){}
	template<class T2> throw_allocator<T>& operator=(const throw_allocator<T2> &){}
	pointer allocate(size_type n, const void *hint){
		pointer p = (pointer)(operator new(n * sizeof(T)));
		if(!p){ throw std::bad_alloc();}
	}
	char* _Charalloc(size_type n) {
    return allocate(n);
  }
	void deallocate(pointer p, size_type n){
		if(!p){DEBUGMB(DKUTIL_BAKAMON );}
		operator delete(p); 
	}
	void construct(pointer p, const T& val){
		new ((void *)p) T(val); 
	}
	void destroy(pointer p){
		p->~T(); 
	}
	size_type max_size() const{
		size_type c = (size_type)(-1) / sizeof(T);
		return (0<c ? c : 1);
	}


	///私の環境ではSTLPort4.5.3ではこれが必要です。
	template <class _Tp1, class _Tp2>
		inline throw_allocator<_Tp2>& __stl_alloc_rebind(throw_allocator<_Tp1>& __a, const _Tp2*) 
	{
		return (throw_allocator<_Tp2>&)(__a);
	}
	///STLPortではこれも必要だと思います。
	template <class _Tp1, class _Tp2>
	inline throw_allocator<_Tp2> __stl_alloc_create(
			const throw_allocator<_Tp1>&, const _Tp2*
	){ 
		return throw_allocator<_Tp2>(); 
	}
};


}//end of dkutil namespace

#undef DKUTIL_BAKAMON 

#endif//end of include once