#include
#include
#include
#include
#include
#include
#include
template < typename _Tp, ::std::size_t _Nm >
struct __array_traits{
typedef _Tp _Type[ _Nm ];
typedef ::std::is_swappable< _Tp > _IS_Swappable;
typedef ::std::is_nothrow_swappable< _Tp > _IS_Nothrow_Swappable;
static constexpr _Tp&
_S_ref( const _Type& __t, ::std::size_t __n ) noexcept
{ return const_cast< _Tp& >( __t[__n] ); }
static constexpr _Tp*
_S_ptr( const _Type& __t ) noexcept
{ return const_cast< _Tp* >( __t); }
};
template < typename _Tp >
struct __array_traits< _Tp, 0 >{
struct _Type { };
typedef ::std::true_type _IS_Swappable;
typedef ::std::true_type _IS_Nothrow_Swappable;
static constexpr _Tp&
_S_ref( const _Type&, std::size_t ) noexcept
{ return *static_cast< _Tp* >( nullptr ); }
static constexpr _Tp*
_S_ptr( const _Type& ) noexcept
{ return nullptr; }
};
template < typename _Tp, ::std::size_t _Nm >
struct array{
typedef _Tp value_type;
typedef ::std::add_pointer< ::std::decay_t< value_type > > pointer;
typedef ::std::add_const< pointer > const_pointer;
typedef ::std::add_lvalue_reference< ::std::decay_t < value_type > > reference;
typedef ::std::add_const< reference > const_reference;
typedef pointer iterator;
typedef const_pointer const_iterator;
typedef ::std::size_t size_type;
typedef ::std::ptrdiff_t difference;
typedef ::std::reverse_iterator< iterator > reverse_iterator;
typedef ::std::reverse_iterator< const_iterator > const_reverse_iterator;
typedef __array_traits< _Tp, _Nm > _AT_Type;
typename _AT_Type::_Type _M_elems;
constexpr pointer
data( void ) noexcept
{ return _AT_Type::_S_ptr( _M_elems ); }
constexpr const_pointer
data( void ) const noexcept
{ return _AT_Type::_S_ptr( _M_elems ); }
constexpr size_type
size( void ) const noexcept
{ return _Nm; }
constexpr size_type
max_size( void ) const noexcept
{ return _Nm; }
constexpr bool
empty( void ) const noexcept
{ return ! size(); }
constexpr reference
operator[]( size_type __n ) noexcept
{ return _AT_Type::_S_ref( _M_elems, __n ); }
constexpr const_reference
operator[]( size_type __n ) const noexcept
{ return _AT_Type::_S_ref( _M_elems, __n ); }
constexpr reference
at( size_type __n ){
if( __n >= _Nm ){
char _MsgBuf[ 64 ];
sprintf( _MsgBuf,
"array::at:: __n(which is %llu)"
">= _Nm (which is %llu)",
__n, _Nm );
throw ::std::out_of_range( _MsgBuf );
}
return _AT_Type::_S_ref( _M_elems, __n );
}
constexpr const_reference
at( size_type __n ) const{
return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n)
: (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) "
">= _Nm (which is %zu)"),
__n, _Nm),
_AT_Type::_S_ref(_M_elems, 0));
}
constexpr iterator
begin( void ) noexcept
{ return iterator( data() ); }
constexpr const_iterator
begin( void ) const noexcept
{ return const_iterator( data() ); }
constexpr iterator
end( void ) noexcept
{ return iterator( data() + _Nm ); }
constexpr const_iterator
end( void ) const noexcept
{ return const_iterator( data() + _Nm ); }
constexpr void
fill( const value_type& __u )
{ ::std::fill_n( begin(), size(), __u); }
constexpr void
swap( array& __other )
noexcept( _AT_Type::_IS_Nothrow_Swappable::value )
{ ::std::swap_ranges( begin(), end(), __other.begin(), __other.end() ); }
constexpr reference
front( void ) noexcept
{ return *begin(); }
constexpr const_reference
front( void ) const noexcept
{ return _AT_Type::_S_ref( _M_elems, 0 ); }
constexpr reference
back( void ) noexcept
{ return _Nm ? *( end() - 1 ) : *end(); }
constexpr const_reference
back( void ) const noexcept{
return _Nm ? _AT_Type::_S_ref( _M_elems, _Nm - 1)
: _AT_Type::_S_ref(_M_elems,0); }
};
template < typename _Tp, typename... _Up >
array( _Tp,_Up... )
->array< ::std::enable_if< ( ::std::is_same_v< _Tp, _Up >&& ...), _Tp>,
sizeof...(_Up) + 1>;
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator==( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two)
{ return ::std::equal( __one.begin(), __one.end(), __two.begin() ); }
template < typename _Tp, ::std::size_t _Nm >
constexpr ::std::partial_ordering
operator<=>( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two){
if constexpr ( _Nm )
return ::std::memcmp( __one.data(),
__two.data(),
_Nm * sizeof( _Tp ) )
<=> 0;
for( ::std::size_t __i { 0 }; __i < _Nm; ++__i ){
auto __result = __one[__i] <=> __two[__i];
if( __result != 0 ) return __result;
}
return ::std::strong_ordering::equal;
}
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator!=( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two )
{ return !( __one == __two ); }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator<( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two)
{ return ( __one <=> __two ) < 0; }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator>( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two)
{ return __two < __one; }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator<=( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two)
{ return !( __one > __two); }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline bool
operator>=( const array< _Tp, _Nm >& __one,
const array< _Tp, _Nm >& __two)
{ return !( __one < __two); }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline
typename ::std::enable_if<
__array_traits< _Tp, _Nm >::_IS_Swappable::value
>::type
swap( array< _Tp, _Nm >& __one,
array< _Tp, _Nm >& __two)
noexcept( noexcept( __one.swap( __two ) ) )
{ __one.swap(__two); }
template < typename _Tp, ::std::size_t _Nm >
constexpr inline
typename ::std::enable_if<
!__array_traits< _Tp, _Nm >::_IS_Swappable::value
>::type
swap( array< _Tp, _Nm >& __one,
array< _Tp, _Nm >& __two) = delete;
template < ::std::size_t _INT,
typename _Tp, ::std::size_t _Nm >
constexpr _Tp&
get( array< _Tp, _Nm >& __arr ) noexcept{
static_assert( _INT < _Nm, " array index is within bounds" );
return __array_traits< _Tp, _Nm >::_S_ref( __arr._M_elems, _INT );
}
template < ::std::size_t _INT,
typename _Tp, ::std::size_t _Nm >
constexpr _Tp&&
get( array< _Tp, _Nm >& __arr ) noexcept{
static_assert( _INT < _Nm, " array index is within bounds" );
return ::std::move( get< _INT >( __arr ) );
}
template < ::std::size_t _INT,
typename _Tp, ::std::size_t _Nm >
constexpr const _Tp&
get( array< _Tp, _Nm >& __arr ) noexcept{
static_assert( _INT < _Nm, " array index is within bounds" );
return __array_traits< _Tp, _Nm >::_S_ref( __arr._M_elems, _INT );
}
template < ::std::size_t _INT,
typename _Tp, ::std::size_t _Nm >
constexpr const _Tp&&
get( array< _Tp, _Nm >& __arr ) noexcept{
static_assert( _INT < _Nm, " array index is within bounds" );
return ::std::move( get< _INT >( __arr ) );
}
template < bool _Move = false, typename _Tp, ::std::size_t... _Idx >
constexpr array< ::std::remove_cv_t< _Tp >, sizeof...( _Idx ) >
__to_array( _Tp (&__a)[sizeof...(_Idx)], ::std::index_sequence< _Idx... > ){
if constexpr ( _Move )
return {{::std::move( __a[ _Idx ] )...} };
else
return {{ __a[ _Idx ]...} };
}
template < typename _Tp, ::std::size_t _Nm >
constexpr array<::std::remove_cv_t< _Tp >, _Nm >
to_array( _Tp (&__a)[ _Nm ] )
noexcept( ::std::is_nothrow_constructible_v< _Tp, _Tp& > ){
static_assert( !::std::is_array_v< _Tp > );
static_assert( ::std::is_constructible_v< _Tp, _Tp& > );
if constexpr (::std::is_constructible_v< _Tp, _Tp& >)
return __to_array( __a, ::std::make_index_sequence< _Nm >{} );
}
template < typename _Tp, ::std::size_t _Nm >
constexpr array<::std::remove_cv_t< _Tp >, _Nm >
to_array( _Tp (&&__a)[ _Nm ] )
noexcept( ::std::is_nothrow_move_constructible_v< _Tp > ){
static_assert( !::std::is_array_v< _Tp > );
static_assert( ::std::is_move_constructible_v< _Tp > );
if constexpr (::std::is_move_constructible_v< _Tp >)
return __to_array< 1 >( __a, ::std::make_index_sequence< _Nm >{} );
}