#pragma once
#include <istream>
#include <xutility>
namespace std
{
// 34
#define _RNG_PROHIBIT_CHAR(_CheckedType)               \
	static_assert(!_Is_character<_CheckedType>::value, \
				  "note: char, signed char, unsigned char, char8_t, int8_t, and uint8_t are not allowed")
	// 38
// 50
#define _RNG_REQUIRE_UINTTYPE(_RandType, _CheckedType)                                                               \
	static_assert(_Is_any_of_v<_CheckedType, unsigned short, unsigned int, unsigned long, unsigned long long>,       \
				  "invalid template argument for " #_RandType ": N4659 29.6.1.1 [rand.req.genl]/1f requires one of " \
				  "unsigned short, unsigned int, unsigned long, or unsigned long long");                             \
	_RNG_PROHIBIT_CHAR(_CheckedType)

	template <class _Seed_seq, class _Self, class _Engine = _Self>
	using _Enable_if_seed_seq_t =
		enable_if_t<!is_convertible_v<remove_cv_t<_Seed_seq>, typename _Self::result_type> && !is_same_v<remove_cv_t<_Seed_seq>, _Self> && !is_same_v<remove_cv_t<_Seed_seq>, _Engine>,
					int>;
	// 62
	// 128
	template <class _Elem, class _Traits, class _Ty>
	class _Wrap_istream
	{ // wrap input stream as function object
	public:
		_Wrap_istream(basic_istream<_Elem, _Traits> &_Is) : _Str(_Is) {}

		_Ty operator()()
		{ // read next value
			_Ty _Data;
			_Str >> _Data;

			return _Data;
		}

		_Wrap_istream &operator=(const _Wrap_istream &) = delete;

	private:
		basic_istream<_Elem, _Traits> &_Str;
	};
	// 149
	// 609
	template <class _Ty, size_t _Nw>
	struct _Circ_buf
	{ // holds historical values for generators
		_Ty _At(size_t _Ix) const
		{
			return _Ax[_Base(_Ix)];
		}

		bool _Equals(const _Circ_buf &_Right) const
		{
			const _Ty *_Last1 = _Ax + _Idx;
			const _Ty *_Last2 = _Right._Ax + _Right._Idx;
			const _Ty *_First;
			const _Ty *_Last;
			const _Ty *_Other;
			bool _Use2 = _Base() < _Right._Base();

			if (_Use2)
			{ // _Right's range is higher up in the array
			  // than ours, so scan it first
				_First = _Right._Ax + _Right._Base();
				_Last = _Last2;
				_Other = _Ax + _Base();
			}
			else
			{ // our range is higher up in the array
			  // than _Right's, so scan ours first
				_First = _Ax + _Base();
				_Last = _Last1;
				_Other = _Right._Ax + _Right._Base();
			}

			ptrdiff_t _Nx0 = _Nw;
			while (0 < _Nx0)
			{ // scan
			  // note: may need up to three passes; each scan starts at the
			  // current highest array position and ends at the end of the
			  // array or the _Idx value, whichever comes first; the
			  // equality test succeeds only by reaching the _Idx value.
				const _Ty *_Limit = _First < _Last ? _Last : _Use2 ? _Right._Ax + 2 * _Nw
																   : _Ax + 2 * _Nw;
				_Nx0 -= _Limit - _First;
				while (_First != _Limit)
				{
					if (*_First++ != *_Other++)
					{
						return false;
					}
				}

				_First = _Other;
				_Last = _Use2 ? _Last1 : _Last2;
				_Other = _Use2 ? _Right._Ax : _Ax;
				_Use2 = !_Use2;
			}
			return true;
		}

		size_t _Base(size_t _Ix = 0) const
		{
			return (_Ix += _Idx) < _Nw ? (_Ix + _Nw) : (_Ix - _Nw);
		}

		unsigned int _Idx;
		_Ty _Ax[2 * _Nw];
	};
	// 665
	// 1087
	template <class _Ty, int _Wx, int _Nx, int _Mx, int _Rx, _Ty _Px, int _Ux, int _Sx, _Ty _Bx, int _Tx, _Ty _Cx, int _Lx>
	class mersenne_twister : public _Circ_buf<_Ty, _Nx>
	{ // mersenne twister generator
	public:
		using result_type = _Ty;

		static constexpr int word_size = _Wx;
		static constexpr int state_size = _Nx;
		static constexpr int shift_size = _Mx;
		static constexpr int mask_bits = _Rx;
		static constexpr _Ty parameter_a = _Px;
		static constexpr int output_u = _Ux;
		static constexpr int output_s = _Sx;
		static constexpr _Ty output_b = _Bx;
		static constexpr int output_t = _Tx;
		static constexpr _Ty output_c = _Cx;
		static constexpr int output_l = _Lx;

		static constexpr _Ty default_seed = 5489U;

		mersenne_twister() : _Dxval(_WMSK)
		{
			seed(default_seed, static_cast<_Ty>(1812433253));
		}

		explicit mersenne_twister(_Ty _Xx0, _Ty _Dxarg = _WMSK, _Ty _Fxarg = static_cast<_Ty>(1812433253))
			: _Dxval(_Dxarg)
		{
			seed(_Xx0, _Fxarg);
		}

		template <class _Gen, _Enable_if_seed_seq_t<_Gen, mersenne_twister> = 0>
		explicit mersenne_twister(_Gen &_Gx) : _Dxval(_WMSK)
		{
			seed(_Gx);
		}

		void seed(_Ty _Xx0 = default_seed, _Ty _Fx = static_cast<_Ty>(1812433253))
		{
			// set initial values from specified value
			_Ty _Prev = this->_Ax[0] = _Xx0 & _WMSK;
			for (size_t _Ix = 1; _Ix < _Nx; ++_Ix)
			{
				_Prev = this->_Ax[_Ix] = (_Ix + _Fx * (_Prev ^ (_Prev >> (_Wx - 2)))) & _WMSK;
			}

			this->_Idx = _Nx;
		}

		template <class _Gen, _Enable_if_seed_seq_t<_Gen, mersenne_twister> = 0>
		void seed(_Gen &_Gx, bool = false)
		{ // set initial values from range
			for (size_t _Ix = 0; _Ix < _Nx; ++_Ix)
			{
				this->_Ax[_Ix] = _Gx() & _WMSK;
			}

			this->_Idx = _Nx;
		}

		_NODISCARD_FRIEND bool operator==(const mersenne_twister &_Left, const mersenne_twister &_Right)
		{
			return _Left._Equals(_Right);
		}

#if !_HAS_CXX20
		_NODISCARD_FRIEND bool operator!=(const mersenne_twister &_Left, const mersenne_twister &_Right)
		{
			return !_Left._Equals(_Right);
		}
#endif // !_HAS_CXX20

		template <class _Elem, class _S_Traits>
		friend basic_istream<_Elem, _S_Traits> &operator>>(basic_istream<_Elem, _S_Traits> &_Istr,
														   mersenne_twister &_Eng)
		{ // read state from _Istr
			_Wrap_istream<_Elem, _S_Traits, _Ty> _Gen(_Istr);
			_Eng.seed(_Gen);
			return _Istr;
		}

		template <class _Elem, class _S_Traits>
		friend basic_ostream<_Elem, _S_Traits> &operator<<(basic_ostream<_Elem, _S_Traits> &_Ostr,
														   const mersenne_twister &_Eng)
		{ // write state to _Ostr
			_Ostr << _Eng._At(0);

			for (size_t _Ix = 1; _Ix < mersenne_twister::state_size; ++_Ix)
			{
				_Ostr << ' ' << _Eng._At(_Ix);
			}

			return _Ostr;
		}

		_NODISCARD result_type(min)() const
		{
			return 0;
		}

		_NODISCARD result_type(max)() const
		{
			return _WMSK;
		}

		_NODISCARD result_type operator()()
		{
			if (this->_Idx == _Nx)
			{
				_Refill_upper();
			}
			else if (2 * _Nx <= this->_Idx)
			{
				_Refill_lower();
			}

			_Ty _Res = this->_Ax[this->_Idx++] & _WMSK;
			_Res ^= (_Res >> _Ux) & _Dxval;
			_Res ^= (_Res << _Sx) & _Bx;
			_Res ^= (_Res << _Tx) & _Cx;
			_Res ^= (_Res & _WMSK) >> _Lx;
			return _Res;
		}

		void discard(unsigned long long _Nskip)
		{ // discard _Nskip elements
			for (; 0 < _Nskip; --_Nskip)
			{
				(void)(*this)();
			}
		}

	protected:
		void _Refill_lower()
		{
			// compute values for the lower half of the history array
			constexpr size_t _Wrap_bound_one = _Nx - _One_mod_n;
			constexpr size_t _Wrap_bound_m = _Nx - _M_mod_n;

			if constexpr (_M_mod_n == 0)
			{
				for (size_t _Ix = 0; _Ix < _Wrap_bound_one; ++_Ix)
				{ // fill in values
					const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK);
					this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n];
				}

				if constexpr (_One_mod_n == 1)
				{ // fill in _Ax[_Nx - 1]
					constexpr size_t _Ix = _Wrap_bound_one;

					const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK);
					this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n];
				}
			}
			else
			{
				for (size_t _Ix = 0; _Ix < _Wrap_bound_m; ++_Ix)
				{ // fill in lower region
					const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK);
					this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix + _Nx + _M_mod_n];
				}

				for (size_t _Ix = _Wrap_bound_m; _Ix < _Wrap_bound_one; ++_Ix)
				{
					// fill in upper region (avoids modulus operation)
					const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix + _Nx + _One_mod_n] & _LMSK);
					this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n];
				}

				if constexpr (_One_mod_n == 1)
				{ // fill in _Ax[_Nx - 1]
					constexpr size_t _Ix = _Wrap_bound_one;

					const _Ty _Tmp = (this->_Ax[_Ix + _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK);
					this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n];
				}
			}

			this->_Idx = 0;
		}

		void _Refill_upper()
		{ // compute values for the upper half of the history array
			for (size_t _Ix = _Nx; _Ix < 2 * _Nx; ++_Ix)
			{ // fill in values
				const _Ty _Tmp = (this->_Ax[_Ix - _Nx] & _HMSK) | (this->_Ax[_Ix - _Nx + _One_mod_n] & _LMSK);
				this->_Ax[_Ix] = (_Tmp >> 1) ^ (_Tmp & 1 ? _Px : 0) ^ this->_Ax[_Ix - _Nx + _M_mod_n];
			}
		}

		_Ty _Dxval;

		static constexpr _Ty _WMSK = ~((~_Ty{0} << (_Wx - 1)) << 1);
		static constexpr _Ty _HMSK = (_WMSK << _Rx) & _WMSK;
		static constexpr _Ty _LMSK = ~_HMSK & _WMSK;

		static constexpr int _One_mod_n = 1 % _Nx; // either 0 or 1
		static constexpr int _M_mod_n = _Mx % _Nx;
	};
	_EXPORT_STD template <class _Ty, size_t _Wx, size_t _Nx, size_t _Mx, size_t _Rx, _Ty _Px, size_t _Ux, _Ty _Dx,
						  size_t _Sx, _Ty _Bx, size_t _Tx, _Ty _Cx, size_t _Lx, _Ty _Fx>
	class mersenne_twister_engine : public mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx>
	{
	public:
		static constexpr unsigned long long _Max = (((1ULL << (_Wx - 1)) - 1) << 1) + 1;

		_RNG_REQUIRE_UINTTYPE(mersenne_twister_engine, _Ty);
		static_assert(0 < _Mx && _Mx <= _Nx && 2U < _Wx && _Rx <= _Wx && _Ux <= _Wx && _Sx <= _Wx && _Tx <= _Wx && _Lx <= _Wx && 16 <= numeric_limits<_Ty>::digits && _Px <= _Max && _Bx <= _Max && _Cx <= _Max && _Dx <= _Max && _Fx <= _Max,
					  "invalid template argument for mersenne_twister_engine");

		using _Mybase = mersenne_twister<_Ty, _Wx, _Nx, _Mx, _Rx, _Px, _Ux, _Sx, _Bx, _Tx, _Cx, _Lx>;
		using result_type = _Ty;

		static constexpr size_t word_size = _Wx;
		static constexpr size_t state_size = _Nx;
		static constexpr size_t shift_size = _Mx;
		static constexpr size_t mask_bits = _Rx;
		static constexpr _Ty xor_mask = _Px;
		static constexpr size_t tempering_u = _Ux;
		static constexpr _Ty tempering_d = _Dx;
		static constexpr size_t tempering_s = _Sx;
		static constexpr _Ty tempering_b = _Bx;
		static constexpr size_t tempering_t = _Tx;
		static constexpr _Ty tempering_c = _Cx;
		static constexpr size_t tempering_l = _Lx;
		static constexpr _Ty initialization_multiplier = _Fx;

		static constexpr result_type default_seed = 5489U;

		mersenne_twister_engine() : _Mybase(default_seed, _Dx, _Fx) {}

		explicit mersenne_twister_engine(result_type _Xx0) : _Mybase(_Xx0, _Dx, _Fx) {}

		template <class _Seed_seq, _Enable_if_seed_seq_t<_Seed_seq, mersenne_twister_engine> = 0>
		explicit mersenne_twister_engine(_Seed_seq &_Seq) : _Mybase(default_seed, _Dx, _Fx)
		{
			seed(_Seq);
		}

		void seed(result_type _Xx0 = default_seed)
		{ // set initial values from specified value
			_Mybase::seed(_Xx0, _Fx);
		}

		template <class _Seed_seq, _Enable_if_seed_seq_t<_Seed_seq, mersenne_twister_engine> = 0>
		void seed(_Seed_seq &_Seq)
		{ // reset sequence from seed sequence
			constexpr int _Kx = (_Wx + 31) / 32;
			unsigned long _Arr[_Kx * _Nx];
			_Seq.generate(&_Arr[0], &_Arr[_Kx * _Nx]);

			int _Idx0 = 0;
			_Ty _Sum = 0;
			for (size_t _Ix = 0; _Ix < _Nx; ++_Ix, _Idx0 += _Kx)
			{ // pack _Kx words
				this->_Ax[_Ix] = static_cast<_Ty>(_Arr[_Idx0]);
				for (int _Jx = 1; _Jx < _Kx; ++_Jx)
				{
					this->_Ax[_Ix] |= static_cast<_Ty>(_Arr[_Idx0 + _Jx]) << (32 * _Jx);
				}

				this->_Ax[_Ix] &= this->_WMSK;

				if (_Ix == 0)
				{
					_Sum = this->_Ax[_Ix] >> _Rx;
				}
				else
				{
					_Sum |= this->_Ax[_Ix];
				}
			}

			if (_Sum == 0)
			{
				this->_Ax[0] = _Ty{1} << (_Wx - 1);
			}

			this->_Idx = _Nx;
		}

		_NODISCARD static constexpr result_type(min)()
		{
			return 0;
		}

		_NODISCARD static constexpr result_type(max)()
		{
			return _Mybase::_WMSK;
		}
	};
	// 1340
	// 5039
	// MSVC这里原文是unsigned int，但Arduino上该数值类型实际上是uint16_t而不是uint32_t，因此需要修改
	// 此对象将占用5K内存，请谨慎使用
	_EXPORT_STD using mt19937 = mersenne_twister_engine<uint32_t, 32, 624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7,
														0x9d2c5680, 15, 0xefc60000, 18, 1812433253>;
	// 5042
	struct ArduinoUrng
	{
		//UniformRandomBitGenerator要求无符号整数
		using result_type = make_unsigned_t<decltype(random())>;
		static constexpr result_type max()
		{
			return numeric_limits<result_type>::max();
		};
		static constexpr result_type min()
		{
			return 0;
		};
		result_type operator()() const
		{
			return random();
		}
		static void seed(uint32_t S)
		{
			randomSeed(S);
		}
	};
}
