//	Roast+ License

//	SIMD

#ifndef __SFJP_OPENMGL_roast_vecpro_HPP__
#define __SFJP_OPENMGL_roast_vecpro_HPP__

#include "roast/simd_lambda/simd_core.hpp"
#include "roast/std/parallelable.hpp"
#include <string>
#include <memory.h>

namespace roast{

	class vecpro_exeption
	{
	protected:
		std::string m_msg;
	public:
		vecpro_exeption(const char* msg){ m_msg = msg; }
		const char* get(){ return m_msg.c_str(); }
	};

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

	template <int _SIMD_Ty, typename _SIMD_CLASS, int _FLOAT_COUNT, int _START_INDEX>	/*	_SIMD_Ty = ROAST_PARALLELABLE_TYPE_〜 (by roast/std/parallelable.hpp)	*/
	class vecpro
	{
	public:
		//	Constructor/Destructor
		vecpro(){
		}
		vecpro(float *f_array_4, unsigned int float_count, int xmm_start=0)
		{
			vecpro();
			load_floats( f_array_4, float_count, xmm_start );
		}
		virtual ~vecpro(){}

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

		//	複数のfloat型をロードします。
		//	- float_countは4の倍数である必要があります
		//	- xmm_startにXMM_START_TAILを指定するか省略すると、自動で空いているxmmを探し、割り当てます。
		//	  ただしこの場合速度が低下するため、自分で番号を指定するのが好ましいです。なお1〜8の間で指定します。
		//	- XMMにfloat_count個分のfloatを格納するための連続した空き領域がないと、vecpro_exeption 例外を投げます。
		inline vecpro& load_al_floats(const float *p_floats, unsigned int float_count){
			return load_aligned_floats( p_floats, float_count );
		}
		inline vecpro& load_aligned_floats(const float *p_floats, unsigned int float_count)
		{
			//	SSEです。
			if ( _SIMD_Ty >= ROAST_PARALLELABLE_TYPE_SIMD_SSE &&
				 _SIMD_Ty <= ROAST_PARALLELABLE_TYPE_SIMD_SSE_END )
			{
				const float *p_floats2 = p_floats - _START_INDEX;

				switch(_START_INDEX)
				{
				case 0:
					_SIMD_CLASS::movaps(0, p_floats2);

				case 4:
					if ( float_count+_START_INDEX <= 4 )
						break;
					_SIMD_CLASS::movaps(1, p_floats2+4);

				case 8:
					if ( float_count+_START_INDEX <= 8 )
						break;
					_SIMD_CLASS::movaps(2, p_floats2+8);

				case 12:
					if ( float_count+_START_INDEX <= 12 )
						break;
					_SIMD_CLASS::movaps(3, p_floats2+12);

				case 16:
					if ( float_count+_START_INDEX <= 16 )
						break;
					_SIMD_CLASS::movaps(4, p_floats2+16);

				case 20:
					if ( float_count+_START_INDEX <= 20 )
						break;
					_SIMD_CLASS::movaps(5, p_floats2+20);

				case 24:
					if ( float_count+_START_INDEX <= 24 )
						break;
					_SIMD_CLASS::movaps(6, p_floats2+24);

				case 28:
					if ( float_count+_START_INDEX <= 28 )
						break;
					_SIMD_CLASS::movaps(7, p_floats2+28);
				}
				/*
				if ( p_floats2 >= p_floats )
					_SIMD_CLASS::movaps(0, p_floats2);

				if ( p_floats2+4 >= p_floats )
					_SIMD_CLASS::movaps(1, p_floats2+4);

				if ( p_floats2+8 >= p_floats )
					_SIMD_CLASS::movaps(2, p_floats2+8);

				if ( p_floats2+12 >= p_floats )
					_SIMD_CLASS::movaps(3, p_floats2+12);

				if ( p_floats2+16 >= p_floats )
					_SIMD_CLASS::movaps(4, p_floats2+16);

				if ( p_floats2+20 >= p_floats )
					_SIMD_CLASS::movaps(5, p_floats2+20);

				if ( p_floats2+24 >= p_floats )
					_SIMD_CLASS::movaps(6, p_floats2+24);

				if ( p_floats2+28 >= p_floats )
					_SIMD_CLASS::movaps(7, p_floats2+28);
				*/
			}

			return *this;
		}

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

		class vecpro_ary
		{

		};

		/*vecpro& operator ,(const vecpro& left/*, const vecpro& right*)
		{
			m_low_index = left.m_low_index + 1;
			return *this;
		}*/
		vecpro& operator ,(const vecpro& left/*, const vecpro& right*/)
		{
			m_low_index = left.m_low_index + 1;
			return *this;
		}
	};

	/*typedef vecpro<ROAST_PARALLELABLE_TYPE_SIMD_SSE, roast::simd::sse1> vecpro_sse;
	typedef vecpro<ROAST_PARALLELABLE_TYPE_SIMD_SSE2, roast::simd::sse2> vecpro_sse2;
	typedef vecpro<ROAST_PARALLELABLE_TYPE_SIMD_SSE3, roast::simd::sse3> vecpro_sse3;
	typedef vecpro<ROAST_PARALLELABLE_TYPE_SIMD_SSE4, roast::simd::sse4> vecpro_sse4;*/
	/*typedef vecpro<roast::simd::sse1, 32> vecpro_sse;
	typedef vecpro<roast::simd::sse2, 32> vecpro_sse2;
	typedef vecpro<roast::simd::sse3, 32> vecpro_sse3;
	typedef vecpro<roast::simd::sse4, 32> vecpro_sse4;*/
	template <int start_index>
	class vecpro_sse2 : public vecpro<ROAST_PARALLELABLE_TYPE_SIMD_SSE2, roast::simd::sse2, 32, start_index>{};
}

#endif//__SFJP_OPENMGL_roast_vecpro_HPP__
