/**
 *  @file   deepcopy_ptr.hpp
 *  @author takagi@kijineko.co.jp
 *  @brief  ディープコピーを行うスマートポインタの宣言定義
 *
 *  deepcopy_ptrクラステンプレートを提供する。
 *
 *  @code
 *  // 使用例
 *  #include <deepcopy_ptr.hpp>
 *  #include <cassert>
 *
 *  class A
 *  {
 *  public:
 *      void func();
 *      ...
 *  };
 *
 *  int main()
 *  {
 *      deepcopy_ptr<A> p1(new A);
 *      p1->func();
 *      deepcopy_ptr<A> p2(p1);
 *      assert(p1.get() != p2.get());
 *  }
 *  @endcode
 */
#ifndef DEEPCOPY_PTR_HPP_
#define DEEPCOPY_PTR_HPP_

#include <memory>
#include <cassert>

/**
 *  \class  deepcopy_ptr deepcopy_ptr.hpp <deepcopy_ptr.hpp>
 *  \brief  ディープコピーを行うスマートポインタ
 */
template <class T>
class deepcopy_ptr
{
public:
    /// 生のポインタを指定するコンストラクタ
    explicit deepcopy_ptr(T* ptr = 0)
        : ptr_(ptr)
    {
    }
    // auto_ptr からの変換を行うコンストラクタ
    explicit deepcopy_ptr(std::auto_ptr<T>& aptr)
        : ptr_(aptr.release())
    {
    }
    /// コピーコンストラクタ
    deepcopy_ptr(deepcopy_ptr const& other)
        : ptr_(other.ptr_ != 0 ? new T(*other.ptr_) : 0)
    {
    }
    /// デストラクタ
    ~deepcopy_ptr()
    {
        delete ptr_;
    }

    /// コピー代入演算子
    deepcopy_ptr<T> operator=(deepcopy_ptr<T> const& other)
    {
        deepcopy_ptr<T> temp(other);
        swap(temp);
        return *this;
    }
    /// 生のポインタの代入演算子
    deepcopy_ptr<T> operator=(T* ptr)
    {
        deepcopy_ptr<T> temp(other);
        swap(temp);
        return *this;
    }
    /// auto_ptrからの変換を行う代入演算子
    deepcopy_ptr<T> operator=(std::auto_ptr<T>& aptr)
    {
        deepcopy_ptr<T> temp(aptr);
        swap(temp);
        return *this;
    }
    /// 間接参照演算子
    T& operator*() const
    {
        assert(ptr_ != 0);
        return *ptr_;
    }
    /// 矢印演算子
    T* operator->() const
    {
        assert(ptr_ != 0);
        return ptr_;
    }
    /// !演算子
    bool operator!() const
    {
        return !ptr_;
    }

    /// 生のポインタを取得する
    T* get() const
    {
        return ptr_;
    }
    /// 指定した生のポインタでリセットする
    void reset(T* ptr = 0)
    {
        delete ptr_;
        ptr_ = ptr;
    }
    /// 値を交換する
    void swap(deepcopy_ptr<T>& other)
    {
        T* temp = ptr_;
        ptr_ = other.ptr_;
        other.ptr_ = temp;
    }
private:
    T* ptr_;
};

namespace std
{
    /// ats::swapの多重定義
    template <class T>
    inline void swap(deepcopy_ptr<T>& lhs, deepcopy_ptr<T>& rhs)
    {
        lhs.swap(rhs);
    }
}

#endif  // DEEPCOPY_PTR_HPP_

