/*****************************************************************************/
//
//	qsp.h: Quantum::Superpositions implementation in C/C++ using Boost.PP.
//
//	 $URL: https://yak.myhome.cx/repos/www/trunk/data/junks/dist/qsp.h $
//	$Date: 2010-02-07 23:36:28 +0900 (Sun, 07 Feb 2010) $
//	 $Rev: 266 $
//	 $Id: b584773dad168f74b4b6d9cb12101eed18f6d34a $
//
//		Copyright (c) 2010 Yak!
//
//	This code is distributed under the zlib/libpng License.
//	See http://www.opensource.org/licenses/zlib-license.php
//
/*****************************************************************************/

#ifndef YAK_QSP_H
#define YAK_QSP_H

#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/comparison/equal.hpp>
#include <boost/preprocessor/comparison/greater.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/logical/bitand.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/rest_n.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

#define QSP_ANY_TAG (65)(78)(89)
#define QSP_ALL_TAG (65)(76)(76)
#define QSP_ARG_TAG (65)(82)(71)

#define QSP_ANY QSP_ANY_TAG
#define QSP_ALL QSP_ALL_TAG
#define QSP_ARG QSP_ARG_TAG

#define QSP_SEQ_EQUAL_REPEAT(z, n, data) (BOOST_PP_EQUAL(BOOST_PP_SEQ_ELEM(n, BOOST_PP_TUPLE_ELEM(2, 0, data)), BOOST_PP_SEQ_ELEM(n, BOOST_PP_TUPLE_ELEM(2, 1, data))))
#define QSP_SEQ_EQUAL_FOLD(s, state, elem) BOOST_PP_BITAND(state, elem)

#define QSP_SEQ_TYPE_EQUAL(type, seq) \
	BOOST_PP_SEQ_FOLD_LEFT(\
		QSP_SEQ_EQUAL_FOLD,\
		1,\
		BOOST_PP_REPEAT(\
			3,\
			QSP_SEQ_EQUAL_REPEAT,\
			(type, seq)\
		)\
	)

#define QSP_ARG_NORMALIZE(seq) \
	BOOST_PP_IIF(\
		BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(seq), 3),\
		seq,\
		QSP_ARG_TAG seq\
	)

#define QSP_SFEI_ALL_() &&
#define QSP_SFEI_ANY_() ||

#define QSP_R_R_ALL(z, n, data) \
	BOOST_PP_IIF(BOOST_PP_EQUAL(n, 0), BOOST_PP_EMPTY, QSP_SFEI_ALL_)() \
	(BOOST_PP_TUPLE_ELEM(3,0,data) BOOST_PP_TUPLE_ELEM(3,1,data) BOOST_PP_SEQ_ELEM(n, BOOST_PP_TUPLE_ELEM(3,2,data)))

#define QSP_R_R_ANY(z, n, data) \
	BOOST_PP_IIF(BOOST_PP_EQUAL(n, 0), BOOST_PP_EMPTY, QSP_SFEI_ANY_)() \
	(BOOST_PP_TUPLE_ELEM(3,0,data) BOOST_PP_TUPLE_ELEM(3,1,data) BOOST_PP_SEQ_ELEM(n, BOOST_PP_TUPLE_ELEM(3,2,data)))

#define QSP_R(arg1, op, arg2) \
	BOOST_PP_IIF(\
		QSP_SEQ_TYPE_EQUAL(QSP_ALL_TAG, arg2),\
		(BOOST_PP_REPEAT(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(arg2), 3), QSP_R_R_ALL, (arg1, op, BOOST_PP_SEQ_REST_N(3, arg2)))),\
		BOOST_PP_IIF(\
			QSP_SEQ_TYPE_EQUAL(QSP_ANY_TAG, arg2),\
			(BOOST_PP_REPEAT(BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(arg2), 3), QSP_R_R_ANY, (arg1, op, BOOST_PP_SEQ_REST_N(3, arg2)))),\
			(arg1 op BOOST_PP_SEQ_ELEM(3, arg2))\
		)\
	)

#define QSP_SFEI_ALL(r, data, i, elem) \
	BOOST_PP_IIF(BOOST_PP_EQUAL(i, 0), BOOST_PP_EMPTY, QSP_SFEI_ALL_)() \
	QSP_R(elem, BOOST_PP_TUPLE_ELEM(2,0,data), BOOST_PP_TUPLE_ELEM(2,1,data))

#define QSP_SFEI_ANY(r, data, i, elem) \
	BOOST_PP_IIF(BOOST_PP_EQUAL(i, 0), BOOST_PP_EMPTY, QSP_SFEI_ANY_)() \
	QSP_R(elem, BOOST_PP_TUPLE_ELEM(2,0,data), BOOST_PP_TUPLE_ELEM(2,1,data))

#define QSP_(arg1, op, arg2) \
	BOOST_PP_IIF(\
		QSP_SEQ_TYPE_EQUAL(QSP_ALL_TAG, arg1),\
		(BOOST_PP_SEQ_FOR_EACH_I(QSP_SFEI_ALL, (op, arg2), BOOST_PP_SEQ_REST_N(3, arg1))),\
		BOOST_PP_IIF(\
			QSP_SEQ_TYPE_EQUAL(QSP_ANY_TAG, arg1),\
			(BOOST_PP_SEQ_FOR_EACH_I(QSP_SFEI_ANY, (op, arg2), BOOST_PP_SEQ_REST_N(3, arg1))),\
			QSP_R(BOOST_PP_SEQ_ELEM(3, arg1), op, arg2)\
		)\
	)

#define QSP(arg1, op, arg2) QSP_(QSP_ARG_NORMALIZE(arg1), op, QSP_ARG_NORMALIZE(arg2))

#endif
