module ytl.fastmap;

private import ytl.vector;

///	高速な巡回の出来るmap
/**
	内部的には、mapとvectorを持っている。
	mapの内容を更新したあとに、updateを呼び出す必要がある。
	updateは少し負荷がかかるが、事前にupdateを呼び出せるような
	ケースにおいては巡回の高速性は都合がいい。
<PRE>
	keyの型 = S
	mapの型 = T
</PRE>
*/
//template fastmap(T,S) {
/// fastmap の実体
class fastmap(T,S) {

	///	要素をmapに追加する
	/**
		最終的にvectorのほうに反映させるために update メソッドを
		呼び出す必要がある。
	*/
	void insert(S key,T data) {
		m[key] = data;
	}

	///	要素をmapから消去する(keyに対応するT型のデータも消す)
	/**
		最終的にvectorのほうに反映させるために update メソッドを
		呼び出す必要がある。
	*/
	void erase(S key) {
		m.remove(key);
	}

	///	あるkeyが含まれているかをチェックする
	bool isin(S key) {
		return cast(bool) !( (key in m) is null );
	}

	/// keyに対応するデータを取得する
	T get(S key) { return m[key]; }

	/// keyの数を返す
	int size() { return m.length; }

	///	中身をクリアする
	/**
		map,vectorの両方を初期化する
	*/
	void clear() {
		v = null;
		/*
		//	連想記憶をクリアするのめんどくさー．．(´Д`)
		S[] k = m.keys;
		for (int i = 0; i < k.length; ++i)
	 		delete m[k[i]];
		*/
		m = null;	//	単にnullを入れるだけでクリアできるようだ..
	}

	///	foreachに対応させるためのもの
	/**
		update メソッドを呼び出して、mapの中身がvectorのほうに
		反映させていることが前提条件。
	*/
	int opApply(int delegate(inout T) dg)
	{
		int result = 0;
		int size = v.length;
		for (int i = 0; i < size; ++i)
		{
			result = dg(v[i]);
			if (result)	break;
		}
		return result;
	}

	///	foreachに対応させるためのもの
	/**
		update メソッドを呼び出して、mapの中身がvectorのほうに
		反映させていることが前提条件。
	*/
	int opApply(int delegate(inout S,inout T) dg)
	{
		int result = 0;
		int size = v.length;
		for (int i = 0; i < size; ++i)
		{
			result = dg(keys[i],v[i]);
			if (result)	break;
		}
		return result;
	}

	///	mapの中身をvectorに反映させる。
	/**
		foreachで巡回するときは、vectorを元に巡回する。
		mapの中身をvectorのほうに反映させておく必要がある。
	*/
	void update() {
		keys = m.keys;
		v = new T[keys.length];	//	0サイズのnewは許容されている
		for (int i = 0; i < keys.length; ++i) {
			v[i] = m[keys[i]];
		}
	}

	///	mapの取得
	/**
		最悪、こいつで直接いじったって。
	*/
	T[S] getMap() { return m; }

	///	vectorの取得
	/**
		最悪、こいつで直接いじったって。
		updateを呼び出さないと更新されないことに注意。
	*/
	T[] getVector() { return v; }

	///	mapのキー集合の取得。
	/**
		最悪、こいつで直接いじったって。
		updateを呼び出さないと更新されないことに注意。
	*/
	S[] getKeys() { return keys; }

private:
	T[S]	m;		//	連想配列
	T[]		v;		//	巡回のためのvector
	S[]		keys;	//	巡回のためのkeys
}
//}
