// array standard header
#pragma once
#ifndef _ARRAY_
#define _ARRAY_
#ifndef RC_INVOKED
#include <algorithm>
#include <iterator>
#include <tuple>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,_STL_WARNING_LEVEL)
 #pragma warning(disable: _STL_DISABLED_WARNINGS)
 _STL_DISABLE_CLANG_WARNINGS
 #pragma push_macro("new")
 #undef new

_STD_BEGIN
	// CLASS TEMPLATE array
template<class _Ty,
	size_t _Size>
	class array
	{	// fixed size array of values
public:
	using value_type = _Ty;
	using size_type = size_t;
	using difference_type = ptrdiff_t;
	using pointer = _Ty *;
	using const_pointer = const _Ty *;
	using reference = _Ty&;
	using const_reference = const _Ty&;

	using iterator = _Array_iterator<_Ty, _Size>;
	using const_iterator = _Array_const_iterator<_Ty, _Size>;

	using reverse_iterator = _STD reverse_iterator<iterator>;
	using const_reverse_iterator = _STD reverse_iterator<const_iterator>;

#if _HAS_TR1_NAMESPACE
	_DEPRECATE_TR1_NAMESPACE void assign(const _Ty& _Value)
		{	// assign value to all elements
		_STD fill_n(_Elems, _Size, _Value);
		}
#endif /* _HAS_TR1_NAMESPACE */

	void fill(const _Ty& _Value)
		{	// assign value to all elements
		_STD fill_n(_Elems, _Size, _Value);
		}

	void swap(array& _Other)
		_NOEXCEPT_COND(_Is_nothrow_swappable<_Ty>::value)
		{	// swap contents with _Other
		_Swap_ranges_unchecked(_Elems, _Elems + _Size, _Other._Elems);
		}

	_NODISCARD _CONSTEXPR17 iterator begin() noexcept
		{	// return iterator for beginning of mutable sequence
		return (iterator(_Elems, 0));
		}

	_NODISCARD _CONSTEXPR17 const_iterator begin() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator(_Elems, 0));
		}

	_NODISCARD _CONSTEXPR17 iterator end() noexcept
		{	// return iterator for end of mutable sequence
		return (iterator(_Elems, _Size));
		}

	_NODISCARD _CONSTEXPR17 const_iterator end() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator(_Elems, _Size));
		}

	_NODISCARD _CONSTEXPR17 reverse_iterator rbegin() noexcept
		{	// return iterator for beginning of reversed mutable sequence
		return (reverse_iterator(end()));
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator rbegin() const noexcept
		{	// return iterator for beginning of reversed nonmutable sequence
		return (const_reverse_iterator(end()));
		}

	_NODISCARD _CONSTEXPR17 reverse_iterator rend() noexcept
		{	// return iterator for end of reversed mutable sequence
		return (reverse_iterator(begin()));
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator rend() const noexcept
		{	// return iterator for end of reversed nonmutable sequence
		return (const_reverse_iterator(begin()));
		}

	_NODISCARD _CONSTEXPR17 const_iterator cbegin() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (begin());
		}

	_NODISCARD _CONSTEXPR17 const_iterator cend() const noexcept
		{	// return iterator for end of nonmutable sequence
		return (end());
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator crbegin() const noexcept
		{	// return iterator for beginning of reversed nonmutable sequence
		return (rbegin());
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator crend() const noexcept
		{	// return iterator for end of reversed nonmutable sequence
		return (rend());
		}

	_CONSTEXPR17 _Ty * _Unchecked_begin() noexcept
		{	// return plain pointer to beginning of mutable sequence
		return (_Elems);
		}

	_CONSTEXPR17 const _Ty * _Unchecked_begin() const noexcept
		{	// return plain pointer to beginning of nonmutable sequence
		return (_Elems);
		}

	_CONSTEXPR17 _Ty * _Unchecked_end() noexcept
		{	// return plain pointer to end of mutable sequence
		return (_Elems + _Size);
		}

	_CONSTEXPR17 const _Ty * _Unchecked_end() const noexcept
		{	// return plain pointer to end of nonmutable sequence
		return (_Elems + _Size);
		}

	_NODISCARD constexpr size_type size() const noexcept
		{	// return length of sequence
		return (_Size);
		}

	_NODISCARD constexpr size_type max_size() const noexcept
		{	// return maximum possible length of sequence
		return (_Size);
		}

	_NODISCARD constexpr bool empty() const noexcept
		{	// test if sequence is empty
		return (false);
		}

	_NODISCARD _CONSTEXPR17 reference at(size_type _Pos)
		{	// subscript mutable sequence with checking
		if (_Size <= _Pos)
			{
			_Xran();
			}

		return (_Elems[_Pos]);
		}

	_NODISCARD constexpr const_reference at(size_type _Pos) const
		{	// subscript nonmutable sequence with checking
		if (_Size <= _Pos)
			{
			_Xran();
			}

		return (_Elems[_Pos]);
		}

	_NODISCARD _CONSTEXPR17 reference operator[](_In_range_(0, _Size - 1) size_type _Pos) noexcept // strengthened
		{	// subscript mutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_VERIFY(_Pos < _Size, "array subscript out of range");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[_Pos]);
		}

	_NODISCARD constexpr const_reference operator[](_In_range_(0, _Size - 1) size_type _Pos) const
		noexcept // strengthened
		{	// subscript nonmutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_VERIFY(_Pos < _Size, "array subscript out of range");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[_Pos]);
		}

	_NODISCARD _CONSTEXPR17 reference front() noexcept // strengthened
		{	// return first element of mutable sequence
		return (_Elems[0]);
		}

	_NODISCARD constexpr const_reference front() const noexcept // strengthened
		{	// return first element of nonmutable sequence
		return (_Elems[0]);
		}

	_NODISCARD _CONSTEXPR17 reference back() noexcept // strengthened
		{	// return last element of mutable sequence
		return (_Elems[_Size - 1]);
		}

	_NODISCARD constexpr const_reference back() const noexcept // strengthened
		{	// return last element of nonmutable sequence
		return (_Elems[_Size - 1]);
		}

	_NODISCARD _CONSTEXPR17 _Ty * data() noexcept
		{	// return pointer to mutable data array
		return (_Elems);
		}

	_NODISCARD _CONSTEXPR17 const _Ty * data() const noexcept
		{	// return pointer to nonmutable data array
		return (_Elems);
		}

	[[noreturn]] void _Xran() const
		{	// report an out_of_range error
		_Xout_of_range("invalid array<T, N> subscript");
		}

	_Ty _Elems[_Size];
	};

#if _HAS_CXX17
template<class _First,
	class... _Rest>
	struct _Enforce_same
	{
	static_assert(conjunction_v<is_same<_First, _Rest>...>,
		"N4687 26.3.7.2 [array.cons]/2: "
		"Requires: (is_same_v<T, U> && ...) is true. Otherwise the program is ill-formed.");
	using type = _First;
	};

template<class _First,
	class... _Rest>
	array(_First, _Rest...)
		-> array<typename _Enforce_same<_First, _Rest...>::type, 1 + sizeof...(_Rest)>;
#endif /* _HAS_CXX17 */

template<class _Ty>
	class array<_Ty, 0>
	{	// zero size array of values
public:
	using value_type = _Ty;
	using size_type = size_t;
	using difference_type = ptrdiff_t;
	using pointer = _Ty *;
	using const_pointer = const _Ty *;
	using reference = _Ty&;
	using const_reference = const _Ty&;

	using iterator = _Array_iterator<_Ty, 0>;
	using const_iterator = _Array_const_iterator<_Ty, 0>;
	using reverse_iterator = _STD reverse_iterator<iterator>;
	using const_reverse_iterator = _STD reverse_iterator<const_iterator>;

#if _HAS_TR1_NAMESPACE
	_DEPRECATE_TR1_NAMESPACE void assign(const _Ty&)
		{	// assign value to all elements
		}
#endif /* _HAS_TR1_NAMESPACE */

	void fill(const _Ty&)
		{	// assign value to all elements
		}

	void swap(array&) noexcept
		{	// swap contents with _Other
		}

	_NODISCARD _CONSTEXPR17 iterator begin() noexcept
		{	// return iterator for beginning of mutable sequence
		return (iterator{});
		}

	_NODISCARD _CONSTEXPR17 const_iterator begin() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator{});
		}

	_NODISCARD _CONSTEXPR17 iterator end() noexcept
		{	// return iterator for end of mutable sequence
		return (iterator{});
		}

	_NODISCARD _CONSTEXPR17 const_iterator end() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (const_iterator{});
		}

	_NODISCARD _CONSTEXPR17 reverse_iterator rbegin() noexcept
		{	// return iterator for beginning of reversed mutable sequence
		return (reverse_iterator(end()));
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator rbegin() const noexcept
		{	// return iterator for beginning of reversed nonmutable sequence
		return (const_reverse_iterator(end()));
		}

	_NODISCARD _CONSTEXPR17 reverse_iterator rend() noexcept
		{	// return iterator for end of reversed mutable sequence
		return (reverse_iterator(begin()));
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator rend() const noexcept
		{	// return iterator for end of reversed nonmutable sequence
		return (const_reverse_iterator(begin()));
		}

	_NODISCARD _CONSTEXPR17 const_iterator cbegin() const noexcept
		{	// return iterator for beginning of nonmutable sequence
		return (begin());
		}

	_NODISCARD _CONSTEXPR17 const_iterator cend() const noexcept
		{	// return iterator for end of nonmutable sequence
		return (end());
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator crbegin() const noexcept
		{	// return iterator for beginning of reversed nonmutable sequence
		return (rbegin());
		}

	_NODISCARD _CONSTEXPR17 const_reverse_iterator crend() const noexcept
		{	// return iterator for end of reversed nonmutable sequence
		return (rend());
		}

	_CONSTEXPR17 _Ty * _Unchecked_begin() noexcept
		{	// return plain pointer to beginning of mutable sequence
		return (nullptr);
		}

	_CONSTEXPR17 const _Ty * _Unchecked_begin() const noexcept
		{	// return plain pointer to beginning of nonmutable sequence
		return (nullptr);
		}

	_CONSTEXPR17 _Ty * _Unchecked_end() noexcept
		{	// return plain pointer to end of mutable sequence
		return (nullptr);
		}

	_CONSTEXPR17 const _Ty * _Unchecked_end() const noexcept
		{	// return plain pointer to end of nonmutable sequence
		return (nullptr);
		}

	_NODISCARD constexpr size_type size() const noexcept
		{	// return length of sequence
		return (0);
		}

	_NODISCARD constexpr size_type max_size() const noexcept
		{	// return maximum possible length of sequence
		return (0);
		}

	_NODISCARD constexpr bool empty() const noexcept
		{	// test if sequence is empty
		return (true);
		}

	[[noreturn]] reference at(size_type)
		{	// subscript mutable sequence with checking
		_Xran();
		}

	[[noreturn]] const_reference at(size_type) const
		{	// subscript nonmutable sequence with checking
		_Xran();
		}

	_NODISCARD reference operator[](size_type) noexcept // strengthened
		{	// subscript mutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array subscript out of range");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD const_reference operator[](size_type) const noexcept // strengthened
		{	// subscript nonmutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array subscript out of range");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD reference front() noexcept // strengthened
		{	// return first element of mutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array<T, 0>::front() invalid");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD const_reference front() const noexcept // strengthened
		{	// return first element of nonmutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array<T, 0>::front() invalid");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD reference back() noexcept // strengthened
		{	// return last element of mutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array<T, 0>::back() invalid");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD const_reference back() const noexcept // strengthened
		{	// return last element of nonmutable sequence
 #if _ITERATOR_DEBUG_LEVEL != 0
		_STL_REPORT_ERROR("array<T, 0>::back() invalid");
 #endif /* _ITERATOR_DEBUG_LEVEL != 0 */

		return (_Elems[0]);
		}

	_NODISCARD _CONSTEXPR17 _Ty * data() noexcept
		{	// return pointer to mutable data array
		return (nullptr);
		}

	_NODISCARD _CONSTEXPR17 const _Ty * data() const noexcept
		{	// return pointer to nonmutable data array
		return (nullptr);
		}

	[[noreturn]] void _Xran() const
		{	// report an out_of_range error
		_Xout_of_range("invalid array<T, 0> subscript");
		}

	_Ty _Elems[1];
	};

template<class _Ty,
	size_t _Size,
	class = enable_if_t<_Size == 0 || _Is_swappable<_Ty>::value>>
	void swap(array<_Ty, _Size>& _Left, array<_Ty, _Size>& _Right)
		_NOEXCEPT_COND(_NOEXCEPT_OPER(_Left.swap(_Right)))
	{	// swap arrays
	return (_Left.swap(_Right));
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator==(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test for array equality
	return (_STD equal(_Left.begin(), _Left.end(), _Right.begin()));
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator!=(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test for array inequality
	return (!(_Left == _Right));
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator<(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test if _Left < _Right for arrays
	return (_STD lexicographical_compare(_Left.begin(), _Left.end(), _Right.begin(), _Right.end()));
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator>(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test if _Left > _Right for arrays
	return (_Right < _Left);
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator<=(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test if _Left <= _Right for arrays
	return (!(_Right < _Left));
	}

template<class _Ty,
	size_t _Size>
	_NODISCARD bool operator>=(const array<_Ty, _Size>& _Left, const array<_Ty, _Size>& _Right)
	{	// test if _Left >= _Right for arrays
	return (!(_Left < _Right));
	}

	// TUPLE INTERFACE TO array
template<size_t _Idx,
	class _Ty,
	size_t _Size>
	_NODISCARD constexpr _Ty& get(array<_Ty, _Size>& _Arr) noexcept
	{	// return element at _Idx in array _Arr
	static_assert(_Idx < _Size, "array index out of bounds");
	return (_Arr._Elems[_Idx]);
	}

template<size_t _Idx,
	class _Ty,
	size_t _Size>
	_NODISCARD constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) noexcept
	{	// return element at _Idx in array _Arr
	static_assert(_Idx < _Size, "array index out of bounds");
	return (_Arr._Elems[_Idx]);
	}

template<size_t _Idx,
	class _Ty,
	size_t _Size>
	_NODISCARD constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) noexcept
	{	// return element at _Idx in array _Arr
	static_assert(_Idx < _Size, "array index out of bounds");
	return (_STD move(_Arr._Elems[_Idx]));
	}

template<size_t _Idx,
	class _Ty,
	size_t _Size>
	_NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept
	{	// return element at _Idx in array _Arr
	static_assert(_Idx < _Size, "array index out of bounds");
	return (_STD move(_Arr._Elems[_Idx]));
	}

#if _HAS_TR1_NAMESPACE
namespace _DEPRECATE_TR1_NAMESPACE tr1 {
using _STD array;
using _STD get;
}
#endif /* _HAS_TR1_NAMESPACE */
_STD_END

 #pragma pop_macro("new")
 _STL_RESTORE_CLANG_WARNINGS
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _ARRAY_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
