

/*!
  @author d金魚
  @since 2003/8/21
	@note
	licence:BSD Licence
*/


#ifndef DKUTIL_DKTL_SINGLETON_HPP
#define DKUTIL_DKTL_SINGLETON_HPP

#include <dkutil/config.hpp>
#include <dkutil/macro.hpp>
#include <dkutil/synchronized.hpp>

namespace dkutil{

template <class T>
class singleton {

//やねうらお氏のYTL/singleton.hを参考にしました。
public:
	
	typedef T self_type;
	//typedef UTIL thread_policy;
	singleton(){
		//ODS("OK singleton\n");
	}
	virtual ~singleton() { Release(); }
	///	ポインタのふりをするための仕掛け　(なるほど！これは便利です。
	T& operator*() { return *get(); }
	T* operator->() { return get();	}
	///インスタンス確認あり取得
	T* get() { CheckInstance(); return m_lpObj; }
	///確認無し。速攻ポインタ取得
	T *get_fast(){return m_lpObj;}
	bool	isNull() const { return m_lpObj == NULL; }
	void Release(){
		if (m_lpObj!=NULL) {
			synchronized swimming;
			
			if(m_lpObj!=NULL){		
				delete m_lpObj;
				m_lpObj = NULL;
			}
			
		}
	}
	void CheckInstance(){
		if (m_lpObj==NULL) {
			synchronized swimming;
			if(m_lpObj==NULL){
				m_lpObj = new T;
			}
		}
	}
BOOST_PROTECTED:
	static T*	m_lpObj;
	//UTIL m_util;
};

//	static なオブジェクト
template <class T> T* singleton<T>::m_lpObj = 0;


/*!
@section 使い方

intrusive_singleton_after_new( T *p,void *)
intrusive_singleton_before_delete( T *p,void *)
の二つを定義してください。
前者はnewした後に呼び出すべき処理
後者はdeleteする前に呼び出すべき処理
です。

これらをGlobal namespace ,またはanonymous namespaceに定義してください。
イメージ的には
boost::intrusive_ptr　と同じです。
http://www.kmonos.net/alang/boost/classes/intrusive_ptr.html

*/
///押し付けがましいsingleton(笑) boost::intrusive_ptrみたいなもの
template <class T>
class intrusive_singleton {
	//やねうらお氏のYTL/singleton.hを参考にしました。
public:
	typedef T self_type;
	//typedef UTIL thread_policy;
	intrusive_singleton(){
		//ODS("OK singleton\n");
	}
	///@see set_param()
	intrusive_singleton(void *Ptr,bool overwrite=false){
		set_param(Ptr,overwrite);
	}
	/*
	@param Ptr[in] 邪道だけどポインタ
	@param overwrite[in] 前、渡したポインタがNULLではない時、上書きする時TRUE
	@param create[in] trueだと即行インスタンスを生成(Ptrが上書きされてしまう危険があるため。
	@note
	なんか、singletonの意義の一つのうちの「必要になったら作成する」
	ってのがおざなりになっているような気が＾＾；
	*/
	intrusive_singleton(bool create,void *Ptr,bool overwrite=false){
		if(create){
			force_create_instance(Ptr);
		}else{
			set_param(Ptr,overwrite);
		}
	}	
	/*!
	@param Ptr[in] 邪道だけどポインタ intrusive_singleton_after_new before_deleteの第二引数に渡す奴
	@param overwrite[in] 前、渡したポインタがNULLではない時、上書きする時TRUE
	*/
	void set_param(void *Ptr,bool overwrite=false){
	
		if(overwrite){
			mPtr = Ptr;
		}else if(NULL==mPtr){
			mPtr = Ptr;
		}
	}
	/*!
	強制的に速攻instanceを作成します。
	@see 引数は set_param()と同じ。
	@return falseだとすでにinstanceが作られてしまっている。
	*/
	bool force_create_instance(void *Ptr){
		synchronized swimming;
		if(false==isNull()){
			return false;
		}
		set_param(Ptr,true);
		CheckInstance();
	}

	
	virtual ~intrusive_singleton() { Release(); }
	///	ポインタのふりをするための仕掛け　(なるほど！これは便利です。
	T& operator*() { return *get(); }
	T* operator->() { return get();	}
	///インスタンス確認あり取得
	T* get() { CheckInstance(); return m_lpObj; }
	///確認無し　速攻ポインタ。
	T* get_fast(){ return m_lpObj;}

	bool	isNull() const { return m_lpObj == NULL; }
	void Release(){
		if (m_lpObj!=NULL) {
			synchronized swimming;
			//DKUTIL_LOCKTHREAD(m_util);
			if(m_lpObj!=NULL){
				intrusive_singleton_before_delete(m_lpObj,mPtr); 
				delete m_lpObj;
				m_lpObj = NULL;
			}
			//DKUTIL_UNLOCKTHREAD(m_util);
		}
	}
	void CheckInstance(){
		if (m_lpObj==NULL) {
			synchronized swimming;
			//DKUTIL_LOCKTHREAD(m_util);
			if(m_lpObj==NULL){
				m_lpObj = new T;
				intrusive_singleton_after_new(m_lpObj,mPtr); 
			}
			//DKUTIL_UNLOCKTHREAD(m_util);
		}
	}

BOOST_PROTECTED:
	static T* m_lpObj;
	static void *mPtr;
};

//	static なオブジェクト
template <class T> T* intrusive_singleton<T>::m_lpObj = 0;
template <class T> void* intrusive_singleton<T>::mPtr = 0;
/*
//スマン、Lokiのsingletonが使えないので･･･
template <class T,class UTIL=DKConfigUtility>
class phoenix_singleton{
public:
	typedef T self_type;
	typedef UTIL thread_policy;
	phoenix_singleton(){
		//ODS("OK singleton\n");
	}
	virtual ~phoenix_singleton() { Release(); }
	///	ポインタのふりをするための仕掛け　(なるほど！これは便利です。
	T& operator*() { return *get(); }
	T* operator->() { return get();	}
	T* get() { CheckInstance(); return m_lpObj; }
	bool	isNull() const { return m_lpObj == NULL; }
	void Release(){
		if (m_lpObj!=NULL) {
			DKUTIL_LOCKTHREAD(m_util);
			if(m_lpObj!=NULL){		
				delete m_lpObj;
				m_lpObj = NULL;
			}
			DKUTIL_UNLOCKTHREAD(m_util);
		}
	}
	void CheckInstance(){
		if (m_lpObj==NULL) {
			DKUTIL_LOCKTHREAD(m_util);
			if(m_lpObj==NULL){
				m_lpObj = new T;
			}
			DKUTIL_UNLOCKTHREAD(m_util);
		}
	}
BOOST_PROTECTED:
	static T*	m_lpObj;
	UTIL m_util;
};


//	static なオブジェクト
template <class T,class UTIL> T* phenix_singleton<T,UTIL>::m_lpObj = 0;
*/

}//end of dkutil namepsace

#endif //end of include once