/*
	© 2013-2015 FrankHB.

	This file is part of the YSLib project, and may only be used,
	modified, and distributed under the terms of the YSLib project
	license, LICENSE.TXT.  By continuing to use, modify, or distribute
	this file you indicate that you have read the license and
	understand and accept it fully.
*/

/*!	\file variadic.hpp
\ingroup YStandardEx
\brief C++ 变长参数相关操作。
\version r710
\author FrankHB <frankhb1989@gmail.com>
\since build 412
\par 创建时间:
	2013-06-06 11:38:15 +0800
\par 修改时间:
	2015-04-09 17:17 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	YStandardEx::Variadic
*/


#ifndef YB_INC_ystdex_variadic_hpp_
#define YB_INC_ystdex_variadic_hpp_ 1

#include "../ydef.h" // for ystdex::size_t;

namespace ystdex
{

/*!	\defgroup vseq_operations Variadic Sequence Operations
\ingroup meta_operations
\brief 变长参数标记的序列相关的元操作。
\since build 447

形式为模板类名声明和特化的相关操作，被操作的序列是类类型。
除此处的特化外，可有其它类类型的特化。
特化至少需保证具有表示和此处特化意义相同的 type 类型成员，并可能有其它成员。
对非类型元素，成员 value 表示结果，成员 type 表示对应的序列类型。
*/


//! \since build 589
namespace vseq
{

/*!
\ingroup vseq_operations
\since build 589
*/
//@{
#define YB_Impl_Variadic_SeqOp(_n, _tparams, _targs) \
	template<_tparams> \
	struct _n; \
	\
	template<_tparams> \
	using _n##_t = typename _n<_targs>::type;
#define YB_Impl_Variadic_SeqOpU(_n) \
	YB_Impl_Variadic_SeqOp(_n, class _tSeq, _tSeq)
#define YB_Impl_Variadic_SeqOpB(_n) YB_Impl_Variadic_SeqOp(_n, class _tSeq1 \
	YPP_Comma class _tSeq2, _tSeq1 YPP_Comma _tSeq2)
#define YB_Impl_Variadic_SeqOpI(_n) YB_Impl_Variadic_SeqOp(_n, class _tSeq \
	YPP_Comma size_t _vIdx, _tSeq YPP_Comma _vIdx)
#define YB_Impl_Variadic_SeqOpN(_n) YB_Impl_Variadic_SeqOp(_n, size_t _vN \
	YPP_Comma class _tSeq, _vN YPP_Comma _tSeq)

//! \brief 取序列元素数。
YB_Impl_Variadic_SeqOpU(seq_size)


//! \brief 清除序列。
YB_Impl_Variadic_SeqOpU(clear)


//! \brief 合并序列。
YB_Impl_Variadic_SeqOpB(concat)


//! \brief 取序列最后一个元素。
YB_Impl_Variadic_SeqOpU(back)


//! \brief 取序列第一个元素。
YB_Impl_Variadic_SeqOpU(front)


//! \brief 取序列最后元素以外的元素的序列。
YB_Impl_Variadic_SeqOpU(pop_back)


//! \brief 取序列第一个元素以外的元素的序列。
YB_Impl_Variadic_SeqOpU(pop_front)


//! \brief 取在序列末尾插入一个元素的序列。
YB_Impl_Variadic_SeqOp(push_back, class _tSeq YPP_Comma typename _tItem,
	_tSeq YPP_Comma _tItem)


//! \brief 取在序列起始插入一个元素的序列。
YB_Impl_Variadic_SeqOp(push_front, class _tSeq YPP_Comma typename _tItem,
	_tSeq YPP_Comma _tItem)


//! \brief 投影操作。
YB_Impl_Variadic_SeqOp(project, class _tSeq YPP_Comma class _tIdxSeq,
	_tSeq YPP_Comma _tIdxSeq)


//! \brief 取指定位置的元素。
//@{
YB_Impl_Variadic_SeqOpI(at)

template<class _tSeq, size_t _vIdx>
struct at : at<pop_front_t<_tSeq>, _vIdx - 1>
{};

template<class _tSeq>
struct at<_tSeq, 0> : front<_tSeq>
{};
//@}


//! \brief 拆分序列前若干元素。
//@{
YB_Impl_Variadic_SeqOpN(split_n)

//! \note 使用二分实现减少递归实例化深度。
template<size_t _vN, class _tSeq>
struct split_n
{
private:
	using half = split_n<_vN / 2, _tSeq>;
	using last = split_n<_vN - _vN / 2, typename half::tail>;

public:
	using type = concat_t<typename half::type, typename last::type>;
	using tail = typename last::tail;
};

template<class _tSeq>
struct split_n<0, _tSeq>
{
	using type = clear_t<_tSeq>;
	using tail = _tSeq;
};

template<class _tSeq>
struct split_n<1, _tSeq>
{
	using type = front_t<_tSeq>;
	using tail = pop_front_t<_tSeq>;
};
//@}


//! \brief 删除指定位置的元素。
//@{
YB_Impl_Variadic_SeqOp(erase, class _tSeq YPP_Comma size_t _vIdx YPP_Comma \
	size_t _vEnd = _vIdx + 1, _tSeq YPP_Comma _vIdx YPP_Comma _vEnd)

template<class _tSeq, size_t _vIdx, size_t _vEnd>
struct erase
{
	static_assert(_vIdx <= _vEnd, "Invalid range found.");

public:
	using type = concat_t<split_n_t<_vIdx, _tSeq>,
		typename split_n<_vEnd, _tSeq>::tail>;
};
//@}


//! \brief 查找元素。
//@{
YB_Impl_Variadic_SeqOp(find, class _tSeq YPP_Comma typename _type,
	_tSeq YPP_Comma _type)

namespace details
{

template<size_t _vN, class _tSeq, typename _type>
struct find
{
	static yconstexpr size_t value = std::is_same<front_t<_tSeq>, _type>::value
		? 0 : find<_vN - 1, pop_front_t<_tSeq>, _type>::value + 1;
};

template<class _tSeq, typename _type>
struct find<0, _tSeq, _type>
{
	static yconstexpr size_t value = 0;
};

} // namespace details;

template<class _tSeq, typename _type>
struct find : std::integral_constant<size_t,
	details::find<seq_size<_tSeq>::value, _tSeq, _type>::value>
{};
//@}


//! \brief 取合并相同元素后的序列。
//@{
YB_Impl_Variadic_SeqOpU(deduplicate)

namespace details
{

template<size_t, class _tSeq>
struct deduplicate
{
private:
	using head = pop_back_t<_tSeq>;
	using tail = back_t<_tSeq>;
	using sub = deduplicate_t<head>;

public:
	using type = typename std::conditional<vseq::find<head, tail>::value
		== seq_size<head>::value, concat_t<sub, tail>, sub>::type;
};

template<class _tSeq>
struct deduplicate<0, _tSeq>
{
	using type = _tSeq;
};

template<class _tSeq>
struct deduplicate<1, _tSeq>
{
	using type = _tSeq;
};

} // namespace details;

template<class _tSeq>
struct deduplicate
{
	using type
		= typename details::deduplicate<seq_size<_tSeq>::value, _tSeq>::type;
};
//@}


//! \brief 重复连接序列元素。
//@{
YB_Impl_Variadic_SeqOpN(join_n)

//! \note 使用二分实现减少递归实例化深度。
template<size_t _vN, class _tSeq>
struct join_n
{
private:
	using unit = _tSeq;
	using half = join_n_t<_vN / 2, unit>;

public:
	using type = concat_t<concat_t<half, half>, join_n_t<_vN % 2, unit>>;
};

template<class _tSeq>
struct join_n<0, _tSeq>
{
	using type = clear_t<_tSeq>;
};

template<class _tSeq>
struct join_n<1, _tSeq>
{
	using type = _tSeq;
};
//@}


//! \brief 取逆序列。
//@{
YB_Impl_Variadic_SeqOpU(reverse)

template<class _tSeq>
struct reverse
{
	using type = typename std::conditional<seq_size<_tSeq>::value == 0,
		clear_t<_tSeq>, concat_t<reverse_t<pop_front_t<_tSeq>>, front_t<_tSeq>>
		>::type;
};
//@}


//! \brief 取合并相邻相同元素后的序列。
//@{
YB_Impl_Variadic_SeqOpU(unique)

namespace details
{

template<size_t, class _tSeq>
struct unique
{
	using head = front_t<_tSeq>;
	using type = concat_t<head, unique_t<typename split_n<
		std::is_same<head, at<_tSeq, 1>>::value ? 2 : 1, _tSeq>::tail>>;
};

template<class _tSeq>
struct unique<0, _tSeq>
{
	using type = clear_t<_tSeq>;
};

template<class _tSeq>
struct unique<1, _tSeq>
{
	using type = _tSeq;
};

} // namespace details;

template<class _tSeq>
struct unique
{
	using type = typename details::unique<seq_size<_tSeq>::value, _tSeq>::type;
};


/*!
\brief 二元操作合并应用。
\pre 二元操作符合交换律和结合律。
*/
YB_Impl_Variadic_SeqOp(fold, class _fBinary YPP_Comma typename \
	_tState YPP_Comma class _type, _fBinary YPP_Comma _tState YPP_Comma _type)


//! \brief 序列作为向量的加法。
YB_Impl_Variadic_SeqOpB(vec_add)


//! \brief 序列作为向量的减法。
YB_Impl_Variadic_SeqOpB(vec_subtract)

#undef YB_Impl_Variadic_SeqOpN
#undef YB_Impl_Variadic_SeqOpI
#undef YB_Impl_Variadic_SeqOpU
#undef YB_Impl_Variadic_SeqOp
//@}

} // namespace vseq;

} // namespace ystdex;

#endif

