/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/02/02
/// 
/// @brief  ポインタ管理。
/// 
/// ****************************************************************************

#pragma once

#include "../Base/CPL_Core_Basic.h"
#include "../Container/List/CPL_Core_DoublyList.h"
#include "../Container/List/CPL_Core_Tree.h"
#include "../Memory/CPL_Core_Allocator.h"
#include "CPL_Core_Iterator.h"

#ifdef _MSC_VER
  #pragma warning(push)
  #pragma warning( disable : 4521 ) // 複数のコピーコンストラクタの警告を解除
  #pragma warning( disable : 4522 ) // 複数の代入演算子の警告を解除
  //#pragma warning( disable : 4503 ) // 名前の長さオーバー警告
#endif



//***** 簡易定義用マクロ *****//
//#define CPL_DEF_SP_ACCESSER( T_TYPE, OP_TYPE, GETTER )\
//  (T_TYPE) operator OP_TYPE()          { return static_cast<(T_TYPE)>(GETTER); }\
//  (T_TYPE) operator OP_TYPE() const    { return static_cast<(T_TYPE)>(GETTER); }\
//  (T_TYPE) operator OP_TYPE() volatile { return static_cast<(T_TYPE)>(GETTER); }\
//  (T_TYPE) operator OP_TYPE() cpl_cv   { return static_cast<(T_TYPE)>(GETTER); }
// operator ->
#define CPL_DEF_SP_ACCESSER_for_ALLOW( T_PTR, GETTER )\
  (T_PTR) operator ->()          { return static_cast<T_PTR>(GETTER); }\
  (T_PTR) operator ->() const    { return static_cast<T_PTR>(GETTER); }\
  (T_PTR) operator ->() volatile { return static_cast<T_PTR>(GETTER); }\
  (T_PTR) operator ->() cpl_cv   { return static_cast<T_PTR>(GETTER); }
// operator *
#define CPL_DEF_SP_ACCESSER_for_ASTERISK( T_REF, GETTER )\
  (T_REF) operator *()          { return static_cast<T_REF>(*GETTER); }\
  (T_REF) operator *() const    { return static_cast<T_REF>(*GETTER); }\
  (T_REF) operator *() volatile { return static_cast<T_REF>(*GETTER); }\
  (T_REF) operator *() cpl_cv   { return static_cast<T_REF>(*GETTER); }
// operator []
#define CPL_DEF_SP_ACCESSER_for_ARRAY( T_REF, GETTER )\
  template<class T_Idx> (T_REF) operator [] ( T_Idx idx )          { return (GETTER)[ idx ]; }\
  template<class T_Idx> (T_REF) operator [] ( T_Idx idx ) const    { return (GETTER)[ idx ]; }\
  template<class T_Idx> (T_REF) operator [] ( T_Idx idx ) volatile { return (GETTER)[ idx ]; }\
  template<class T_Idx> (T_REF) operator [] ( T_Idx idx ) cpl_cv   { return (GETTER)[ idx ]; }
//operator +
#define CPL_DEF_SP_ACCESSER_for_PLUS( T_PTR, GETTER )\
  template<class T_Idx> (T_PTR) operator +  ( T_Idx idx )          { return (GETTER) + idx; }\
  template<class T_Idx> (T_PTR) operator +  ( T_Idx idx ) const    { return (GETTER) + idx; }\
  template<class T_Idx> (T_PTR) operator +  ( T_Idx idx ) volatile { return (GETTER) + idx; }\
  template<class T_Idx> (T_PTR) operator +  ( T_Idx idx ) cpl_cv   { return (GETTER) + idx; }
// operator -
#define CPL_DEF_SP_ACCESSER_for_MINUS( T_PTR, GETTER )\
  template<class T_Idx> POINTER   operator -  ( T_Idx  idx )          { return get_ptr_() - idx; }\
  template<class T_Idx> POINTER   operator -  ( T_Idx  idx ) const    { return get_ptr_() - idx; }\
  template<class T_Idx> POINTER   operator -  ( T_Idx  idx ) volatile { return get_ptr_() - idx; }\
  template<class T_Idx> POINTER   operator -  ( T_Idx  idx ) cpl_cv   { return get_ptr_() - idx; }
// 比較演算子
#define CPL_DEF_SP_ACCESSER_for_COMPARE( T_PTR, GETTER )\
  template<class T> bool operator <  ( const T& p ) const  noexcept { return ((GETTER) <  &*p); }\
  template<class T> bool operator <  ( const T& p ) cpl_cv noexcept { return ((GETTER) <  &*p); }\
  template<class T> bool operator >  ( const T& p ) const  noexcept { return ((GETTER) >  &*p); }\
  template<class T> bool operator >  ( const T& p ) cpl_cv noexcept { return ((GETTER) >  &*p); }\
  template<class T> bool operator == ( const T& p ) const  noexcept { return ((GETTER) == &*p); }\
  template<class T> bool operator == ( const T& p ) cpl_cv noexcept { return ((GETTER) == &*p); }\
  template<class T> bool operator != ( const T& p ) const  noexcept { return ((GETTER) != &*p); }\
  template<class T> bool operator != ( const T& p ) cpl_cv noexcept { return ((GETTER) != &*p); }\
  bool operator == ( nullptr_t null ) const  noexcept { return (GETTER) == (T_PTR)null; }\
  bool operator == ( nullptr_t null ) cpl_cv noexcept { return (GETTER) == (T_PTR)null; }\
  bool operator != ( nullptr_t null ) const  noexcept { return (GETTER) != (T_PTR)null; }\
  bool operator != ( nullptr_t null ) cpl_cv noexcept { return (GETTER) != (T_PTR)null; }\
  bool operator !  ()  const  noexcept { return ((GETTER) == nullptr); }\
  bool operator !  ()  cpl_cv noexcept { return ((GETTER) == nullptr); }\
  operator     bool()  const  noexcept { return !(operator!()); }\
  operator     bool()  cpl_cv noexcept { return !(operator!()); }


namespace CPL {
namespace Core {


// =============================================================================
// ポインタラッパー
// ※ 不意の明示的deleteを防ぐためや、生ポインタandスマートポインタ代入用
// ※ 参照禁止化修正。よって*,[]は不可。（2013/06/22）
// =============================================================================
template<class T>
class XPtr
{
  template<class T> friend class XPtr;

  typedef typename Traits::AlterConst<T>::type              CONST_TYPE;
  typedef typename Traits::AlterPointer<T>::type            POINTER;
  typedef typename Traits::AlterPointer<CONST_TYPE>::type   CPOINTER;
  typedef typename Traits::AlterReference<T>::type          REFERENCE;
  typedef typename Traits::AlterReference<CONST_TYPE>::type CREFERENCE;

  POINTER m_ptr;

public:
  typedef XPtr< CONST_TYPE > Const;

  XPtr<T>& operator = ( POINTER in_ptr )
  {
    m_ptr = in_ptr;
    return *this;
  }

//  template< class TX >
//  XPtr<TX>& operator = ( XPtr<TX> const& ptr ){ m_ptr = ptr.m_ptr; }

  template<class T>
  XPtr& operator = ( XPtr<T> const& in_xptr )
  {
    m_ptr = in_xptr.m_ptr;
    return *this;
  }

  template< class TX >
  XPtr<T>& operator = ( TX const& in_smptr )
  {
    m_ptr = SmartCast<POINTER>(&*in_smptr);
    return *this;
  }

  XPtr<T>& operator = ( Nothing_ const& null )
  {
    m_ptr = nullptr;
    return *this;
  }

  POINTER    operator ->()       { return static_cast<POINTER>(m_ptr); }
  CPOINTER   operator ->() const { return static_cast<CPOINTER>(m_ptr); }
  //REFERENCE  operator *()        { return *static_cast<POINTER>(m_ptr); }
  //CREFERENCE operator *()  const { return *static_cast<CPOINTER>(m_ptr); }

  //template<class T_Idx> CREFERENCE operator [] ( T_Idx  idx ) const noexcept { return m_ptr[ idx ];  }
  //template<class T_Idx> REFERENCE  operator [] ( T_Idx  idx )       noexcept { return m_ptr[ idx ];  }
  template<class T_Idx> CPOINTER   operator +  ( T_Idx  idx ) const noexcept { return m_ptr + idx;   }
  template<class T_Idx> POINTER    operator +  ( T_Idx  idx )       noexcept { return m_ptr + idx;   }
  template<class T_Idx> CPOINTER   operator -  ( T_Idx  idx ) const noexcept { return m_ptr - idx;   }
  template<class T_Idx> POINTER    operator -  ( T_Idx  idx )       noexcept { return m_ptr - idx;   }

  template<class T> bool operator <  ( const T& p ) const noexcept { return (m_ptr <  &*p); }
  template<class T> bool operator >  ( const T& p ) const noexcept { return (m_ptr >  &*p); }
  template<class T> bool operator == ( const T& p ) const noexcept { return (m_ptr == &*p); }
  template<class T> bool operator != ( const T& p ) const noexcept { return (m_ptr != &*p); }
  bool operator == ( const int null ) const noexcept { return m_ptr == (CPOINTER)null; }
  bool operator != ( const int null ) const noexcept { return m_ptr != (CPOINTER)null; }
  bool operator !  () const noexcept { return (m_ptr == nullptr); }
  operator     bool() const noexcept { return !(operator!()); }

  XPtr( POINTER ptr ) : m_ptr( ptr ){}

  XPtr( nullptr_t null ) : m_ptr( nullptr ){}

  template< class TX >
  XPtr( XPtr<TX> ptr )
    : m_ptr( SmartCast<POINTER>(ptr.m_ptr) ) {}

  template< class TX >
  XPtr( TX in_smptr )
    : m_ptr( SmartCast<POINTER>( &*in_smptr ) )
  {}

  XPtr( Nothing_ const& null )
    : m_ptr( nullptr )
  {}
};


/// @cond
//namespace sp {
//namespace zzz_ {
//
//
//// =============================================================================
//// 全てのスマートポインタクラスの基底クラス
//// ※ 仮想禁止
//// =============================================================================
//class baseSmartPointer
//  : public Core::BaseObject
//{
//protected:
//  baseSmartPointer(){}
//  ~baseSmartPointer(){}
//
//  //
//  //template<class T_SP, int Flag> struct MTFlag { volatile int flag_; };
//  //template<class T_SP> struct MTFlag<T,false>{};
//};
//
///*
//T_Type == int[]
//type : int[]
//type_const : int const[]
//type_volatile : int volatile[]
//pointer : int[]*
//cpointer : int const[]*
//*/
//
//// =============================================================================
//// タイプ宣言
//// non array
//// array[]
//// array[N]
//// =============================================================================
//template<class T_Type>
//class SmartPointerDefinedBasicTypes
//{
//  template<class T>       struct SmartType       { typedef T type;   };
//  template<class T>       struct SmartType<T[]>  { typedef T type[1]; };
//  template<class T,int N> struct SmartType<T[N]> { typedef T type[N]; };
//
//  static const int N = Traits::IsArray<T_Type>::value; // 配列数
//public:
//  typedef typename Traits::RemoveArray<T_Type>::type        BASIC_TYPE;
//  typedef typename T_Type                                   TYPE;
//  //typedef typename Traits::IfType2< N==0, N>0,
//  //          typename Traits::InConst<BASIC_TYPE>::type,
//  //          typename Traits::InConst<BASIC_TYPE>::type[N],
//  //          typename Traits::InConst<BASIC_TYPE>::type[] >::type    CONST_TYPE;
//  //typedef typename Traits::IfType2< N==0, N>0,
//  //          typename Traits::InVolatile<BASIC_TYPE>::type,
//  //          typename Traits::InVolatile<BASIC_TYPE>::type[N],
//  //          typename Traits::InVolatile<BASIC_TYPE>::type[] >::type VOLATILE_TYPE;
//  //typedef typename Traits::IfType2< N==0, N>0,
//  //          typename Traits::InCV<BASIC_TYPE>::type,
//  //          typename Traits::InCV<BASIC_TYPE>::type[N],
//  //          typename Traits::InCV<BASIC_TYPE>::type[] >::type       CV_TYPE;
//  typedef typename Traits::AlterConst<TYPE>::type                CONST_TYPE;
//  typedef typename Traits::AlterVolatile<TYPE>::type             VOLATILE_TYPE;
//  typedef typename Traits::AlterCV<TYPE>::type                   CV_TYPE;
//  typedef typename Traits::AddPointer<BASIC_TYPE>::type          POINTER;
//  typedef typename Traits::AddPointer<BASIC_TYPE const>::type    CPOINTER;
//  typedef typename Traits::AddPointer<BASIC_TYPE volatile>::type VPOINTER;
//  typedef typename Traits::AddPointer<BASIC_TYPE cpl_cv>::type   CVPOINTER;
//
//  //typedef typename Traits::IfType<
//  //          Traits::IsArray<T_Type>::value==-1, // 不定配列サイズの場合
//  //          typename Traits::InReference<BASIC_TYPE*>::type,
//  //          typename Traits::InReference<TYPE>::type >::type  REFERENCE;
//  //typedef typename Traits::IfType<
//  //          Traits::IsArray<T_Type>::value==-1, // 不定配列サイズの場合
//  //          typename Traits::InReference<BASIC_TYPE const*>::type,
//  //          typename Traits::InReference<CONST_TYPE>::type >::type  REFERENCE;
//  typedef typename Traits::AddReference<BASIC_TYPE>::type          REFERENCE;
//  typedef typename Traits::AddReference<BASIC_TYPE const>::type    CREFERENCE;
//  typedef typename Traits::AddReference<BASIC_TYPE volatile>::type VREFERENCE;
//  typedef typename Traits::AddReference<BASIC_TYPE cpl_cv>::type   CVREFERENCE;
//
//  typedef XPtr< TYPE >          XPOINTER;
//  typedef XPtr< CONST_TYPE >    XCPOINTER;
//  typedef XPtr< VOLATILE_TYPE > XVPOINTER;
//  typedef XPtr< CV_TYPE >       XCVPOINTER;
//};
//
//
//// =============================================================================
//// デラックス版　スマートポインタが有効かどうかをチェックする関数
//// =============================================================================
//template<class T>
//bool checkEnableSmartPtr( T* in_ptr )
//{
//  return in_ptr ? (in_ptr->getSmartPtr() != nullptr) : nullptr;
//}
//
//// =============================================================================
//// デラックス版　生ポインタからスマートポインタへの変換
//// =============================================================================
//template<class T_SP, class T_PTR>
//typename T_SP convertSmartPtr( T_PTR in_ptr )
//{
//  return in_ptr->m_sp_this;
//}
//
//} // namespace zzz_
//} // namespace sp
/// @endcond





// =============================================================================
// デバッグ用リミット付きポインタ
//  ※ リリースビルドでは通常のポインタとほぼ同様に振舞う
// =============================================================================
template<class T_Type>
class CheckPointer
  : public Core::BaseObject
{
  typedef typename Traits::RemovePointer<T_Type>::type& REFERENCE;

  T_Type m_ptr;
#ifdef CPL_DEBUG
  T_Type m_ptr_top;
  T_Type m_ptr_end;
#endif

public:
  CheckPointer( T_Type in_ptr, T_Type in_ptr_top, T_Type in_ptr_end )
    : m_ptr( in_ptr )
#ifdef CPL_DEBUG
    , m_ptr_top( in_ptr_top )
    , m_ptr_end( in_ptr_end )
#endif
  {}
  ~CheckPointer(){}

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator -> ()       { return m_ptr; }
  T_Type operator -> () const { return m_ptr; }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  REFERENCE operator *()       { return *m_ptr; }
  REFERENCE operator *() const { return *m_ptr; }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_IDX>
  REFERENCE operator []( T_IDX in_idx )       { return m_ptr[ in_idx ]; }
  template<class T_IDX>
  REFERENCE operator []( T_IDX in_idx ) const { return m_ptr[ in_idx ]; }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator = ( T_Type in_new_ptr )
  {
  #ifdef CPL_DEBUG
    if( in_new_ptr < m_ptr_top  ||  m_ptr_end < in_new_ptr )
      throw;
  #endif
    m_ptr = in_new_ptr;
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator + ( int in_idx ) const
  {
  #ifdef CPL_DEBUG
    if( m_ptr + in_idx > m_ptr_end )
      throw;
  #endif
    return m_ptr + in_idx;
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator += ( int in_idx )
  {
  #ifdef CPL_DEBUG
    if( m_ptr + in_idx > m_ptr_end )
      throw;
  #endif
    return m_ptr + in_idx;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator ++ ()
  {
  #ifdef CPL_DEBUG
    if( m_ptr + 1 > m_ptr_end )
      throw;
  #endif
    return ++m_ptr;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator - ( int in_idx ) const
  {
  #ifdef CPL_DEBUG
    if( m_ptr - in_idx < m_ptr_top )
      throw;
  #endif
    return m_ptr - in_idx;
  }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator -= ( int in_idx )
  {
  #ifdef CPL_DEBUG
    if( m_ptr - in_idx < m_ptr_top )
      throw;
  #endif
    return m_ptr - in_idx;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  T_Type operator -- ()
  {
  #ifdef CPL_DEBUG
    if( m_ptr - 1 < m_ptr_top )
      throw;
  #endif
    return --m_ptr;
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> bool operator < ( const T in_ptr ) const { return (m_ptr < in_ptr); }
  template<class T> bool operator > ( const T in_ptr ) const { return (m_ptr > in_ptr); }
  template<class T> bool operator ==( const T in_ptr ) const { return (m_ptr == in_ptr); }
  template<class T> bool operator !=( const T in_ptr ) const { return (m_ptr != in_ptr); }
  bool operator !() const { return (m_ptr == nullptr); }

  operator T_Type() const { return m_ptr; }
};



} // namespace Core
} // namespace CPL




#ifdef _MSC_VER
  #pragma warning(pop) // 元へ
#endif
