//	Roast+ License
/*
	
*/
#ifndef __SFJP_OPENMGL_roast_parallelable_HPP__
#define __SFJP_OPENMGL_roast_parallelable_HPP__

//#include "roast/std/thread.hpp"

#define ROAST_PARALLELABLE_TYPE_NULL		(0)
#define ROAST_PARALLELABLE_TYPE_THREAD		(10)
#define ROAST_PARALLELABLE_TYPE_GPGPU		(20)

#define ROAST_PARALLELABLE_TYPE_SIMD_AUTO	(60)
#define ROAST_PARALLELABLE_TYPE_SIMD		(ROAST_PARALLELABLE_TYPE_SIMD_AUTO)
#define ROAST_PARALLELABLE_TYPE_SIMD_MMX	(ROAST_PARALLELABLE_TYPE_SIMD+1)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE	(ROAST_PARALLELABLE_TYPE_SIMD+2)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE2	(ROAST_PARALLELABLE_TYPE_SIMD+3)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE3	(ROAST_PARALLELABLE_TYPE_SIMD+4)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE4	(ROAST_PARALLELABLE_TYPE_SIMD+5)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE41	(ROAST_PARALLELABLE_TYPE_SIMD+6)
#define ROAST_PARALLELABLE_TYPE_SIMD_SSE42	(ROAST_PARALLELABLE_TYPE_SIMD+7)
#define ROAST_PARALLELABLE_TYPE_SIMD_AVX	(ROAST_PARALLELABLE_TYPE_SIMD+16)

#define ROAST_PARALLELABLE_TYPE_SIMD_3DNOW	(ROAST_PARALLELABLE_TYPE_SIMD+30)

#define ROAST_PARALLELABLE_TYPE_DEFAULT		(ROAST_PARALLELABLE_TYPE_THREAD)
#define ROAST_PARALLELABLE_TYPE_AUTO		(ROAST_PARALLELABLE_TYPE_DEFAULT)


////////////////////////////////////////////////////

#define _ROAST_parallelable__TMPL_ARGS_CALLBACK(N)		typename PARAM_T ## N
#define _ROAST_parallelable__FUNC_ARGS_CALLBACK(N)		PARAM_T ## N  param ## N
#define _ROAST_parallelable__CALL_ARGS_CALLBACK(N)		param ## N


#define _ROAST_parallelable__CLASS_DECLARE_X(N)		\
	template <typename RET_T,	\
		ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__TMPL_ARGS_CALLBACK),	\
		bool enable_prallel=false, int parallel_type=ROAST_PARALLELABLE_TYPE_DEFAULT >	\
	class parallelable ## N	\
	{	\
	public:	\
		class _CDummyBase{}; /* ダミークラス（コンパイラを誤魔化すためだけに・・・ */	\
		typedef RET_T (_CDummyBase::*CLASS_FUNC_PTR)(	\
			ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__FUNC_ARGS_CALLBACK));	\
	protected:	\
		void* m_pClassInstance;	\
		CLASS_FUNC_PTR m_pFunc;	\
		RET_T m_ret;	\
	\
	public:	\
		/*	Constructor/Destructor	*/	\
		parallelable ## N(void* pClassInstance, CLASS_FUNC_PTR pFunc){	\
			set(pClassInstance, pFunc);	\
		}	\
		virtual ~parallelable ## N(){}	\
		\
		void set(void* pClassInstance, CLASS_FUNC_PTR pFunc){	\
			m_pClassInstance = pClassInstance;	\
			m_pFunc = pFunc;\
		}	\
		\
		RET_T& call(	\
			ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__FUNC_ARGS_CALLBACK) )	\
		{	\
			m_ret = (((_CDummyBase*)m_pClassInstance)->*(m_pFunc))(	\
				ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__CALL_ARGS_CALLBACK) );	\
			return m_ret;	\
		}	\
		RET_T& get_ret(){ return m_ret; }	\
		\
		enum {	\
			TYPE_DEFAULT = ROAST_PARALLELABLE_TYPE_DEFAULT,	\
			TYPE_THREAD = ROAST_PARALLELABLE_TYPE_THREAD,	\
			TYPE_GPGPU = ROAST_PARALLELABLE_TYPE_GPGPU,	\
			TYPE_SIMD = ROAST_PARALLELABLE_TYPE_SIMD	\
		};	\
	};
	
/////////////////////////////////////////////////////


namespace roast{

	template <typename RET_T, bool enable_prallel=false, int parallel_type=ROAST_PARALLELABLE_TYPE_DEFAULT>
	class parallelable0
	{
	public:
		//	Constructor/Destructor
		parallelable0(){}
		virtual ~parallelable0(){}

		////////////////////////////////////////

		enum {
			TYPE_DEFAULT = ROAST_PARALLELABLE_TYPE_DEFAULT,
			TYPE_THREAD = ROAST_PARALLELABLE_TYPE_THREAD,
			TYPE_GPGPU = ROAST_PARALLELABLE_TYPE_GPGPU,
			TYPE_SIMD = ROAST_PARALLELABLE_TYPE_SIMD
		};
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
	template <typename FUNCOBJ_T, bool enable_prallel=false, int parallel_type=ROAST_PARALLELABLE_TYPE_DEFAULT>
	class parallelable_fast
	{
	public:
		typedef FUNCOBJ_T._CDummyBase CLASS_TYPE;
		typedef FUNCOBJ_T.CLASS_FUNC_PTR CLASS_FUNC_PTR;
		typedef FUNCOBJ_T.RET_T RET_T;

	protected:
		void* m_pClassInstance;
		CLASS_FUNC_PTR m_pFunc;
		RET_T m_ret;

	public:
		//	Constructor/Destructor
		parallelable_fast(CLASS_TYPE pClassInstance, CLASS_FUNC_PTR pFunc){
			set(pClassInstance, pFunc);
		}
		virtual ~parallelable_fast(){}
	
		void set(CLASS_TYPE pClassInstance, CLASS_FUNC_PTR pFunc){
			m_pClassInstance = pClassInstance;
			m_pFunc = pFunc;
		}
	
		RET_T& call(
			ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__FUNC_ARGS_CALLBACK) )
		{
			m_ret = (((_CDummyBase*)m_pClassInstance)->*(m_pFunc))(
				ROAST_PP_COMMA_REPEART_INC(N, _ROAST_parallelable__CALL_ARGS_CALLBACK) );
			return m_ret;
		}
		RET_T& get_ret(){ return m_ret; }	
		
		////////////////////////////////////////

		enum {
			TYPE_DEFAULT = ROAST_PARALLELABLE_TYPE_DEFAULT,
			TYPE_THREAD = ROAST_PARALLELABLE_TYPE_THREAD,
			TYPE_GPGPU = ROAST_PARALLELABLE_TYPE_GPGPU,
			TYPE_SIMD = ROAST_PARALLELABLE_TYPE_SIMD
		};
	};*/

_ROAST_parallelable__CLASS_DECLARE_X(1)

}

#endif//__SFJP_OPENMGL_roast_parallelable_HPP__
