/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2002?/X/X - 2014/01/20
/// 
/// @brief  メモリプール関連
/// 
/// ****************************************************************************

#pragma once

#include "CPL_Core_BlockPool.h"
#include "../Pointer/CPL_Core_Pointer.h"
#include "../Container/List/CPL_Core_DoublyList.h"
#include "../Container/Array/CPL_Core_StaticArray.h"
#include "../Container/List/CPL_Core_BinaryTree.h"



namespace CPL {
namespace Core {
namespace Memory {


// _____________________________________________________________________________
/// @brief メモリ取得用の簡易メモリマネージャ
///
// *****************************************************************************
class MemoryAlloc
  : public Core::BaseObject
{
private:
  U8* const m_ptr_top;
  U8* const m_ptr_end;
  U8*       m_ptr_pos;

public:
  void* Alloc( size_t in_size )
  {
    void* p = m_ptr_pos;
    if( m_ptr_pos + in_size <= m_ptr_end )
    {
      m_ptr_pos += in_size;
      return p;
    }
    else
    {
      return nullptr;
    }
  }

  void Reset()
  {
    m_ptr_pos = m_ptr_top;
  }

  size_t GetSize()
  {
    return m_ptr_pos - m_ptr_top;
  }

  MemoryAlloc( size_t in_size )
    : m_ptr_top( (U8*)::malloc( in_size ) )
    , m_ptr_end( m_ptr_top + in_size )
    , m_ptr_pos( m_ptr_top )
  {}
  ~MemoryAlloc()
  {
    ::free( m_ptr_top );
  }
};


const int MEMPOOl_DEf_MAx_NUm = 256;


// _____________________________________________________________________________
/// @brief メモリプール管理クラス
///
// *****************************************************************************
class MemoryPool
  : public Core::BaseObject
{
protected:
  struct PoolInfo {
    U8* m_ptr_end;
    U8  m_ptr_top[ sizeof(long) ];

    size_t GetSize()
    {
      return static_cast<size_t>((U8*)m_ptr_end - (U8*)m_ptr_top);
    }
  };

  using type_btree_poolinfo     = List::BinaryTree<PoolInfo*>;
  using type_btree_poolinfo_itr = type_btree_poolinfo::iterator;

  void*  m_ptr_alloc_top; // 
  void*  m_ptr_alloc_end;

  type_btree_poolinfo m_all_tree;     // 全ての分割領域
  type_btree_poolinfo m_free_tree;    // フリー領域のみ
  type_btree_poolinfo m_reserve_tree; // 予約領域のみ

//  long   m_max;
//  long   m_num;
  size_t m_size;

  PoolInfo* zzf_TopInfo()
  {
    return static_cast<PoolInfo*>(m_ptr_alloc_top);
  }

  PoolInfo* zzf_NextInfo( PoolInfo* in_ptr_info, size_t in_size )
  {
    return reinterpret_cast<PoolInfo*>(in_ptr_info->m_ptr_top + in_size);
  }

  bool  zzf_EnableInfo( PoolInfo* in_ptr_info )
  {
    return (in_ptr_info->m_ptr_top < m_ptr_alloc_end);
  }
  
  // フリー領域テーブルから検索
  type_btree_poolinfo_itr
    zzf_FindFreeArea
      ( size_t in_size
      , type_btree_poolinfo_itr in_itr_cache_begin
      , type_btree_poolinfo_itr in_itr_cache_end );
  type_btree_poolinfo_itr
    zzf_FindFreeArea( size_t in_size )
  {
    return
      zzf_FindFreeArea
        ( in_size
        , m_free_tree.begin()
        , m_free_tree.end() );
  }

  // 補正サイズを取得  ※ 渡す領域情報は、予約サイズが確保できることが前提
  size_t zzf_GetReviseSize( size_t in_alloc_size, PoolInfo* in_ptr_pool_info )
  {
    in_alloc_size = (in_alloc_size + 7) & ~7; // 8byte align
    return in_ptr_pool_info->GetSize() < in_alloc_size + sizeof(PoolInfo) ? in_ptr_pool_info->GetSize() : in_alloc_size;
  }

public:
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void*  New( size_t in_alloc_size );
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t Delete( void* in_ptr_del );
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t DeleteFirst();
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t DeleteLast();
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void   Refresh();

  // _____________________________________________________________________________
  /// @brief 確保サイズの取得。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t GetSize() const { return size_t((U8*)m_ptr_alloc_end - (U8*)m_ptr_alloc_top); }

  // _____________________________________________________________________________
  /// @brief 予約数の取得。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  size_t GetNum()  const { return m_reserve_tree.GetNum(); }
 
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  MemoryPool( size_t in_size, int in_num = 0 );
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ~MemoryPool();
};



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