#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2002/X/X - 2016/02/02
/// 
/// @brief  メモリ割り当て管理
/// 
/// ****************************************************************************


// CPL_ALLOC_MAXSIZE        最大確保サイズ
// CPL_ALLOC_MAXNUM         最大確保回数
// CPL_ALLOC_BACKUP_INFO    デバッグ情報を保存するかどうか
// CPL_UN_ALLOC_INFO_SIZE   サイズ情報を保持するかどうか
// CPL_UN_ALLOC_INFO_FILE   確保したソースの名前と位置
// CPL_UN_ALLOC_INFO_COUNT  何回目に呼ばれたか


#include <memory.h>
#include <malloc.h>

#include "../Base/CPL_Core_Define.h"
#include "../Base/CPL_Core_Thread.h"
#include "../Base/CPL_Core_Cast.h"

#include "../../CPL_Setup.h"


namespace CPL{

  // _____________________________________________________________________________
  /// @brief プライベートコンストラクタ呼び出し用クラス。
  ///
  /// CPL_NEWやCPL_MAKE_SHAREDでオブジェクトを生成する場合、このクラスをfriendにすること。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>
  class CallPrivateConstructor
  {
  public:
	  static void Call(T* p)
		{
		  ::new ((void*)p) T();
		}

	  static void Call(T* p, const T& val)
		{
		  ::new ((void*)p) T(val);
		}

	  template<class Tx, class... Params>
		static void Call( Tx *p, Params&&... args )
		{
      // ここでエラーが出た場合、コンストラクタ呼び出しの引数が間違っている可能性があります。
		  ::new ((void*)p) Tx(std::forward<Params>(args)...);
		}
  };

namespace Core {
namespace Memory {
  void allocate_dump();

  void*
    Allocator
      ( size_t         in_size
      , ThreadMutex<>* in_critical_section
      , const char*    in_file_name
      , int            in_line
      );
  void
    Deleter
      ( void*          io_ptr
      , ThreadMutex<>* in_critical_section
      );

  void*
    MemCopy
      ( void*       out_buf0
      , const void* in_buf1
      , size_t      in_copy_size
      );

  inline Core::ThreadMutex<>* AllocCS()
  {
    static Core::ThreadMutex<> cs;
    return &cs;
  };


  // _____________________________________________________________________________
  /// @brief CorePLi用カスタムアロケータ
  ///
  // *****************************************************************************
  template<class T_Type>
  class CustomNew
  {
    using type_this = CustomNew<T_Type>;
    using type      = typename std::remove_extent<T_Type>::type;
    using type_ptr  = type*;

    char*       m_addr;
    size_t      m_num;
    const char* m_file_name;
    int         m_line ;
    bool        m_flag_alloc; // 領域確保済みフラグ。
    bool        m_flag_init;  // コンストラクタコール済みフラグ。

    //
    type_ptr get(){ return reinterpret_cast<type_ptr>(m_addr + 8); }
    size_t   get_num() const { return *(size_t*)m_addr; }
    void     set_num( size_t n ){ *(size_t*)m_addr = n; }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 領域確保。
    void alloc_( size_t in_num )
    {
      if( m_flag_alloc )
        return;
      // 確保
      const size_t size = sizeof(T_Type) * in_num + 8;
      m_addr = static_cast<char*>(Allocator( size, AllocCS(), m_file_name, m_line ));
      set_num( in_num );
      m_flag_alloc = true;
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // コンストラクタ呼び出し。
    template<class... T_Params>
    void ctor_( T_Params&&... in_args )
    {
      if( m_flag_init )
        return;

      for( type_ptr p = get(), end = get() + get_num(); p < end; ++p )
      {
        try {
          CallPrivateConstructor<T_Type>::Call
            ( p
            , std::forward<T_Params>(in_args)...
            );
          // コンストラクタ呼び出し済みフラグON.
          m_flag_init = true;
        }
        catch(...)
        {
          // 既に処理したオブジェクトのデストラクタ呼び出し。
          for( type_ptr p_ = get(); p_ < p; ++p_ )
          {
            p_->~type();
          }
          throw; // 受け取った例外をそのまま投げよう。
        }
      }
    }

  public:
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // キャスト（最後に必ず呼ばれる）
    operator type_ptr()
    {
      try {
        alloc_( 1 );
        ctor_();
      }
      catch(...)
      {
        // 確保メモリを解放。
        Deleter( m_addr, AllocCS() );
        throw; // 受け取った例外をそのまま投げよう。
      }

      return get();
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // コンストラクタ。
    // この時点では領域を確保しない。
    CustomNew
    ( const char* in_file_name
    , int         in_line )
      : m_addr( nullptr )
      , m_num( 1 )
      , m_file_name( in_file_name )
      , m_line( in_line )
      , m_flag_alloc( false )
      , m_flag_init( false )
    {
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 関数呼び出し演算子のオーロード。
    // コンストラクタ初期化っぽいインターフェイス提供のため。
    template<class... T_Params>
    type_ptr operator()( T_Params&&... args )
    {
      try {
        alloc_( 1 );
        ctor_( std::forward<T_Params>(args)... );
      }
      catch(...)
      {
        // 確保メモリを解放。
        Deleter( m_addr, AllocCS() );
        throw; // 受け取った例外をそのまま投げよう。
      }
      return get();
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 添字演算子のオーロード。
    // 配列宣言用。
    template<class N>
    type_ptr operator[]( N in_num )
    {
      try {
        alloc_( in_num );
        ctor_();
      }
      catch(...)
      {
        // 確保メモリを解放。
        Deleter( m_addr, AllocCS() );
        throw; // 受け取った例外をそのまま投げよう。
      }
      return get();
    }

  };

  // _____________________________________________________________________________
  /// @brief カスタムデアロケータ
  ///
  // *****************************************************************************
  template<class T_Type>
  void CustomDelete( T_Type* in_ptr )
  {
    if( in_ptr == nullptr )
      return;
    auto p = in_ptr;
    void* addr = (((char*)p) - 8);
    size_t num = *(size_t*)addr;
    CPL_LOOP( num )
    {
      p->~T_Type();
      ++p;
    }
    Deleter( addr, AllocCS() );
  }

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



#ifdef CPL_DBGSW_ALLOCATOR

#ifndef CPL_ALLOC_MAXSIZE
#define CPL_ALLOC_MAXSIZE (1024*1024*256)
#endif

#ifndef CPL_ALLOC_MAXNUM
#define CPL_ALLOC_MAXNUM  (1024*2)
#endif



#define CPL_NEW(type)\
  (type*)CPL::Core::Memory::CustomNew<type>(__FILE__,__LINE__)
#define CPL_NEW2(type,file,line)\
  (type*)CPL::Core::Memory::CustomNew<type>(file,line)

#define CPL_DELETE(p)\
  CPL::Core::Memory::CustomDelete( p )
#define CPL_DELETE_ARR(p)\
  CPL::Core::Memory::CustomDelete( p )

#ifdef CPL_DBGSW_MEMCPY
#define CPL_MEMCPY CPL::Core::Memory::MemCopy
#else
#define CPL_MEMCPY memcpy
#endif


//inline void*  operator new  ( size_t size ){ return CPL::Core::Memory::Allocator( size, CPL::Core::Memory::AllocCS(), __FILE__, __LINE__ ); }
//inline void*  operator new[]( size_t size ){ return CPL::Core::Memory::Allocator( size, CPL::Core::Memory::AllocCS(), __FILE__, __LINE__ ); }
//inline void*  operator new  ( size_t size, void cpl_cv* io_ptr ){ return (void*)io_ptr; }
//inline void*  operator new[]( size_t size, void cpl_cv* io_ptr ){ return (void*)io_ptr; }
//inline void*  operator new  ( size_t size, const char* filename, int line ){ return CPL::Core::Memory::Allocator( size, CPL::Core::Memory::AllocCS(), filename, line ); }
//inline void*  operator new[]( size_t size, const char* filename, int line ){ return CPL::Core::Memory::Allocator( size, CPL::Core::Memory::AllocCS(), filename, line ); }
//inline void   operator delete  ( void* in_ptr ){ CPL::Core::Memory::Deleter( in_ptr, CPL::Core::Memory::AllocCS() ); }
//inline void   operator delete[]( void* in_ptr ){ CPL::Core::Memory::Deleter( in_ptr, CPL::Core::Memory::AllocCS() ); }
//inline void   operator delete  ( void* in_ptr, void cpl_cv* io_ptr ){}
//inline void   operator delete[]( void* in_ptr, void cpl_cv* io_ptr ){}
//inline void   operator delete  ( void* in_ptr, const char* in_file_name, int line ){ CPL::Core::Memory::Deleter( in_ptr, CPL::Core::Memory::AllocCS() ); }
//inline void   operator delete[]( void* in_ptr, const char* in_file_name, int line ){ CPL::Core::Memory::Deleter( in_ptr, CPL::Core::Memory::AllocCS() ); }



#else  // CPL_DBGSW_ALLOCATOR
  #define CPL_NEW(type) new type
  #define CPL_NEW2(type,file,line) new type
  #define CPL_DELETE(p) delete p
  #define CPL_DELETE_ARR(p) delete[] p;

  #define CPL_MEMCPY memcpy
  //inline void operator delete( void const* in_ptr )
  //{
  //  operator delete( const_cast<void*>(in_ptr) );
  //}
  //inline void volatile* operator new  ( size_t size, void volatile* io_ptr ){ return io_ptr; }
  //inline void volatile* operator new[]( size_t size, void volatile* io_ptr ){ return io_ptr; }
  //inline void           operator delete( void cpl_cv* in_ptr );
  //inline void           operator delete[]( void cpl_cv* in_ptr );

#endif // CPL_ALLOCATOR

//void* operator new  ( size_t size, CPL::CriticalSection* in_pCS );
//void* operator new[]( size_t size, CPL::CriticalSection* in_pCS );
//void  operator delete  ( void* in_ptr, CPL::CriticalSection* in_pCS );
//void  operator delete[]( void* in_ptr, CPL::CriticalSection* in_pCS );

namespace CPL {

// _____________________________________________________________________________
/// @brief delete
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Pointer> inline
void DEL( T_Pointer in_ptr )
{
  if( in_ptr )
  {
    CPL_DELETE( &*in_ptr );
  }
}

// _____________________________________________________________________________
/// @brief 設定有りdelete
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Pointer> inline
void DEL( T_Pointer& io_ptr, T_Pointer in_set_data )
{
  if( io_ptr )
  {
    T_Pointer del_ptr = &*io_ptr;
    io_ptr = in_set_data;
    CPL_DELETE( del_ptr );
  }
}

// _____________________________________________________________________________
/// @brief 設定有りdelete  ※ volatile仕様
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Pointer> inline
void DEL( T_Pointer volatile& io_ptr, T_Pointer in_set_data )
{
  if( io_ptr )
  {
    T_Pointer del_ptr = &*io_ptr;
    io_ptr = in_set_data;
    CPL_DELETE( del_ptr );
  }
}


// _____________________________________________________________________________
/// @brief nullptr設定有りdelete
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Pointer> inline
void DEL_CLEAR( T_Pointer& io_ptr )
{
  if( io_ptr )
  {
    T_Pointer del_ptr = &*io_ptr;
    io_ptr = nullptr;
    CPL_DELETE( del_ptr );
  }
}


// _____________________________________________________________________________
/// @brief nullptr設定有りdelete  ※ volatile仕様
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Pointer> inline
void DEL_CLEAR( T_Pointer volatile& io_ptr )
{
  if( io_ptr )
  {
    T_Pointer del_ptr = &*io_ptr;
    io_ptr = nullptr;
    CPL_DELETE( del_ptr );
  }
}



// _____________________________________________________________________________
/// @brief delete (CPL専用イテレータ仕様)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Type> inline
void DEL_ITR( T_Type& in_itr )
{
  CPL_DELETE( &*in_itr );
}


// _____________________________________________________________________________
/// @brief 設定有りdelete（CPL専用イテレータ仕様）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Type> inline
void DEL_ITR( T_Type& in_itr, T_Type in_set )
{
  CPL_DELETE( &*in_itr );
  in_itr = in_set;
}



// _____________________________________________________________________________
/// @brief delete[]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Type> inline
void DEL_ARR( T_Type* in_ptr )
{
  CPL_DELETE_ARR( in_ptr );
}


// _____________________________________________________________________________
/// @brief クリア有りdelete[]
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Type> inline
void DEL_ARR( T_Type*& in_ref_ptr, T_Type* in_set )
{
  CPL_DELETE_ARR( in_ref_ptr );
  in_ref_ptr = in_set;
}


// _____________________________________________________________________________
/// @brief ->Release()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T_Type> inline
void RELEASE( T_Type& o )
{
  if(o!=nullptr){ o->Release(); o = nullptr; }
}



namespace Core {
  namespace Memory {
    // =============================================================================
    // 基底デリータ
    class baseDeleter {
    public:
      virtual ~baseDeleter(){}
      virtual void operator()( void_cptr cp ) const = 0;
      virtual void operator()( void_cvptr cvp ) cpl_cv = 0;
    };

    // =============================================================================
    // newデリータ
    template<class T_Type>
    struct NewDeleter
      : public baseDeleter
    {
      // delete : const
      void operator()( void_cptr p ) const
      {
        CPL_DELETE( static_cast<T_Type const*>( p ) );
      }
      // delete : const volatile
      void operator()( void_cvptr p ) const volatile
      {
        CPL_DELETE( static_cast<T_Type cpl_cv*>( p ) );
      }


      // static cast : normal
      template<class T> T* StaticCast( void* p ) noexcept
      {
        return static_cast<T*>( static_cast<T_Type*>(p) );
      }
      // static cast : volatile
      template<class T> T* StaticCast( void volatile* p ) volatile noexcept
      {
        return static_cast<T*>( static_cast<T_Type volatile*>(p) );
      }

      // 静的削除用
      static void Call( T_Type*& p, T_Type* set )
      {
        T_Type* del_ptr = p;
        p = set;
        CPL_DELETE( del_ptr );
      }
      // 静的削除用 : volatile仕様
      static void Call( T_Type*volatile& p, T_Type* set )
      {
        T_Type* del_ptr = p;
        p = set;
        CPL_DELETE( del_ptr );
      }

    //  static void* operator new( size_t size, void* buf ){ return buf; }
    //  static void  operator delete( void* p ){}
    };

    // =============================================================================
    // new[]デリータ
    template<class T_Type>
    struct NewDeleterArr
      : public baseDeleter
    {
      // delete[]
      void operator()( void_cptr p ) const {
        CPL_DELETE_ARR( static_cast<T_Type const*>( p ) );
      }
      // delete[]  ※ volatile仕様
      void operator()( void_cvptr p ) cpl_cv {
        CPL_DELETE_ARR( static_cast<T_Type cpl_cv*>( p ) );
      }
  
      // static cast
      template<class T> T* StaticCast( void_ptr p ) noexcept
      {
        return static_cast<T*>( static_cast<T_Type*>(p) );
      }
      // static cast  ※ volatile仕様
      template<class T> T* StaticCast( void_vptr p ) noexcept
      {
        return static_cast<T*>( static_cast<T_Type*>(p) );
      }

      // 静的削除用
      static void Call( T_Type*& p, T_Type* set )
      {
        T_Type* del_ptr = p;
        p = set;
        CPL_DELETE_ARR( del_ptr );
      }
      // 静的削除用　※volatile仕様
      static void Call( T_Type*volatile& p, T_Type* set )
      {
        T_Type* del_ptr = p;
        p = set;
        CPL_DELETE_ARR( del_ptr );
      }
  
    //  static void* operator new( size_t size, void* buf ){ return buf; }
    //  static void  operator delete( void* p ){}
    };


    //// =============================================================================
    //// Release
    //template<class T_Type>
    //struct ComDeleter
    //{
    //  void operator()( void* p, T_Type* set )
    //  {
    //    T_Type* del_ptr = static_cast<T_Type*>(p);
    //    ptr = set;
    //    del_ptr->Release();
    //  }
    //};

  }// namespace Memory


/// @cond
  namespace zzz_
  {
    // *****************************************************************************
    template<class T_Type>
    class alloc_ex
      : public std::allocator<T_Type>
    {
    private:
      using type_base = std::allocator<T_Type>;
      using type_this = alloc_ex<T_Type>;

#ifdef CPL_DBGSW_ALLOCATOR
      char_cptr m_file_name;
      int       m_line;
    public:
      template<class... T_Params>
      alloc_ex( char_cptr in_file_name, int in_line, T_Params&&... args )
        : type_base( std::forward<T_Params>(args)... )
        , m_file_name( in_file_name )
        , m_line( in_line )
      {}

	    T_Type* allocate( size_t in_size )
		  {
		    return (T_Type*)Allocator( in_size, Memory::AllocCS(), m_file_name, m_line );
		  }

	    T_Type* allocate( size_t in_size, const void* )
		  {
		    return (T_Type*)Allocator( in_size, Memory::AllocCS(), m_file_name, m_line );
		  }

	    void deallocate( T_Type* p, size_t )
		  {
		    Memory::NewDeleter<T_Type>()( p );
		  }
#else
    public:
      template<class... T_Params>
      alloc_ex( T_Params&&... args )
        : type_base( std::forward<T_Params>(args)... )
      {}
#endif

	    void construct( T_Type* p )
		  {
		    CallPrivateConstructor<T_Type>::Call( p );
		  }

	    void construct( T_Type* p, T_Type const& val )
		  {
		    CallPrivateConstructor<T_Type>::Call( p, val );
		  }

	    template<class Tx, class... Params>
		  void construct( Tx* p, Params&&... args )
		  {
        CallPrivateConstructor<T_Type>::Call( p, std::forward<Params>(args)... );
		  }
    };


    // *****************************************************************************
    template<class T_Type>
    struct shared_ex
    {
#ifdef CPL_DBGSW_ALLOCATOR
      char_cptr m_file_name;
      int       m_line;

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      shared_ex( char_cptr in_file_name, int in_line )
        : m_file_name( in_file_name )
        , m_line( in_line )
      {}

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      template<class... T_Params>
      std::shared_ptr<T_Type>
        operator()( T_Params&&... args )
      {
        return
          std::allocate_shared<T_Type>
            ( alloc_ex<T_Type>(m_file_name, m_line)
            , std::forward<T_Params>(args)...
            );
      }

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      operator std::shared_ptr<T_Type>()
      {
        return
          std::allocate_shared<T_Type>
            ( alloc_ex<T_Type>(m_file_name, m_line) );
      }
#else

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      shared_ex()
      {}

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      template<class... T_Params>
      std::shared_ptr<T_Type>
        operator()( T_Params&&... args )
      {
        return
          std::allocate_shared<T_Type>
            ( alloc_ex<T_Type>()
            , std::forward<T_Params>(args)...
            );
      }

      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      operator std::shared_ptr<T_Type>()
      {
        return std::allocate_shared<T_Type>( alloc_ex<T_Type>() );
      }
#endif
    };
  } // namespace zzz_
/// @endcond

#ifdef CPL_DBGSW_ALLOCATOR


// _____________________________________________________________________________
/// @brief
/// CorePLiのメモリチェック機能付きのstd::make_shared\n
/// ※ 実装はstd::allocate_sharedにオリジナルアロケータ渡してるだけ。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define CPL_MAKE_SHARED(type, ...)\
  (std::shared_ptr<type>)CPL::Core::zzz_::shared_ex<type>(__FILE__,__LINE__)( __VA_ARGS__ )

#else

// _____________________________________________________________________________
/// @brief
/// CorePLiのメモリチェック機能付きのstd::make_shared\n
/// ※ 実装はstd::allocate_sharedにオリジナルアロケータ渡してるだけ。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define CPL_MAKE_SHARED(type, ...)\
  (std::shared_ptr<type>)CPL::Core::zzz_::shared_ex<type>()( __VA_ARGS__ )

#endif



  // _____________________________________________________________________________
  /// @brief CorePLiカスタムアロケータ用のstd::unique_ptr拡張。
  ///
  // *****************************************************************************
  template<class T_Type>
  using unique_ptr =
    std::unique_ptr
      < T_Type
      , typename std::conditional
        < std::is_array<T_Type>::value == true
        , Memory::NewDeleterArr<typename std::remove_extent<T_Type>::type>
        , Memory::NewDeleter<T_Type>
        >::type
      >;


} // namespace Core


} // namespace CPL
