//---------------------------------------------------------------------------
// 汎用１，２次元配列クラス (Ver. 2.01)
// 作成者，著作権者：　三上 直樹
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// 2010.01.27 以前の以前の修正は C:\CodeGear\RAD Studio\5.0\uLib\array\test1\MK_Array.h に記録
//      以下は C++ Builder 2010 で変更
//---------------------------------------------------------------------------
// 修正日：　2010.01.27 (Ver. 2.0)
//      配列の範囲の検査の有無を“NDEBUG”で行うように変更．その結果，範囲チェックが，
//      Debug でビルドした場合は有効になり，Release でビルドした場合は無効になる
// 修正日：　2010.02.05 (Ver. 2.01)
//      new 演算子を使う部分は try-catch 構文に変更．メモリの確保に失敗した場合は
//      メッセージを表示した後，abort() が起動されて強制終了になる．
// 修正日：　2010.03.08 (Ver. 2.01)
//      関数名の先頭の文字を小文字に変更
// 修正日：　2010.04.15 (Ver. 2.1)
//      Matrix に assign() を加え，コピーコンストラクタを削除

#ifndef MK_Array_Lib

#include <cassert>  // assert用
#include <new>      // std::bad_alloc 用
#include <windows.h>

#include <vcl.h>
//---------------------------------------------------------------------------
// 汎用１次元配列クラス
template <typename T> class Vector
{
public:
    explicit Vector(int i = 1);                 // コンストラクタ
    Vector(int n, const T a[]);                 // 配列の内容で初期化するコンストラクタ
    Vector(const Vector<T>& a) { copy(a); }     // コピーコンストラクタ
    ~Vector() { delete[] v_; }                  // デストラクタ
    void setSize(int i);                        // 大きさの再設定
    Vector<T>& operator=(const Vector<T>& a);   // 代入
    Vector<T>& operator=(const T a[]);          // 代入
    inline T& operator[](int i);                // 要素への書き込み
    inline const T& operator[](int i) const;    // 要素の読み出し
    int length() const { return size_; }        // 配列の大きさ取得
    operator const T* () const { return v_; }   // 型変換
private:
    T*   v_;
    int  size_;
    void range(int pos) const;                  // 配列の範囲の検査
    void copy(const Vector<T>& v_src);
    void errMsg(const char *s) { MessageBox(NULL, s, "", MB_ICONSTOP | MB_OK); }
};

// 汎用１次元配列クラスの実装部
template <typename T> void Vector<T>::range(int pos) const
{
    assert(0 <= pos && pos < size_);
}

template <typename T> void Vector<T>::copy(const Vector<T>& v_src)
{
    try { v_ = new T[size_ = v_src.size_]; }
    catch (std::bad_alloc)                      // メモリ確保に失敗
    {
        errMsg("メモリ確保に失敗しました");
        abort();
    }
    for (int i=0; i<size_; i++) v_[i] = v_src.v_[i];
}

template <typename T> Vector<T>::Vector(int i)
{
    assert(i > 0);                              // サイズ指定の誤り

    try { v_ = new T[size_ = i]; }
    catch (std::bad_alloc)                      // メモリ確保に失敗
    {
        errMsg("メモリ確保に失敗しました");
        abort();
    }
}

template <typename T> Vector<T>::Vector(int n, const T a[])
{
    assert(n > 0);                              // サイズ指定の誤り
    try { v_ = new T[size_ = n]; }
    catch (std::bad_alloc)                      // メモリ確保に失敗
    {
        errMsg("メモリ確保に失敗しました");
        abort();
    }
    for (int i=0; i<n; i++) v_[i] = a[i];
}

template <typename T> void Vector<T>::setSize(int i)
{
    delete[] v_;
    assert(i > 0);                              // サイズ指定の誤り
    try {v_ = new T[size_ = i]; }
    catch (std::bad_alloc)                      // メモリ確保に失敗
    {
        errMsg("メモリ確保に失敗しました");
        abort();
    }
}

template <typename T> Vector<T>& Vector<T>::operator=(const Vector<T>& a)
{
    if (this != &a)                             // 自己代入禁止
    {
        delete [] v_;
        copy(a);
    }
    return *this;
}

template <typename T> Vector<T>& Vector<T>::operator=(const T a[])
{
    for (int n=0; n<size_; n++) v_[n] = a[n];
    return *this;
}

template <typename T> inline T& Vector<T>::operator[](int i)
{
#ifndef NDEBUG
    range(i);                                   // 引数の範囲のチェック
#endif
    return v_[i];
}

template <typename T> inline const T& Vector<T>::operator[](int i) const
{
#ifndef NDEBUG
    range(i);
#endif
    return v_[i];
}

//---------------------------------------------------------------------------

// 汎用２次元配列クラス
template <typename T> class Matrix
{
public:
    explicit Matrix(int rows = 1, int cols = 1);
    void setSize(int rows, int cols);           // 大きさの再設定
    void assign(const T b[]);                   // 代入
    Vector<T>& operator[](int i) { return a_[i]; }
    const Vector<T>& operator[](int i) const { return a_[i]; }
    int rows() const { return a_.length(); }
    int cols() const { return a_[0].length(); }
private:
    Vector< Vector<T> > a_;
};

// 汎用２次元配列クラスの実装部
template <typename T> Matrix<T>::Matrix(int rows, int cols): a_(rows)
{
    Vector<T> a(cols);
    assert(rows > 0);                           // サイズ指定の誤り
    for (int i=0; i<rows; i++) a_[i] = a;
}

template <typename T> void Matrix<T>::assign(const T b[])
{
    int colsN = cols();
    for (int m=0; m<rows(); m++)
        for (int n=0; n<colsN; n++)  a_[m][n] = b[n + m*colsN];
}

template <typename T> void Matrix<T>::setSize(int rows, int cols)
{
    Vector<T> a(cols);
    assert(rows > 0);                          // サイズ指定の誤り
    a_.setSize(rows);
    for (int i=0; i<rows; i++) a_[i] = a;
}

#define MK_Array_Lib
#endif
