

/*!
	@file double_key_map.h
  @author d金魚
  @since 2004/01/19
	@note
	licence:BSD Licence
*/


#ifndef _dktl_double_key_map__h_
#define _dktl_double_key_map__h_


namespace dkutil{
/*
template<class _Tp>
struct force_address_less : public std::binary_function<_Tp,_Tp,bool>{
	bool operator()(const _Tp& x, const _Tp& y) const {
		return ((UINT *)boost::addressof(x) < (UINT *)boost::addressof(y));
		//return ((UINT)boost::addressof(x) < (UINT)booost::addressof(y));
		//return ((*x) < (*y));
	}
};
*/
typedef UINT* FORCE_ADDRESS_OF_PTR;
/*
#define FORCE_ADDRESS_OF_DEFINE(el) \
bool force_address_of(const _Tp& x, const _Tp& y) const {\
	return ((UINT *)boost::addressof(x) el (UINT *)boost::addressof(y));\
}
*/

template<class _Tp,class _Pr>
struct force_address_function : public std::binary_function<_Tp,_Tp,bool>
{
	bool force_address_of(const _Tp& x, const _Tp& y) const {
		_Pr r;
		return r((FORCE_ADDRESS_OF_PTR)boost::addressof(x) , (FORCE_ADDRESS_OF_PTR)boost::addressof(y));
	}
	
	bool operator()(const _Tp& x, const _Tp& y) const {
		return force_address_of(x,y);
	}
};

template<class _Tp>
struct force_address_less : public force_address_function<_Tp,std::less<FORCE_ADDRESS_OF_PTR> >
{
	bool operator()(const _Tp& x, const _Tp& y) const {
		return force_address_of(x,y);
	}
};

/*!
@note
get()メンバはスレッドセーフでは無い。<br>
例：getして、そのポインタを弄繰り回している間にスレッドチェンジしてそのポインタ先が削除されるとか。<br>
<br>
注意：このコンテナはメモリの無駄づかいです。＾＾；<br>
<br>
@todo MAP2_ のMAP1_::iterator はMAP1_::iterator *の方がいいのだろうか？<br>
<s>double_key_mapの構造を再起化して</s>コンパイラが許すまでのキーをもてるようにする？
（私の技術では無理そう）といいますか、論理的に無理そう･･･<br>


*/
template<class K1,class K2,class T,
class MAP1_ = std::map<K1,T> ,
class MAP2_ = std::map<K2,MAP1_::iterator
//,	force_address_less<K2>
 >,
class MAP3_ = std::map<MAP1_::iterator,MAP2_::iterator,
	force_address_less<MAP1_::iterator> >
>
class double_key_map
{
public:
	
	typedef MAP1_ MAP1_TYPE;
	typedef MAP2_ MAP2_TYPE;
	typedef MAP3_ MAP3_TYPE;
	typedef typename MAP1_TYPE::size_type size_type;
	
	typedef MAP1_TYPE::iterator MAP1_ITERATOR;
	typedef MAP1_TYPE::const_iterator MAP1_CONST_ITERATOR;
	typedef MAP2_TYPE::iterator MAP2_ITERATOR;
	typedef MAP2_TYPE::const_iterator MAP2_CONST_ITERATOR;
	typedef MAP3_TYPE::iterator MAP3_ITERATOR;
	typedef MAP3_TYPE::const_iterator MAP3_CONST_ITERATOR;

	typedef K1 KEY1_TYPE;
	typedef K2 KEY2_TYPE;
	typedef T TARGET_DATA_TYPE;

	struct INSERT_DATA_TYPE{
		INSERT_DATA_TYPE(
			const KEY1_TYPE &key1,
			const KEY2_TYPE &key2,
			const TARGET_DATA_TYPE &target
			) : k1(key1),k2(key2),data(target){}
		
		KEY1_TYPE k1;
		KEY2_TYPE k2;
		TARGET_DATA_TYPE data;
	};
	/*typedef boost::tuple<
		KEY1_TYPE,
		KEY2_TYPE,
		TARGET_DATA_TYPE
	> INSERT_DATA_TYPE;
	*/
	

	typedef std::pair<K1,T> MAP1_INSERT_DATA;
	typedef std::pair<K2,MAP1_ITERATOR> MAP2_INSERT_DATA;
	typedef std::pair<MAP1_ITERATOR,MAP2_ITERATOR> MAP3_INSERT_DATA;

	typedef std::pair<MAP1_ITERATOR,bool> MAP1_RESULT;
	typedef std::pair<MAP2_ITERATOR,bool> MAP2_RESULT;
	typedef std::pair<MAP3_ITERATOR,bool> MAP3_RESULT;

	struct INSERT_RESULT{
		/*INSERT_RESULT(bool r=false,
			MAP1_ITERATOR i1,
			MAP2_ITERATOR i2,
			MAP3_ITERATOR i3) : 
			result(r) , it1(i1) , it2(i2) , it3(i3){}
			*/
		INSERT_RESULT(bool r=false) : result(r){}
		bool result;
		MAP1_ITERATOR it1;
		MAP2_ITERATOR it2;
		MAP3_ITERATOR it3;
	};

	///最初にboolあった方が仕様変更に耐えやすい＾＾；？
	//typedef boost::tuple<bool,MAP1_TYPE::iterator,MAP2_TYPE::iterator> INSERT_RESULT;
private:
	MAP1_TYPE mM1;
	MAP2_TYPE mM2;
	MAP3_TYPE mM3;
public:
	double_key_map(){}
	virtual ~double_key_map(){
		clear();
	}
	///データを挿入する
	INSERT_RESULT insert(const INSERT_DATA_TYPE &data)
	{
		INSERT_RESULT result;
		result.result = false;
		result.it1 = mM1.end();
		result.it2 = mM2.end();
		result.it3 = mM3.end();


		MAP1_RESULT m1r;
		m1r = mM1.insert(MAP1_INSERT_DATA(data.k1,data.data));
		if(false == m1r.second){
			return result;
		}

		result.it1 = m1r.first;

		MAP2_RESULT m2r;
		m2r = mM2.insert(MAP2_INSERT_DATA(data.k2,m1r.first));
		
		if(false == m2r.second){
			mM1.erase(m1r.first);
			return result;
		}


		result.it2 = m2r.first;

		MAP3_RESULT m3r;
		m3r = mM3.insert(MAP3_INSERT_DATA(m1r.first,m2r.first));

		if(false == m3r.second){
			mM1.erase(m1r.first);
			mM2.erase(m2r.first);
			return result;
		}
		//ﾜｰｲヽ(ﾟ∀ﾟ)メ(ﾟ∀ﾟ)メ(ﾟ∀ﾟ)ノﾜｰｲ　成功だ＾＾
		result.it3 = m3r.first;
		result.result = true;


		return result;
	}
	///データを削除（キー１版
	bool erase(const K1 &k1){
		MAP1_ITERATOR it = mM1.find(k1);
		if(it == mM1.end()){
			return false;
		}
		MAP3_ITERATOR it3 = mM3.find(it);//ここ
		if(it3 == mM3.end()){
			throw std::runtime_error("なんで、もう一つのキーが見当たらない！？");
		}
		mM1.erase(it1);
		mM2.erase((*it3).second);
		mM3.erase(it3);
		return true;
	}
	///データを削除（キー２版
	bool erase2(const K2 &k2){
		MAP2_ITERATOR it = mM2.find(k2);
		if(it == mM2.end()){
			return false;
		}
		mM1.erase((*it).second);
		mM2.erase(it);
		mM3.erase((*it).second);
		return true;
	}

	
	///データをゲットする(キー２番
	T *get(const K1 &k){
		MAP1_ITERATOR it = mM1.find(k);
		if(it == mM1.end())
		{//｜出口｜　　　λ....　　ｿﾝﾅﾉﾅｶｯﾀYO
			return NULL;
		}
		return &it.second;
	}
	///データをゲットする(キー２版
	T *get2(const K2 &k){
		MAP2_ITERATOR it = mM2.find(k);
		if(it == mM2.end())
		{//なにもねぇよ！
			return NULL;
		}
		return &it.second.second;
	}
	MAP1_CONST_ITERATOR find(const K1 &k)const{
		return mM1.find(k);
	}
	MAP1_ITERATOR find(const K1 &k){
		return mM1.find(k);
	}
	MAP2_CONST_ITERATOR find(const K2 &k)const{
		return mM2.find(k);
	}
	MAP2_ITERATOR find2(const K2 &k){
		return mM2.find(k);
	}

	///キー１を管理しているマップにアクセス（標準）
	MAP1_ITERATOR begin(){	return mM1.begin();}
	MAP1_ITERATOR end(){	return mM1.end();}
	MAP1_CONST_ITERATOR begin()const{	return mM1.begin();}
	MAP1_CONST_ITERATOR end()const{	return mM1.end();}
	///キー２を管理しているマップにアクセス
	MAP2_ITERATOR begin2(){	return mM2.begin();}
	MAP2_ITERATOR end2(){	return mM2.end();}
	MAP2_CONST_ITERATOR begin2()const{	return mM2.begin();}
	MAP2_CONST_ITERATOR end2()const{	return mM2.end();}
	///二つのマップのイテレーターを保存しているマップにアクセス
	MAP3_ITERATOR begin_iterator(){	return mM3.begin();}
	MAP3_ITERATOR end_iterator(){	return mM3.end();}
	MAP3_CONST_ITERATOR begin_iterator()const{	return mM3.begin();}
	MAP3_CONST_ITERATOR end_iterator()const{	return mM3.end();}

	bool erase(const MAP1_ITERATOR &it){
		return erase(it.first);
	}
	size_type size()const{
#	ifndef NDEBUG
		if(mM1.size() != mM2.size() || mM2.size() != mM3.size() || mM3.size() != mM1.size())
		{

			DKUTIL_NOT_ASSERT("んなわケネーだろ");
			
		}
#	endif
		return mM1.size();

	}
	void clear(){
		mM1.clear();
		mM2.clear();
		mM3.clear();
	}
	bool empty(){
#	ifndef NDEBUG
		if(mM1.empty() != mM2.empty() || mM2.empty() != mM3.empty() || mM3.empty() != mM1.empty())
		{
			DKUTIL_NOT_ASSERT("emptyが合わない。");
		}
#	endif
		return mM1.empty();
	}
				



};


}//end of dkutil namepsace

#endif //end of include once