#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2015/04/06 - 2015/04/06
/// 
/// @brief  特定型アロケータ
/// 
/// ****************************************************************************

#include <deque>
#include "CPL_Core_Allocator.h"

namespace CPL {
namespace Core {
namespace Memory {

// _____________________________________________________________________________
/// @brief 特定型アロケータ
///
// *****************************************************************************
template<class T>
class TypeBlockAllocator
{
public:
  using size_type       = size_t;
  using difference_type = ptrdiff_t;
  using pointer         = T*;
  using const_pointer   = T const*;
  using reference       = T&;
  using const_reference = T const&;
  using value_type      = T;
  template <class U>
  struct rebind { typedef TypeBlockAllocator<U> other; };

  pointer Allocate()
  {
    return zzf_alloc_();
  }

	template<class T_Obj, class... Types>
	T_Obj* Construct( T_Obj* p, Types&&... args )
	{
		::new((void*)p) T_Obj( std::forward<Types>(args)... );
    return p;
	}

  template<class... Types>
  pointer New( Types&&... args )
  {
    return Construct( Allocate(), std::forward<Types>(args)... );
  }

  bool Deallocate( pointer p )
  {
    return zzf_deallocate_( p );
  }

private:
  struct zzc_area_ { char n[sizeof(value_type) ]; };
  pointer zzf_alloc_()
  {
    m_deque_data.resize( m_deque_data.size() + 1 );
    m_deque_data.push_back( &m_deque_data.back() );
    return reinterpret_cast<pointer>( m_deque_handle.back() );
  }

  bool zzf_deallocate_( pointer p )
  {
    auto res_hit = std::find( m_deque_handle.begin(), m_deque_handle.end(), p );
    if( res_hit == m_deque_handle.end() )
    {
      return false;
    }
    return res_hit - m_deque_handle.begin();
  }

  std::deque<zzc_area_>  m_deque_data;
  std::deque<zzc_area_*> m_deque_handle;
};


} // namespace Memory
} // namespace Core
} // namespace CPL
