2015-08-20 18:09:14 -07:00
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <new>
#include <stdexcept>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#include <array>
#include <iterator>
#include "fail_fast.h"
#ifndef _MSC_VER
#define _CONSTEXPR constexpr
#else
#define _CONSTEXPR
#endif
#pragma push_macro("_NOEXCEPT")
#ifndef _NOEXCEPT
#ifdef SAFER_CPP_TESTING
#define _NOEXCEPT
#else
#define _NOEXCEPT noexcept
#endif
#else // _NOEXCEPT
#ifdef SAFER_CPP_TESTING
#undef _NOEXCEPT
#define _NOEXCEPT
#endif
#endif // _NOEXCEPT
2015-09-21 03:09:33 -07:00
#if defined(_MSC_VER) && _MSC_VER <= 1800
2015-09-14 15:11:07 -07:00
#pragma warning(push)
#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
#endif // _MSC_VER <= 1800
2015-08-20 18:09:14 -07:00
namespace Guide {
/*
** begin definitions of index and bounds
*/
namespace details
{
template < typename SizeType >
struct SizeTypeTraits
{
static const size_t max_value = std :: is_signed < SizeType >:: value ? static_cast < typename std :: make_unsigned < SizeType >:: type > ( - 1 ) / 2 : static_cast < SizeType > ( - 1 );
};
template < typename ConcreteType , typename ValueType , unsigned int Rank >
class coordinate_facade
{
static_assert ( std :: is_integral < ValueType >:: value
&& sizeof ( ValueType ) <= sizeof ( size_t ), "ValueType must be unsigned integral type!" );
static_assert ( Rank > 0 , "Rank must be greater than 0!" );
template < typename OtherConcreteType , typename OtherValueType , unsigned int OtherRank >
friend class coordinate_facade ;
public :
using reference = ValueType & ;
using const_reference = const ValueType & ;
using value_type = ValueType ;
static const unsigned int rank = Rank ;
_CONSTEXPR coordinate_facade () _NOEXCEPT
2015-08-30 23:30:15 -07:00
{
static_assert ( std :: is_base_of < coordinate_facade , ConcreteType >:: value , "ConcreteType must be derived from coordinate_facade." );
}
_CONSTEXPR coordinate_facade ( const value_type ( & values )[ rank ]) _NOEXCEPT
2015-08-20 18:09:14 -07:00
{
static_assert ( std :: is_base_of < coordinate_facade , ConcreteType >:: value , "ConcreteType must be derived from coordinate_facade." );
for ( unsigned int i = 0 ; i < rank ; ++ i )
2015-08-30 23:30:15 -07:00
elems [ i ] = values [ i ];
2015-08-20 18:09:14 -07:00
}
_CONSTEXPR coordinate_facade ( value_type e0 ) _NOEXCEPT
{
static_assert ( std :: is_base_of < coordinate_facade , ConcreteType >:: value , "ConcreteType must be derived from coordinate_facade." );
static_assert ( rank == 1 , "This constructor can only be used with rank == 1." );
elems [ 0 ] = e0 ;
}
// Preconditions: il.size() == rank
_CONSTEXPR coordinate_facade ( std :: initializer_list < value_type > il )
{
static_assert ( std :: is_base_of < coordinate_facade , ConcreteType >:: value , "ConcreteType must be derived from coordinate_facade." );
2015-08-30 23:30:15 -07:00
fail_fast_assert ( il . size () == rank , "The size of the initializer list must match the rank of the array" );
2015-08-20 18:09:14 -07:00
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
elems [ i ] = begin ( il )[ i ];
}
}
_CONSTEXPR coordinate_facade ( const coordinate_facade & other ) = default ;
template < typename OtherConcreteType , typename OtherValueType >
_CONSTEXPR coordinate_facade ( const coordinate_facade < OtherConcreteType , OtherValueType , Rank > & other )
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
fail_fast_assert ( static_cast < size_t > ( other . elems [ i ]) <= SizeTypeTraits < value_type >:: max_value );
elems [ i ] = static_cast < value_type > ( other . elems [ i ]);
}
}
protected :
coordinate_facade & operator = ( const coordinate_facade & rhs ) = default ;
// Preconditions: component_idx < rank
_CONSTEXPR reference operator []( unsigned int component_idx )
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( component_idx < rank , "Component index must be less than rank" );
2015-08-20 18:09:14 -07:00
return elems [ component_idx ];
}
// Preconditions: component_idx < rank
_CONSTEXPR const_reference operator []( unsigned int component_idx ) const
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( component_idx < rank , "Component index must be less than rank" );
2015-08-20 18:09:14 -07:00
return elems [ component_idx ];
}
_CONSTEXPR bool operator == ( const ConcreteType & rhs ) const _NOEXCEPT
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
if ( elems [ i ] != rhs . elems [ i ])
return false ;
}
return true ;
}
_CONSTEXPR bool operator != ( const ConcreteType & rhs ) const _NOEXCEPT
{
return ! ( to_concrete () == rhs );
}
_CONSTEXPR ConcreteType operator + () const _NOEXCEPT
{
return to_concrete ();
}
_CONSTEXPR ConcreteType operator - () const
{
ConcreteType ret = to_concrete ();
for ( unsigned int i = 0 ; i < rank ; ++ i )
ret . elems [ i ] = - ret . elems [ i ];
return ret ;
}
_CONSTEXPR ConcreteType operator + ( const ConcreteType & rhs ) const
{
ConcreteType ret = to_concrete ();
ret += rhs ;
return ret ;
}
_CONSTEXPR ConcreteType operator - ( const ConcreteType & rhs ) const
{
ConcreteType ret = to_concrete ();
ret -= rhs ;
return ret ;
}
_CONSTEXPR ConcreteType & operator += ( const ConcreteType & rhs )
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
elems [ i ] += rhs . elems [ i ];
return to_concrete ();
}
_CONSTEXPR ConcreteType & operator -= ( const ConcreteType & rhs )
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
elems [ i ] -= rhs . elems [ i ];
return to_concrete ();
}
_CONSTEXPR ConcreteType & operator ++ ()
{
static_assert ( rank == 1 , "This operator can only be used with rank == 1." );
++ elems [ 0 ];
return to_concrete ();
}
_CONSTEXPR ConcreteType operator ++ ( int )
{
static_assert ( rank == 1 , "This operator can only be used with rank == 1." );
ConcreteType ret = to_concrete ();
++ ( * this );
return ret ;
}
_CONSTEXPR ConcreteType & operator -- ()
{
static_assert ( rank == 1 , "This operator can only be used with rank == 1." );
-- elems [ 0 ];
return to_concrete ();
}
_CONSTEXPR ConcreteType operator -- ( int )
{
static_assert ( rank == 1 , "This operator can only be used with rank == 1." );
ConcreteType ret = to_concrete ();
-- ( * this );
return ret ;
}
_CONSTEXPR ConcreteType operator * ( value_type v ) const
{
ConcreteType ret = to_concrete ();
ret *= v ;
return ret ;
}
_CONSTEXPR ConcreteType operator / ( value_type v ) const
{
ConcreteType ret = to_concrete ();
ret /= v ;
return ret ;
}
friend _CONSTEXPR ConcreteType operator * ( value_type v , const ConcreteType & rhs )
{
return rhs * v ;
}
_CONSTEXPR ConcreteType & operator *= ( value_type v )
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
elems [ i ] *= v ;
return to_concrete ();
}
_CONSTEXPR ConcreteType & operator /= ( value_type v )
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
elems [ i ] /= v ;
return to_concrete ();
}
2015-08-30 23:30:15 -07:00
value_type elems [ rank ] = {};
2015-08-20 18:09:14 -07:00
private :
_CONSTEXPR const ConcreteType & to_concrete () const _NOEXCEPT
{
return static_cast < const ConcreteType &> ( * this );
}
_CONSTEXPR ConcreteType & to_concrete () _NOEXCEPT
{
return static_cast < ConcreteType &> ( * this );
}
};
template < typename T >
class arrow_proxy
{
public :
explicit arrow_proxy ( T t )
: val ( t )
{}
const T operator * () const _NOEXCEPT
{
return val ;
}
const T * operator -> () const _NOEXCEPT
{
return & val ;
}
private :
T val ;
};
}
template < unsigned int Rank , typename ValueType = size_t >
class index : private details :: coordinate_facade < index < Rank , ValueType > , ValueType , Rank >
{
using Base = details :: coordinate_facade < index < Rank , ValueType > , ValueType , Rank > ;
friend Base ;
2015-08-30 23:30:15 -07:00
template < unsigned int OtherRank , typename OtherValueType >
friend class index ;
2015-08-20 18:09:14 -07:00
public :
using Base :: rank ;
using reference = typename Base :: reference ;
using const_reference = typename Base :: const_reference ;
using size_type = typename Base :: value_type ;
using value_type = typename Base :: value_type ;
_CONSTEXPR index () _NOEXCEPT : Base (){}
2015-08-30 23:30:15 -07:00
_CONSTEXPR index ( const value_type ( & values )[ rank ]) _NOEXCEPT : Base ( values ) {}
_CONSTEXPR index ( std :: initializer_list < value_type > il ) : Base ( il ) {}
2015-08-20 18:09:14 -07:00
_CONSTEXPR index ( const index & ) = default ;
template < typename OtherValueType >
_CONSTEXPR index ( const index < Rank , OtherValueType > & other ) : Base ( other )
{
2015-08-30 23:30:15 -07:00
}
_CONSTEXPR static index shift_left ( const index < rank + 1 , value_type >& other ) _NOEXCEPT
{
2015-09-14 18:55:06 -07:00
value_type ( & arr )[ rank ] = ( value_type ( & )[ rank ])( * ( other . elems + 1 ));
return index ( arr );
2015-08-20 18:09:14 -07:00
}
using Base :: operator [];
using Base :: operator == ;
using Base :: operator != ;
using Base :: operator + ;
using Base :: operator - ;
using Base :: operator += ;
using Base :: operator -= ;
using Base :: operator ++ ;
using Base :: operator -- ;
using Base :: operator * ;
using Base :: operator / ;
using Base :: operator *= ;
using Base :: operator /= ;
};
template < typename ValueType >
class index < 1 , ValueType >
{
template < unsigned int , typename OtherValueType >
friend class index ;
public :
static const unsigned int rank = 1 ;
using reference = ValueType & ;
using const_reference = const ValueType & ;
using size_type = ValueType ;
using value_type = ValueType ;
_CONSTEXPR index () _NOEXCEPT : value ( 0 )
{
}
_CONSTEXPR index ( value_type e0 ) _NOEXCEPT : value ( e0 )
{
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR index ( const value_type ( & values )[ 1 ]) _NOEXCEPT : index ( values [ 0 ])
{
}
2015-08-20 18:09:14 -07:00
// Preconditions: il.size() == rank
_CONSTEXPR index ( std :: initializer_list < value_type > il )
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( il . size () == rank , "Size of the initializer list must match the rank of the array" );
2015-08-20 18:09:14 -07:00
value = begin ( il )[ 0 ];
}
_CONSTEXPR index ( const index & ) = default ;
template < typename OtherValueType >
_CONSTEXPR index ( const index < 1 , OtherValueType > & other )
{
fail_fast_assert ( other . value <= details :: SizeTypeTraits < ValueType >:: max_value );
value = static_cast < ValueType > ( other . value );
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR static index shift_left ( const index < rank + 1 , value_type >& other ) _NOEXCEPT
{
return other . elems [ 1 ];
}
2015-08-20 18:09:14 -07:00
// Preconditions: component_idx < rank
_CONSTEXPR reference operator []( size_type component_idx ) _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( component_idx == 0 , "Component index must be less than rank" );
2015-08-20 18:09:14 -07:00
( void )( component_idx );
return value ;
}
// Preconditions: component_idx < rank
_CONSTEXPR const_reference operator []( size_type component_idx ) const _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( component_idx == 0 , "Component index must be less than rank" );
2015-08-20 18:09:14 -07:00
( void )( component_idx );
return value ;
}
_CONSTEXPR bool operator == ( const index & rhs ) const _NOEXCEPT
{
return value == rhs . value ;
}
_CONSTEXPR bool operator != ( const index & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
_CONSTEXPR index operator + () const _NOEXCEPT
{
return * this ;
}
_CONSTEXPR index operator - () const _NOEXCEPT
{
return index ( - value );
}
_CONSTEXPR index operator + ( const index & rhs ) const _NOEXCEPT
{
return index ( value + rhs . value );
}
_CONSTEXPR index operator - ( const index & rhs ) const _NOEXCEPT
{
return index ( value - rhs . value );
}
_CONSTEXPR index & operator += ( const index & rhs ) _NOEXCEPT
{
value += rhs . value ;
return * this ;
}
_CONSTEXPR index & operator -= ( const index & rhs ) _NOEXCEPT
{
value -= rhs . value ;
return * this ;
}
_CONSTEXPR index & operator ++ () _NOEXCEPT
{
++ value ;
return * this ;
}
_CONSTEXPR index operator ++ ( int ) _NOEXCEPT
{
index ret = * this ;
++ ( * this );
return ret ;
}
_CONSTEXPR index & operator -- () _NOEXCEPT
{
-- value ;
return * this ;
}
_CONSTEXPR index operator -- ( int ) _NOEXCEPT
{
index ret = * this ;
-- ( * this );
return ret ;
}
_CONSTEXPR index operator * ( value_type v ) const _NOEXCEPT
{
return index ( value * v );
}
_CONSTEXPR index operator / ( value_type v ) const _NOEXCEPT
{
return index ( value / v );
}
_CONSTEXPR index & operator *= ( value_type v ) _NOEXCEPT
{
value *= v ;
return * this ;
}
_CONSTEXPR index & operator /= ( value_type v ) _NOEXCEPT
{
value /= v ;
return * this ;
}
friend _CONSTEXPR index operator * ( value_type v , const index & rhs ) _NOEXCEPT
{
return index ( rhs * v );
}
private :
value_type value ;
};
#ifndef _MSC_VER
struct static_bounds_dynamic_range_t
{
template < typename T , typename Dummy = std :: enable_if_t < std :: is_integral < T >:: value >>
constexpr operator T () const noexcept
{
return static_cast < T > ( - 1 );
}
template < typename T , typename Dummy = std :: enable_if_t < std :: is_integral < T >:: value >>
constexpr bool operator == ( T other ) const noexcept
{
return static_cast < T > ( - 1 ) == other ;
}
template < typename T , typename Dummy = std :: enable_if_t < std :: is_integral < T >:: value >>
constexpr bool operator != ( T other ) const noexcept
{
return static_cast < T > ( - 1 ) != other ;
}
};
template < typename T , typename Dummy = std :: enable_if_t < std :: is_integral < T >:: value >>
constexpr bool operator == ( T left , static_bounds_dynamic_range_t right ) noexcept
{
return right == left ;
}
template < typename T , typename Dummy = std :: enable_if_t < std :: is_integral < T >:: value >>
constexpr bool operator != ( T left , static_bounds_dynamic_range_t right ) noexcept
{
return right != left ;
}
constexpr static_bounds_dynamic_range_t dynamic_range {};
#else
const char dynamic_range = - 1 ;
#endif
struct generalized_mapping_tag {};
struct contiguous_mapping_tag : generalized_mapping_tag {};
namespace details
{
template < typename SizeType , SizeType Fact1 , SizeType Fact2 , SizeType ConstBound >
struct StaticSizeHelperImpl
{
static_assert ( static_cast < size_t > ( Fact1 ) * static_cast < size_t > ( Fact2 ) <= SizeTypeTraits < SizeType >:: max_value , "Value out of the range of SizeType" );
static const SizeType value = Fact1 * Fact2 ;
};
template < typename SizeType , SizeType Fact1 , SizeType ConstBound >
struct StaticSizeHelperImpl < SizeType , Fact1 , ConstBound , ConstBound >
{
static const SizeType value = ConstBound ;
};
template < typename SizeType , SizeType Fact2 , SizeType ConstBound >
struct StaticSizeHelperImpl < SizeType , ConstBound , Fact2 , ConstBound >
{
static const SizeType value = ConstBound ;
};
template < typename SizeType , SizeType ConstBound >
struct StaticSizeHelperImpl < SizeType , ConstBound , ConstBound , ConstBound >
{
static const SizeType value = static_cast < SizeType > ( ConstBound );
};
template < typename SizeType , SizeType Fact1 , SizeType Fact2 >
struct StaticSizeHelper
{
static const SizeType value = StaticSizeHelperImpl < SizeType , static_cast < SizeType > ( Fact1 ), static_cast < SizeType > ( Fact2 ), static_cast < SizeType > ( dynamic_range ) >:: value ;
};
template < size_t Left , size_t Right >
struct LessThan
{
static const bool value = Left < Right ;
};
template < typename SizeType , size_t ... Ranges >
struct BoundsRanges {
static const unsigned int Depth = 0 ;
static const unsigned int DynamicNum = 0 ;
static const SizeType CurrentRange = 1 ;
static const SizeType TotalSize = 1 ;
BoundsRanges ( const BoundsRanges & ) = default ;
// TODO : following signature is for work around VS bug
template < typename OtherType >
BoundsRanges ( const OtherType & , bool firstLevel ) {}
2015-09-19 07:52:30 +01:00
BoundsRanges ( const SizeType * const ) { }
2015-08-20 18:09:14 -07:00
BoundsRanges () = default ;
template < typename T , unsigned int Dim >
void serialize ( T & ) const {
}
template < typename T , unsigned int Dim >
SizeType linearize ( const T & ) const {
return 0 ;
}
template < typename T , unsigned int Dim >
ptrdiff_t contains ( const T & ) const {
return 0 ;
}
size_t totalSize () const _NOEXCEPT {
return TotalSize ;
}
bool operator == ( const BoundsRanges & ) const _NOEXCEPT
{
return true ;
}
};
template < typename SizeType , size_t ... RestRanges >
struct BoundsRanges < SizeType , dynamic_range , RestRanges ... > : BoundsRanges < SizeType , RestRanges ... > {
using Base = BoundsRanges < SizeType , RestRanges ... > ;
static const unsigned int Depth = Base :: Depth + 1 ;
static const unsigned int DynamicNum = Base :: DynamicNum + 1 ;
static const SizeType CurrentRange = dynamic_range ;
static const SizeType TotalSize = dynamic_range ;
const SizeType m_bound ;
BoundsRanges ( const BoundsRanges & ) = default ;
BoundsRanges ( const SizeType * const arr ) : Base ( arr + 1 ), m_bound ( static_cast < SizeType > ( * arr * this -> Base :: totalSize ()))
{
fail_fast_assert ( 0 <= * arr );
fail_fast_assert ( * arr * this -> Base :: totalSize () <= details :: SizeTypeTraits < SizeType >:: max_value );
}
BoundsRanges () : m_bound ( 0 ) {}
template < typename OtherSizeType , size_t OtherRange , size_t ... RestOtherRanges >
BoundsRanges ( const BoundsRanges < OtherSizeType , OtherRange , RestOtherRanges ... > & other , bool firstLevel = true ) :
Base ( static_cast < const BoundsRanges < OtherSizeType , RestOtherRanges ... >&> ( other ), false ), m_bound ( static_cast < SizeType > ( other . totalSize ()))
{
}
template < typename T , unsigned int Dim = 0 >
void serialize ( T & arr ) const {
arr [ Dim ] = elementNum ();
this -> Base :: template serialize < T , Dim + 1 > ( arr );
}
template < typename T , unsigned int Dim = 0 >
SizeType linearize ( const T & arr ) const {
const size_t index = this -> Base :: totalSize () * arr [ Dim ];
fail_fast_assert ( index < static_cast < size_t > ( m_bound ));
return static_cast < SizeType > ( index ) + this -> Base :: template linearize < T , Dim + 1 > ( arr );
}
template < typename T , unsigned int Dim = 0 >
ptrdiff_t contains ( const T & arr ) const {
const ptrdiff_t last = this -> Base :: template contains < T , Dim + 1 > ( arr );
if ( last == - 1 )
return - 1 ;
const ptrdiff_t cur = this -> Base :: totalSize () * arr [ Dim ];
return static_cast < size_t > ( cur ) < static_cast < size_t > ( m_bound ) ? cur + last : - 1 ;
}
size_t totalSize () const _NOEXCEPT {
return m_bound ;
}
SizeType elementNum () const _NOEXCEPT {
return static_cast < SizeType > ( totalSize () / this -> Base :: totalSize ());
}
SizeType elementNum ( unsigned int dim ) const _NOEXCEPT {
if ( dim > 0 )
return this -> Base :: elementNum ( dim - 1 );
else
return elementNum ();
}
bool operator == ( const BoundsRanges & rhs ) const _NOEXCEPT
{
return m_bound == rhs . m_bound && static_cast < const Base &> ( * this ) == static_cast < const Base &> ( rhs );
}
};
template < typename SizeType , size_t CurRange , size_t ... RestRanges >
struct BoundsRanges < SizeType , CurRange , RestRanges ... > : BoundsRanges < SizeType , RestRanges ... > {
using Base = BoundsRanges < SizeType , RestRanges ... > ;
static const unsigned int Depth = Base :: Depth + 1 ;
static const unsigned int DynamicNum = Base :: DynamicNum ;
static const SizeType CurrentRange = static_cast < SizeType > ( CurRange );
static const SizeType TotalSize = StaticSizeHelper < SizeType , Base :: TotalSize , CurrentRange >:: value ;
static_assert ( CurRange <= SizeTypeTraits < SizeType >:: max_value , "CurRange must be smaller than SizeType limits" );
BoundsRanges ( const BoundsRanges & ) = default ;
BoundsRanges ( const SizeType * const arr ) : Base ( arr ) { }
BoundsRanges () = default ;
template < typename OtherSizeType , size_t OtherRange , size_t ... RestOtherRanges >
BoundsRanges ( const BoundsRanges < OtherSizeType , OtherRange , RestOtherRanges ... > & other , bool firstLevel = true ) : Base ( static_cast < const BoundsRanges < OtherSizeType , RestOtherRanges ... >&> ( other ), false )
{
fail_fast_assert (( firstLevel && totalSize () <= other . totalSize ()) || totalSize () == other . totalSize ());
}
template < typename T , unsigned int Dim = 0 >
void serialize ( T & arr ) const {
arr [ Dim ] = elementNum ();
this -> Base :: template serialize < T , Dim + 1 > ( arr );
}
template < typename T , unsigned int Dim = 0 >
SizeType linearize ( const T & arr ) const {
2015-08-30 23:30:15 -07:00
fail_fast_assert ( arr [ Dim ] < CurrentRange , "Index is out of range" );
2015-08-20 18:09:14 -07:00
return static_cast < SizeType > ( this -> Base :: totalSize ()) * arr [ Dim ] + this -> Base :: template linearize < T , Dim + 1 > ( arr );
}
template < typename T , unsigned int Dim = 0 >
ptrdiff_t contains ( const T & arr ) const {
if ( static_cast < size_t > ( arr [ Dim ]) >= CurrentRange )
return - 1 ;
const ptrdiff_t last = this -> Base :: template contains < T , Dim + 1 > ( arr );
if ( last == - 1 )
return - 1 ;
return static_cast < ptrdiff_t > ( this -> Base :: totalSize () * arr [ Dim ]) + last ;
}
size_t totalSize () const _NOEXCEPT {
return CurrentRange * this -> Base :: totalSize ();
}
SizeType elementNum () const _NOEXCEPT {
return CurrentRange ;
}
SizeType elementNum ( unsigned int dim ) const _NOEXCEPT {
if ( dim > 0 )
return this -> Base :: elementNum ( dim - 1 );
else
return elementNum ();
}
bool operator == ( const BoundsRanges & rhs ) const _NOEXCEPT
{
return static_cast < const Base &> ( * this ) == static_cast < const Base &> ( rhs );
}
};
template < typename SourceType , typename TargetType , size_t Rank >
struct BoundsRangeConvertible2 ;
// TODO: I have to rewrite BoundsRangeConvertible into following way to workaround VS 2013 bugs
template < size_t Rank , typename SourceType , typename TargetType , typename Ret = BoundsRangeConvertible2 < typename SourceType :: Base , typename TargetType :: Base , Rank >>
auto helpBoundsRangeConvertible ( SourceType , TargetType , std :: true_type ) -> Ret ;
template < size_t Rank , typename SourceType , typename TargetType >
auto helpBoundsRangeConvertible ( SourceType , TargetType , ...) -> std :: false_type ;
template < typename SourceType , typename TargetType , size_t Rank >
struct BoundsRangeConvertible2 : decltype ( helpBoundsRangeConvertible < Rank - 1 > ( SourceType (), TargetType (),
std :: integral_constant < bool , SourceType :: Depth == TargetType :: Depth
&& ( SourceType :: CurrentRange == TargetType :: CurrentRange || TargetType :: CurrentRange == dynamic_range || SourceType :: CurrentRange == dynamic_range ) > ()))
{};
template < typename SourceType , typename TargetType >
struct BoundsRangeConvertible2 < SourceType , TargetType , 0 > : std :: true_type {};
template < typename SourceType , typename TargetType , size_t Rank = TargetType :: Depth >
struct BoundsRangeConvertible : decltype ( helpBoundsRangeConvertible < Rank - 1 > ( SourceType (), TargetType (),
std :: integral_constant < bool , SourceType :: Depth == TargetType :: Depth
&& ( ! LessThan < size_t ( SourceType :: CurrentRange ), size_t ( TargetType :: CurrentRange ) >:: value || TargetType :: CurrentRange == dynamic_range || SourceType :: CurrentRange == dynamic_range ) > ()))
{};
template < typename SourceType , typename TargetType >
struct BoundsRangeConvertible < SourceType , TargetType , 0 > : std :: true_type {};
template < typename TypeChain >
struct TypeListIndexer
{
const TypeChain & obj ;
TypeListIndexer ( const TypeChain & obj ) : obj ( obj ){}
template < unsigned int N >
const TypeChain & getObj ( std :: true_type )
{
return obj ;
}
template < unsigned int N , typename MyChain = TypeChain , typename MyBase = typename MyChain :: Base >
auto getObj ( std :: false_type ) -> decltype ( TypeListIndexer < MyBase > ( static_cast < const MyBase &> ( obj )). template get < N > ())
{
return TypeListIndexer < MyBase > ( static_cast < const MyBase &> ( obj )). template get < N > ();
}
template < unsigned int N >
auto get () -> decltype ( getObj < N - 1 > ( std :: integral_constant < bool , true > ()))
{
return getObj < N - 1 > ( std :: integral_constant < bool , N == 0 > ());
}
};
template < typename TypeChain >
TypeListIndexer < TypeChain > createTypeListIndexer ( const TypeChain & obj )
{
return TypeListIndexer < TypeChain > ( obj );
}
}
template < typename IndexType >
class bounds_iterator ;
template < typename SizeType , size_t ... Ranges >
class static_bounds {
public :
static_bounds ( const details :: BoundsRanges < SizeType , Ranges ... > & empty ) {
}
};
template < typename SizeType , size_t FirstRange , size_t ... RestRanges >
class static_bounds < SizeType , FirstRange , RestRanges ... >
{
using MyRanges = details :: BoundsRanges < SizeType , FirstRange , RestRanges ... > ;
static_assert ( std :: is_integral < SizeType >:: value
&& details :: SizeTypeTraits < SizeType >:: max_value <= SIZE_MAX , "SizeType must be an integral type and its numeric limits must be smaller than SIZE_MAX" );
MyRanges m_ranges ;
_CONSTEXPR static_bounds ( const MyRanges & range ) : m_ranges ( range ) { }
template < typename SizeType2 , size_t ... Ranges2 >
friend class static_bounds ;
public :
static const unsigned int rank = MyRanges :: Depth ;
static const unsigned int dynamic_rank = MyRanges :: DynamicNum ;
static const SizeType static_size = static_cast < SizeType > ( MyRanges :: TotalSize );
using size_type = SizeType ;
using index_type = index < rank , size_type > ;
using iterator = bounds_iterator < index_type > ;
using const_iterator = bounds_iterator < index_type > ;
using difference_type = ptrdiff_t ;
using sliced_type = static_bounds < SizeType , RestRanges ... > ;
using mapping_type = contiguous_mapping_tag ;
public :
_CONSTEXPR static_bounds ( const static_bounds & ) = default ;
template < typename OtherSizeType , size_t ... Ranges , typename Dummy = std :: enable_if_t <
details :: BoundsRangeConvertible < details :: BoundsRanges < OtherSizeType , Ranges ... > , details :: BoundsRanges < SizeType , FirstRange , RestRanges ... >>:: value >>
_CONSTEXPR static_bounds ( const static_bounds < OtherSizeType , Ranges ... > & other ) :
m_ranges ( other . m_ranges )
{
}
_CONSTEXPR static_bounds ( std :: initializer_list < size_type > il ) : m_ranges ( il . begin ())
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( MyRanges :: DynamicNum == il . size (), "Size of the initializer list must match the rank of the array" );
fail_fast_assert ( m_ranges . totalSize () <= details :: SizeTypeTraits < size_type >:: max_value , "Size of the range is larger than the max element of the size type" );
2015-08-20 18:09:14 -07:00
}
_CONSTEXPR static_bounds () = default ;
_CONSTEXPR static_bounds & operator = ( const static_bounds & otherBounds )
{
new ( & m_ranges ) MyRanges ( otherBounds . m_ranges );
return * this ;
}
_CONSTEXPR sliced_type slice () const _NOEXCEPT
{
return sliced_type { static_cast < const details :: BoundsRanges < SizeType , RestRanges ... > &> ( m_ranges )};
}
_CONSTEXPR size_type stride () const _NOEXCEPT
{
return rank > 1 ? slice (). size () : 1 ;
}
_CONSTEXPR size_type size () const _NOEXCEPT
{
return static_cast < size_type > ( m_ranges . totalSize ());
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR size_type total_size () const _NOEXCEPT
{
return static_cast < size_type > ( m_ranges . totalSize ());
}
2015-08-20 18:09:14 -07:00
_CONSTEXPR size_type linearize ( const index_type & idx ) const
{
return m_ranges . linearize ( idx );
}
_CONSTEXPR bool contains ( const index_type & idx ) const _NOEXCEPT
{
return m_ranges . contains ( idx ) != - 1 ;
}
_CONSTEXPR size_type operator []( unsigned int index ) const _NOEXCEPT
{
return m_ranges . elementNum ( index );
}
template < unsigned int Dim = 0 >
_CONSTEXPR size_type extent () const _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
static_assert ( Dim < rank , "dimension should be less than rank (dimension count starts from 0)" );
2015-08-20 18:09:14 -07:00
return details :: createTypeListIndexer ( m_ranges ). template get < Dim > (). elementNum ();
}
_CONSTEXPR index_type index_bounds () const _NOEXCEPT
{
index_type extents ;
m_ranges . serialize ( extents );
return extents ;
}
template < typename OtherSizeTypes , size_t ... Ranges >
_CONSTEXPR bool operator == ( const static_bounds < OtherSizeTypes , Ranges ... > & rhs ) const _NOEXCEPT
{
return this -> size () == rhs . size ();
}
template < typename OtherSizeTypes , size_t ... Ranges >
_CONSTEXPR bool operator != ( const static_bounds < OtherSizeTypes , Ranges ... > & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
_CONSTEXPR const_iterator begin () const _NOEXCEPT
{
return const_iterator ( * this );
}
_CONSTEXPR const_iterator end () const _NOEXCEPT
{
index_type boundary ;
m_ranges . serialize ( boundary );
return const_iterator ( * this , this -> index_bounds ());
}
};
template < unsigned int Rank , typename SizeType = size_t >
class strided_bounds : private details :: coordinate_facade < strided_bounds < Rank > , SizeType , Rank >
{
using Base = details :: coordinate_facade < strided_bounds < Rank > , SizeType , Rank > ;
friend Base ;
2015-08-30 23:30:15 -07:00
template < unsigned int OtherRank , typename OtherSizeType >
friend class strided_bounds ;
2015-08-20 18:09:14 -07:00
public :
using Base :: rank ;
using reference = typename Base :: reference ;
using const_reference = typename Base :: const_reference ;
using size_type = typename Base :: value_type ;
using difference_type = typename Base :: value_type ;
using value_type = typename Base :: value_type ;
using index_type = index < rank , size_type > ;
using iterator = bounds_iterator < index_type > ;
using const_iterator = bounds_iterator < index_type > ;
static const int dynamic_rank = rank ;
static const size_t static_size = dynamic_range ;
using sliced_type = std :: conditional_t < rank != 0 , strided_bounds < rank - 1 > , void > ;
using mapping_type = generalized_mapping_tag ;
_CONSTEXPR strided_bounds ( const strided_bounds & ) = default ;
template < typename OtherSizeType >
2015-08-30 23:30:15 -07:00
_CONSTEXPR strided_bounds ( const strided_bounds < rank , OtherSizeType > & other )
: Base ( other ), m_strides ( other . strides )
2015-08-20 18:09:14 -07:00
{
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR strided_bounds ( const index_type & extents , const index_type & strides )
: m_strides ( strides )
2015-08-20 18:09:14 -07:00
{
for ( unsigned int i = 0 ; i < rank ; i ++ )
Base :: elems [ i ] = extents [ i ];
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR strided_bounds ( const value_type ( & values )[ rank ], index_type strides )
: Base ( values ), m_strides ( std :: move ( strides ))
2015-08-20 18:09:14 -07:00
{
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR index_type strides () const _NOEXCEPT
{
return m_strides ;
}
_CONSTEXPR size_type total_size () const _NOEXCEPT
2015-08-20 18:09:14 -07:00
{
size_type ret = 0 ;
for ( unsigned int i = 0 ; i < rank ; ++ i )
2015-08-30 23:30:15 -07:00
ret += ( Base :: elems [ i ] - 1 ) * m_strides [ i ];
return ret + 1 ;
}
_CONSTEXPR size_type size () const _NOEXCEPT
{
size_type ret = 1 ;
for ( unsigned int i = 0 ; i < rank ; ++ i )
ret *= Base :: elems [ i ];
2015-08-20 18:09:14 -07:00
return ret ;
}
_CONSTEXPR bool contains ( const index_type & idx ) const _NOEXCEPT
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
if ( idx [ i ] < 0 || idx [ i ] >= Base :: elems [ i ])
return false ;
}
return true ;
}
_CONSTEXPR size_type linearize ( const index_type & idx ) const
{
size_type ret = 0 ;
for ( unsigned int i = 0 ; i < rank ; i ++ )
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( idx [ i ] < Base :: elems [ i ], "index is out of bounds of the array" );
ret += idx [ i ] * m_strides [ i ];
2015-08-20 18:09:14 -07:00
}
return ret ;
}
2015-08-30 23:30:15 -07:00
_CONSTEXPR size_type stride () const _NOEXCEPT
{
return m_strides [ 0 ];
}
template < bool Enabled = ( rank > 1 ), typename Ret = std :: enable_if_t < Enabled , sliced_type >>
2015-08-20 18:09:14 -07:00
_CONSTEXPR sliced_type slice () const
{
2015-08-30 23:30:15 -07:00
return { ( value_type ( & )[ rank - 1 ]) Base :: elems [ 1 ], sliced_type :: index_type :: shift_left ( m_strides ) };
2015-08-20 18:09:14 -07:00
}
template < unsigned int Dim = 0 >
_CONSTEXPR size_type extent () const _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
static_assert ( Dim < Rank , "dimension should be less than rank (dimension count starts from 0)" );
2015-08-20 18:09:14 -07:00
return Base :: elems [ Dim ];
}
_CONSTEXPR index_type index_bounds () const _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
return index_type ( Base :: elems );
2015-08-20 18:09:14 -07:00
}
const_iterator begin () const _NOEXCEPT
{
return const_iterator { * this };
}
const_iterator end () const _NOEXCEPT
{
return const_iterator { * this , index_bounds () };
}
2015-08-30 23:30:15 -07:00
private :
index_type m_strides ;
2015-08-20 18:09:14 -07:00
};
template < typename T >
struct is_bounds : std :: integral_constant < bool , false > {};
template < typename SizeType , size_t ... Ranges >
struct is_bounds < static_bounds < SizeType , Ranges ... >> : std :: integral_constant < bool , true > {};
template < unsigned int Rank , typename SizeType >
struct is_bounds < strided_bounds < Rank , SizeType >> : std :: integral_constant < bool , true > {};
template < typename IndexType >
class bounds_iterator
: public std :: iterator < std :: random_access_iterator_tag ,
IndexType ,
ptrdiff_t ,
const details :: arrow_proxy < IndexType > ,
const IndexType >
{
private :
using Base = std :: iterator < std :: random_access_iterator_tag , IndexType , ptrdiff_t , const details :: arrow_proxy < IndexType > , const IndexType > ;
public :
static const unsigned int rank = IndexType :: rank ;
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
using typename Base :: value_type ;
using index_type = value_type ;
using index_size_type = typename IndexType :: size_type ;
template < typename Bounds >
explicit bounds_iterator ( const Bounds & bnd , value_type curr = value_type {}) _NOEXCEPT
: boundary ( bnd . index_bounds ())
, curr ( std :: move ( curr ) )
{
static_assert ( is_bounds < Bounds >:: value , "Bounds type must be provided" );
}
reference operator * () const _NOEXCEPT
{
return curr ;
}
pointer operator -> () const _NOEXCEPT
{
return details :: arrow_proxy < value_type > { curr };
}
bounds_iterator & operator ++ () _NOEXCEPT
{
for ( unsigned int i = rank ; i -- > 0 ;)
{
if ( ++ curr [ i ] < boundary [ i ])
{
return * this ;
}
else
{
curr [ i ] = 0 ;
}
}
// If we're here we've wrapped over - set to past-the-end.
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
curr [ i ] = boundary [ i ];
}
return * this ;
}
bounds_iterator operator ++ ( int ) _NOEXCEPT
{
auto ret = * this ;
++ ( * this );
return ret ;
}
bounds_iterator & operator -- () _NOEXCEPT
{
for ( int i = rank ; i -- > 0 ;)
{
if ( curr [ i ] -- > 0 )
{
return * this ;
}
else
{
curr [ i ] = boundary [ i ] - 1 ;
}
}
// If we're here the preconditions were violated
// "pre: there exists s such that r == ++s"
fail_fast_assert ( false );
return * this ;
}
bounds_iterator operator -- ( int ) _NOEXCEPT
{
auto ret = * this ;
-- ( * this );
return ret ;
}
bounds_iterator operator + ( difference_type n ) const _NOEXCEPT
{
bounds_iterator ret { * this };
return ret += n ;
}
bounds_iterator & operator += ( difference_type n ) _NOEXCEPT
{
auto linear_idx = linearize ( curr ) + n ;
value_type stride ;
stride [ rank - 1 ] = 1 ;
for ( unsigned int i = rank - 1 ; i -- > 0 ;)
{
stride [ i ] = stride [ i + 1 ] * boundary [ i + 1 ];
}
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
curr [ i ] = linear_idx / stride [ i ];
linear_idx = linear_idx % stride [ i ];
}
return * this ;
}
bounds_iterator operator - ( difference_type n ) const _NOEXCEPT
{
bounds_iterator ret { * this };
return ret -= n ;
}
bounds_iterator & operator -= ( difference_type n ) _NOEXCEPT
{
return * this += - n ;
}
difference_type operator - ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return linearize ( curr ) - linearize ( rhs . curr );
}
reference operator []( difference_type n ) const _NOEXCEPT
{
return * ( * this + n );
}
bool operator == ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return curr == rhs . curr ;
}
bool operator != ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
bool operator < ( const bounds_iterator & rhs ) const _NOEXCEPT
{
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
if ( curr [ i ] < rhs . curr [ i ])
return true ;
}
return false ;
}
bool operator <= ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs < * this );
}
bool operator > ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return rhs < * this ;
}
bool operator >= ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs > * this );
}
void swap ( bounds_iterator & rhs ) _NOEXCEPT
{
std :: swap ( boundary , rhs . boundary );
std :: swap ( curr , rhs . curr );
}
private :
index_size_type linearize ( const value_type & idx ) const _NOEXCEPT
{
// TODO: Smarter impl.
// Check if past-the-end
bool pte = true ;
for ( unsigned int i = 0 ; i < rank ; ++ i )
{
if ( idx [ i ] != boundary [ i ])
{
pte = false ;
break ;
}
}
index_size_type multiplier = 1 ;
index_size_type res = 0 ;
if ( pte )
{
res = 1 ;
for ( unsigned int i = rank ; i -- > 0 ;)
{
res += ( idx [ i ] - 1 ) * multiplier ;
multiplier *= boundary [ i ];
}
}
else
{
for ( unsigned int i = rank ; i -- > 0 ;)
{
res += idx [ i ] * multiplier ;
multiplier *= boundary [ i ];
}
}
return res ;
}
value_type boundary ;
value_type curr ;
};
template < typename SizeType >
class bounds_iterator < index < 1 , SizeType >>
: public std :: iterator < std :: random_access_iterator_tag ,
index < 1 , SizeType > ,
ptrdiff_t ,
const details :: arrow_proxy < index < 1 , SizeType >> ,
const index < 1 , SizeType >>
{
using Base = std :: iterator < std :: random_access_iterator_tag , index < 1 , SizeType > , ptrdiff_t , const details :: arrow_proxy < index < 1 , SizeType >> , const index < 1 , SizeType >> ;
public :
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
using typename Base :: value_type ;
using index_type = value_type ;
using index_size_type = typename index_type :: size_type ;
template < typename Bounds >
explicit bounds_iterator ( const Bounds & , value_type curr = value_type {}) _NOEXCEPT
: curr ( std :: move ( curr ) )
{}
reference operator * () const _NOEXCEPT
{
return curr ;
}
pointer operator -> () const _NOEXCEPT
{
return details :: arrow_proxy < value_type > { curr };
}
bounds_iterator & operator ++ () _NOEXCEPT
{
++ curr ;
return * this ;
}
bounds_iterator operator ++ ( int ) _NOEXCEPT
{
auto ret = * this ;
++ ( * this );
return ret ;
}
bounds_iterator & operator -- () _NOEXCEPT
{
curr -- ;
return * this ;
}
bounds_iterator operator -- ( int ) _NOEXCEPT
{
auto ret = * this ;
-- ( * this );
return ret ;
}
bounds_iterator operator + ( difference_type n ) const _NOEXCEPT
{
bounds_iterator ret { * this };
return ret += n ;
}
bounds_iterator & operator += ( difference_type n ) _NOEXCEPT
{
curr += n ;
return * this ;
}
bounds_iterator operator - ( difference_type n ) const _NOEXCEPT
{
bounds_iterator ret { * this };
return ret -= n ;
}
bounds_iterator & operator -= ( difference_type n ) _NOEXCEPT
{
return * this += - n ;
}
difference_type operator - ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return curr [ 0 ] - rhs . curr [ 0 ];
}
reference operator []( difference_type n ) const _NOEXCEPT
{
return curr + n ;
}
bool operator == ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return curr == rhs . curr ;
}
bool operator != ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
bool operator < ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return curr [ 0 ] < rhs . curr [ 0 ];
}
bool operator <= ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs < * this );
}
bool operator > ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return rhs < * this ;
}
bool operator >= ( const bounds_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs > * this );
}
void swap ( bounds_iterator & rhs ) _NOEXCEPT
{
std :: swap ( curr , rhs . curr );
}
private :
value_type curr ;
};
template < typename IndexType >
bounds_iterator < IndexType > operator + ( typename bounds_iterator < IndexType >:: difference_type n , const bounds_iterator < IndexType >& rhs ) _NOEXCEPT
{
return rhs + n ;
}
/*
** begin definitions of basic_array_view
*/
namespace details
{
template < typename Bounds >
_CONSTEXPR std :: enable_if_t < std :: is_same < typename Bounds :: mapping_type , generalized_mapping_tag >:: value , typename Bounds :: index_type > make_stride ( const Bounds & bnd ) _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
return bnd . strides ();
2015-08-20 18:09:14 -07:00
}
// Make a stride vector from bounds, assuming continugous memory.
template < typename Bounds >
_CONSTEXPR std :: enable_if_t < std :: is_same < typename Bounds :: mapping_type , contiguous_mapping_tag >:: value , typename Bounds :: index_type > make_stride ( const Bounds & bnd ) _NOEXCEPT
{
auto extents = bnd . index_bounds ();
typename Bounds :: index_type stride ;
stride [ Bounds :: rank - 1 ] = 1 ;
for ( int i = Bounds :: rank - 2 ; i >= 0 ; -- i )
stride [ i ] = stride [ i + 1 ] * extents [ i + 1 ];
return stride ;
}
template < typename BoundsSrc , typename BoundsDest >
void verifyBoundsReshape ( const BoundsSrc & src , const BoundsDest & dest )
{
static_assert ( is_bounds < BoundsSrc >:: value && is_bounds < BoundsDest >:: value , "The src type and dest type must be bounds" );
static_assert ( std :: is_same < typename BoundsSrc :: mapping_type , contiguous_mapping_tag >:: value , "The source type must be a contiguous bounds" );
static_assert ( BoundsDest :: static_size == dynamic_range || BoundsSrc :: static_size == dynamic_range || BoundsDest :: static_size == BoundsSrc :: static_size , "The source bounds must have same size as dest bounds" );
fail_fast_assert ( src . size () == dest . size ());
}
} // namespace details
template < typename ArrayView >
class contiguous_array_view_iterator ;
template < typename ArrayView >
class general_array_view_iterator ;
enum class byte : std :: uint8_t {};
template < typename ValueType , typename BoundsType >
class basic_array_view
{
public :
static const unsigned int rank = BoundsType :: rank ;
using bounds_type = BoundsType ;
using size_type = typename bounds_type :: size_type ;
using index_type = typename bounds_type :: index_type ;
using value_type = ValueType ;
using pointer = ValueType * ;
using reference = ValueType & ;
using iterator = std :: conditional_t < std :: is_same < typename BoundsType :: mapping_type , contiguous_mapping_tag >:: value , contiguous_array_view_iterator < basic_array_view > , general_array_view_iterator < basic_array_view >> ;
using const_iterator = std :: conditional_t < std :: is_same < typename BoundsType :: mapping_type , contiguous_mapping_tag >:: value , contiguous_array_view_iterator < basic_array_view < const ValueType , BoundsType >> , general_array_view_iterator < basic_array_view < const ValueType , BoundsType >>> ;
using reverse_iterator = std :: reverse_iterator < iterator > ;
using const_reverse_iterator = std :: reverse_iterator < const_iterator > ;
using sliced_type = std :: conditional_t < rank == 1 , value_type , basic_array_view < value_type , typename BoundsType :: sliced_type >> ;
private :
pointer m_pdata ;
bounds_type m_bounds ;
public :
_CONSTEXPR bounds_type bounds () const _NOEXCEPT
{
return m_bounds ;
}
template < unsigned int Dim = 0 >
_CONSTEXPR size_type extent () const _NOEXCEPT
{
2015-08-30 23:30:15 -07:00
static_assert ( Dim < rank , "dimension should be less than rank (dimension count starts from 0)" );
2015-08-20 18:09:14 -07:00
return m_bounds . template extent < Dim > ();
}
_CONSTEXPR size_type size () const _NOEXCEPT
{
return m_bounds . size ();
}
_CONSTEXPR reference operator []( const index_type & idx ) const
{
return m_pdata [ m_bounds . linearize ( idx )];
}
_CONSTEXPR pointer data () const _NOEXCEPT
{
return m_pdata ;
}
2015-08-30 23:30:15 -07:00
template < bool Enabled = ( rank > 1 ), typename Ret = std :: enable_if_t < Enabled , sliced_type >>
2015-08-20 18:09:14 -07:00
_CONSTEXPR Ret operator []( size_type idx ) const
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( idx < m_bounds . size (), "index is out of bounds of the array" );
2015-08-20 18:09:14 -07:00
const size_type ridx = idx * m_bounds . stride ();
2015-08-30 23:30:15 -07:00
fail_fast_assert ( ridx < m_bounds . total_size (), "index is out of bounds of the underlying data" );
2015-08-20 18:09:14 -07:00
return Ret { m_pdata + ridx , m_bounds . slice ()};
}
_CONSTEXPR operator bool () const _NOEXCEPT
{
return m_pdata != nullptr ;
}
_CONSTEXPR iterator begin () const
{
return iterator { this , true };
}
_CONSTEXPR iterator end () const
{
return iterator { this };
}
_CONSTEXPR const_iterator cbegin () const
{
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > *> ( this ), true };
}
_CONSTEXPR const_iterator cend () const
{
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > *> ( this )};
}
_CONSTEXPR reverse_iterator rbegin () const
{
return reverse_iterator { end ()};
}
_CONSTEXPR reverse_iterator rend () const
{
return reverse_iterator { begin ()};
}
_CONSTEXPR const_reverse_iterator crbegin () const
{
return const_reverse_iterator { cend ()};
}
_CONSTEXPR const_reverse_iterator crend () const
{
return const_reverse_iterator { cbegin ()};
}
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
2015-08-27 18:13:49 -07:00
_CONSTEXPR bool operator == ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
2015-08-20 18:09:14 -07:00
{
2015-08-30 23:30:15 -07:00
return m_bounds . size () == other . m_bounds . size () &&
( m_pdata == other . m_pdata || std :: equal ( this -> begin (), this -> end (), other . begin ()));
2015-08-20 18:09:14 -07:00
}
2015-08-30 23:30:15 -07:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
_CONSTEXPR bool operator != ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
{
return ! ( * this == other );
}
2015-08-27 18:13:49 -07:00
2015-08-30 23:30:15 -07:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
_CONSTEXPR bool operator < ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
{
return std :: lexicographical_compare ( this -> begin (), this -> end (), other . begin (), other . end ());
}
2015-08-27 18:13:49 -07:00
2015-08-30 23:30:15 -07:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
_CONSTEXPR bool operator <= ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
{
return ! ( other < * this );
}
2015-08-27 18:13:49 -07:00
2015-08-30 23:30:15 -07:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
_CONSTEXPR bool operator > ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
{
return ( other < * this );
}
2015-08-27 18:13:49 -07:00
2015-08-30 23:30:15 -07:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
_CONSTEXPR bool operator >= ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const _NOEXCEPT
{
return ! ( * this < other );
}
2015-08-27 18:13:49 -07:00
2015-08-20 18:09:14 -07:00
public :
template < typename OtherValueType , typename OtherBounds ,
typename Dummy = std :: enable_if_t < std :: is_convertible < OtherValueType ( * )[], value_type ( * )[] >:: value
&& std :: is_convertible < OtherBounds , bounds_type >:: value >>
_CONSTEXPR basic_array_view ( const basic_array_view < OtherValueType , OtherBounds > & other ) _NOEXCEPT
: m_pdata ( other . m_pdata ), m_bounds ( other . m_bounds )
{
}
protected :
_CONSTEXPR basic_array_view ( pointer data , bounds_type bound ) _NOEXCEPT
: m_pdata ( data )
, m_bounds ( std :: move ( bound ))
{
fail_fast_assert (( m_bounds . size () > 0 && data != nullptr ) || m_bounds . size () == 0 );
}
template < typename T >
_CONSTEXPR basic_array_view ( T * data , std :: enable_if_t < std :: is_same < value_type , std :: remove_all_extents_t < T >>:: value , bounds_type > bound ) _NOEXCEPT
: m_pdata ( reinterpret_cast < pointer > ( data ))
, m_bounds ( std :: move ( bound ))
{
fail_fast_assert (( m_bounds . size () > 0 && data != nullptr ) || m_bounds . size () == 0 );
}
template < typename DestBounds >
_CONSTEXPR basic_array_view < value_type , DestBounds > as_array_view ( const DestBounds & bounds )
{
details :: verifyBoundsReshape ( m_bounds , bounds );
return { m_pdata , bounds };
}
private :
friend iterator ;
friend const_iterator ;
template < typename ValueType2 , typename BoundsType2 >
friend class basic_array_view ;
};
template < size_t DimSize = dynamic_range >
struct dim
{
static const size_t value = DimSize ;
};
template <>
struct dim < dynamic_range >
{
static const size_t value = dynamic_range ;
const size_t dvalue ;
dim ( size_t size ) : dvalue ( size ) {}
};
template < typename ValueTypeOpt , size_t FirstDimension = dynamic_range , size_t ... RestDimensions >
class array_view ;
template < typename ValueTypeOpt , unsigned int Rank >
class strided_array_view ;
namespace details
{
template < typename T , typename = std :: true_type >
struct ArrayViewTypeTraits
{
using value_type = T ;
using size_type = size_t ;
};
template < typename Traits >
struct ArrayViewTypeTraits < Traits , typename std :: is_reference < typename Traits :: array_view_traits &>:: type >
{
using value_type = typename Traits :: array_view_traits :: value_type ;
using size_type = typename Traits :: array_view_traits :: size_type ;
};
template < typename T , typename SizeType , size_t ... Ranks >
struct ArrayViewArrayTraits {
using type = array_view < T , Ranks ... > ;
using value_type = T ;
using bounds_type = static_bounds < SizeType , Ranks ... > ;
using pointer = T * ;
using reference = T & ;
};
template < typename T , typename SizeType , size_t N , size_t ... Ranks >
struct ArrayViewArrayTraits < T [ N ], SizeType , Ranks ... > : ArrayViewArrayTraits < T , SizeType , Ranks ..., N > {};
template < typename BoundsType >
BoundsType newBoundsHelperImpl ( size_t totalSize , std :: true_type ) // dynamic size
{
fail_fast_assert ( totalSize <= details :: SizeTypeTraits < typename BoundsType :: size_type >:: max_value );
return BoundsType { static_cast < typename BoundsType :: size_type > ( totalSize )};
}
template < typename BoundsType >
BoundsType newBoundsHelperImpl ( size_t totalSize , std :: false_type ) // static size
{
fail_fast_assert ( BoundsType :: static_size == totalSize );
return {};
}
template < typename BoundsType >
BoundsType newBoundsHelper ( size_t totalSize )
{
static_assert ( BoundsType :: dynamic_rank <= 1 , "dynamic rank must less or equal to 1" );
return newBoundsHelperImpl < BoundsType > ( totalSize , std :: integral_constant < bool , BoundsType :: dynamic_rank == 1 > ());
}
struct Sep {};
template < typename T , typename ... Args >
T static_as_array_view_helper ( Sep , Args ... args )
{
return T { static_cast < typename T :: size_type > ( args )...};
}
template < typename T , typename Arg , typename ... Args >
std :: enable_if_t <! std :: is_same < Arg , dim < dynamic_range >>:: value && ! std :: is_same < Arg , Sep >:: value , T > static_as_array_view_helper ( Arg , Args ... args )
{
return static_as_array_view_helper < T > ( args ...);
}
template < typename T , typename ... Args >
T static_as_array_view_helper ( dim < dynamic_range > val , Args ... args )
{
return static_as_array_view_helper < T > ( args ..., val . dvalue );
}
template < typename SizeType , typename ... Dimensions >
struct static_as_array_view_static_bounds_helper
{
using type = static_bounds < SizeType , ( Dimensions :: value )... > ;
};
template < typename T >
struct is_array_view_oracle : std :: false_type
{};
template < typename ValueType , size_t FirstDimension , size_t ... RestDimensions >
struct is_array_view_oracle < array_view < ValueType , FirstDimension , RestDimensions ... >> : std :: true_type
{};
template < typename ValueType , unsigned int Rank >
struct is_array_view_oracle < strided_array_view < ValueType , Rank >> : std :: true_type
{};
template < typename T >
struct is_array_view : is_array_view_oracle < std :: remove_cv_t < T >>
{};
}
template < typename ValueType , typename SizeType >
struct array_view_options
{
struct array_view_traits
{
using value_type = ValueType ;
using size_type = SizeType ;
};
};
template < typename ValueTypeOpt , size_t FirstDimension , size_t ... RestDimensions >
class array_view : public basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type ,
static_bounds < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type , FirstDimension , RestDimensions ... >>
{
template < typename ValueTypeOpt2 , size_t FirstDimension2 , size_t ... RestDimensions2 >
friend class array_view ;
2015-08-30 23:30:15 -07:00
using Base = basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type ,
2015-09-14 16:34:26 -07:00
static_bounds < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type , FirstDimension , RestDimensions ... >> ;
2015-08-20 18:09:14 -07:00
public :
using typename Base :: bounds_type ;
using typename Base :: size_type ;
using typename Base :: pointer ;
using typename Base :: value_type ;
using typename Base :: index_type ;
2015-08-30 23:30:15 -07:00
using typename Base :: iterator ;
using typename Base :: const_iterator ;
2015-09-14 21:26:17 +00:00
using typename Base :: reference ;
2015-09-14 15:41:40 -07:00
using Base :: rank ;
2015-08-20 18:09:14 -07:00
public :
// basic
_CONSTEXPR array_view ( pointer ptr , bounds_type bounds ) : Base ( ptr , std :: move ( bounds ))
{
}
_CONSTEXPR array_view ( std :: nullptr_t ) : Base ( nullptr , bounds_type {})
{
}
2015-08-27 19:49:27 -07:00
_CONSTEXPR array_view ( std :: nullptr_t , size_type size ) : Base ( nullptr , bounds_type {})
2015-08-20 18:09:14 -07:00
{
fail_fast_assert ( size == 0 );
}
// default
template < size_t DynamicRank = bounds_type :: dynamic_rank , typename Dummy = std :: enable_if_t < DynamicRank != 0 >>
_CONSTEXPR array_view () : Base ( nullptr , bounds_type ())
{
}
2015-08-30 23:30:15 -07:00
2015-08-20 18:09:14 -07:00
// from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer)
template < typename T , typename Helper = details :: ArrayViewArrayTraits < T , size_type , dynamic_range > ,
2015-09-14 16:34:26 -07:00
typename Dummy = std :: enable_if_t < std :: is_convertible < typename Helper :: value_type ( * )[], typename Base :: value_type ( * )[] >:: value
&& std :: is_convertible < typename Helper :: bounds_type , typename Base :: bounds_type >:: value >>
_CONSTEXPR array_view ( T * const & data , size_type size ) : Base ( data , typename Helper :: bounds_type { size })
2015-08-20 18:09:14 -07:00
{
}
// from n-dimensions static array
template < typename T , size_t N , typename Helper = details :: ArrayViewArrayTraits < T , size_type , N > ,
typename Dummy = std :: enable_if_t < std :: is_convertible < typename Helper :: value_type ( * )[], typename Base :: value_type ( * )[] >:: value
2015-09-14 16:34:26 -07:00
&& std :: is_convertible < typename Helper :: bounds_type , typename Base :: bounds_type >:: value >>
2015-09-14 16:38:25 -07:00
_CONSTEXPR array_view ( T ( & arr )[ N ]) : Base ( arr , typename Helper :: bounds_type ())
2015-08-20 18:09:14 -07:00
{
}
// from n-dimensions static array with size
template < typename T , size_t N , typename Helper = details :: ArrayViewArrayTraits < T , size_type , dynamic_range > ,
typename Dummy = std :: enable_if_t < std :: is_convertible < typename Helper :: value_type ( * )[], typename Base :: value_type ( * )[] >:: value
2015-08-30 23:30:15 -07:00
&& std :: is_convertible < typename Helper :: bounds_type , typename Base :: bounds_type >:: value >>
_CONSTEXPR array_view ( T ( & arr )[ N ], size_type size ) : Base ( arr , typename Helper :: bounds_type { size })
2015-08-20 18:09:14 -07:00
{
fail_fast_assert ( size <= N );
}
// from std array
template < size_t N , typename Dummy = std :: enable_if_t < std :: is_convertible < static_bounds < size_type , N > , typename Base :: bounds_type >:: value >>
_CONSTEXPR array_view ( std :: array < std :: remove_const_t < value_type > , N > & arr ) : Base ( arr . data (), static_bounds < size_type , N > ())
{
}
template < size_t N , typename Dummy = std :: enable_if_t < std :: is_convertible < static_bounds < size_type , N > , typename Base :: bounds_type >:: value && std :: is_const < value_type >:: value >>
_CONSTEXPR array_view ( const std :: array < std :: remove_const_t < value_type > , N > & arr ) : Base ( arr . data (), static_bounds < size_type , N > ())
{
}
// from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity
template < typename Ptr ,
typename Dummy = std :: enable_if_t < std :: is_convertible < Ptr , pointer >:: value
&& details :: LessThan < Base :: bounds_type :: dynamic_rank , 2 >:: value >> // remove literal 0 case
_CONSTEXPR array_view ( pointer begin , Ptr end ) : Base ( begin , details :: newBoundsHelper < typename Base :: bounds_type > ( static_cast < pointer > ( end ) - begin ))
{
}
// from containers. It must has .size() and .data() two function signatures
template < typename Cont , typename DataType = typename Cont :: value_type , typename SizeType = typename Cont :: size_type ,
typename Dummy = std :: enable_if_t <! details :: is_array_view < Cont >:: value
2015-09-14 16:34:26 -07:00
&& std :: is_convertible < DataType ( * )[], typename Base :: value_type ( * )[] >:: value
2015-08-30 23:30:15 -07:00
&& std :: is_convertible < static_bounds < SizeType , dynamic_range > , typename Base :: bounds_type >:: value
&& std :: is_same < std :: decay_t < decltype ( std :: declval < Cont > (). size (), * std :: declval < Cont > (). data ()) > , DataType >:: value >
2015-08-20 18:09:14 -07:00
>
2015-09-14 16:34:26 -07:00
_CONSTEXPR array_view ( Cont & cont ) : Base ( static_cast < pointer > ( cont . data ()), details :: newBoundsHelper < typename Base :: bounds_type > ( cont . size ()))
2015-08-20 18:09:14 -07:00
{
}
2015-08-30 23:30:15 -07:00
2015-08-20 18:09:14 -07:00
_CONSTEXPR array_view ( const array_view & ) = default ;
2015-08-30 23:30:15 -07:00
2015-08-20 18:09:14 -07:00
// convertible
template < typename OtherValueTypeOpt , size_t ... OtherDimensions ,
typename BaseType = basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type , static_bounds < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type , FirstDimension , RestDimensions ... >> ,
typename OtherBaseType = basic_array_view < typename details :: ArrayViewTypeTraits < OtherValueTypeOpt >:: value_type , static_bounds < typename details :: ArrayViewTypeTraits < OtherValueTypeOpt >:: size_type , OtherDimensions ... >> ,
typename Dummy = std :: enable_if_t < std :: is_convertible < OtherBaseType , BaseType >:: value >
>
_CONSTEXPR array_view ( const array_view < OtherValueTypeOpt , OtherDimensions ... > & av ) : Base ( static_cast < const typename array_view < OtherValueTypeOpt , OtherDimensions ... >:: Base &> ( av )) {} // static_cast is required
// reshape
template < typename ... Dimensions2 >
_CONSTEXPR array_view < ValueTypeOpt , Dimensions2 :: value ... > as_array_view ( Dimensions2 ... dims )
{
static_assert ( sizeof ...( Dimensions2 ) > 0 , "the target array_view must have at least one dimension." );
2015-08-30 23:30:15 -07:00
using BoundsType = typename array_view < ValueTypeOpt , ( Dimensions2 :: value )... >:: bounds_type ;
2015-08-20 18:09:14 -07:00
auto tobounds = details :: static_as_array_view_helper < BoundsType > ( dims ..., details :: Sep {});
details :: verifyBoundsReshape ( this -> bounds (), tobounds );
2015-09-14 16:34:26 -07:00
return { this -> data (), tobounds };
2015-08-20 18:09:14 -07:00
}
// to bytes array
template < bool Enabled = std :: is_standard_layout < std :: decay_t < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type >>:: value >
2015-08-30 23:30:15 -07:00
_CONSTEXPR auto as_bytes () const _NOEXCEPT ->
2015-08-20 18:09:14 -07:00
array_view < array_view_options < const byte , size_type > , static_cast < size_t > ( details :: StaticSizeHelper < size_type , Base :: bounds_type :: static_size , sizeof ( value_type ) >:: value ) >
{
static_assert ( Enabled , "The value_type of array_view must be standarded layout" );
2015-09-14 16:34:26 -07:00
return { reinterpret_cast < const byte *> ( this -> data ()), this -> bytes () };
2015-08-20 18:09:14 -07:00
}
template < bool Enabled = std :: is_standard_layout < std :: decay_t < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type >>:: value >
2015-08-30 23:30:15 -07:00
_CONSTEXPR auto as_writeable_bytes () const _NOEXCEPT ->
2015-08-20 18:09:14 -07:00
array_view < array_view_options < byte , size_type > , static_cast < size_t > ( details :: StaticSizeHelper < size_type , Base :: bounds_type :: static_size , sizeof ( value_type ) >:: value ) >
{
static_assert ( Enabled , "The value_type of array_view must be standarded layout" );
2015-09-14 16:34:26 -07:00
return { reinterpret_cast < byte *> ( this -> data ()), this -> bytes () };
2015-08-20 18:09:14 -07:00
}
2015-09-14 16:34:26 -07:00
2015-08-20 18:09:14 -07:00
// from bytes array
template < typename U , bool IsByte = std :: is_same < value_type , const byte >:: value , typename Dummy = std :: enable_if_t < IsByte && sizeof ...( RestDimensions ) == 0 >>
_CONSTEXPR auto as_array_view () const _NOEXCEPT -> array_view < const U , ( Base :: bounds_type :: dynamic_rank == 0 ? Base :: bounds_type :: static_size / sizeof ( U ) : static_cast < size_type > ( dynamic_range )) >
{
static_assert ( std :: is_standard_layout < U >:: value && ( Base :: bounds_type :: static_size == dynamic_range || Base :: bounds_type :: static_size % sizeof ( U ) == 0 ),
"Target type must be standard layout and its size must match the byte array size" );
fail_fast_assert (( this -> bytes () % sizeof ( U )) == 0 );
2015-09-14 16:34:26 -07:00
return { reinterpret_cast < const U *> ( this -> data ()), this -> bytes () / sizeof ( U ) };
2015-08-20 18:09:14 -07:00
}
template < typename U , bool IsByte = std :: is_same < value_type , byte >:: value , typename Dummy = std :: enable_if_t < IsByte && sizeof ...( RestDimensions ) == 0 >>
_CONSTEXPR auto as_array_view () const _NOEXCEPT -> array_view < U , ( Base :: bounds_type :: dynamic_rank == 0 ? Base :: bounds_type :: static_size / sizeof ( U ) : static_cast < size_type > ( dynamic_range )) >
{
static_assert ( std :: is_standard_layout < U >:: value && ( Base :: bounds_type :: static_size == dynamic_range || Base :: bounds_type :: static_size % sizeof ( U ) == 0 ),
"Target type must be standard layout and its size must match the byte array size" );
fail_fast_assert (( this -> bytes () % sizeof ( U )) == 0 );
2015-09-14 16:34:26 -07:00
return { reinterpret_cast < U *> ( this -> data ()), this -> bytes () / sizeof ( U ) };
2015-08-20 18:09:14 -07:00
}
2015-08-30 23:30:15 -07:00
2015-08-20 18:09:14 -07:00
// section on linear space
template < size_t Count >
_CONSTEXPR array_view < ValueTypeOpt , Count > first () const _NOEXCEPT
{
static_assert ( bounds_type :: static_size == dynamic_range || Count <= bounds_type :: static_size , "Index is out of bound" );
fail_fast_assert ( bounds_type :: static_size != dynamic_range || Count <= this -> size ()); // ensures we only check condition when needed
2015-09-14 16:34:26 -07:00
return { this -> data (), Count };
2015-08-20 18:09:14 -07:00
}
_CONSTEXPR array_view < ValueTypeOpt , dynamic_range > first ( size_type count ) const _NOEXCEPT
{
fail_fast_assert ( count <= this -> size ());
2015-09-14 16:34:26 -07:00
return { this -> data (), count };
2015-08-20 18:09:14 -07:00
}
template < size_t Count >
_CONSTEXPR array_view < ValueTypeOpt , Count > last () const _NOEXCEPT
{
static_assert ( bounds_type :: static_size == dynamic_range || Count <= bounds_type :: static_size , "Index is out of bound" );
fail_fast_assert ( bounds_type :: static_size != dynamic_range || Count <= this -> size ());
2015-09-14 16:34:26 -07:00
return { this -> data () + this -> size () - Count , Count };
2015-08-20 18:09:14 -07:00
}
_CONSTEXPR array_view < ValueTypeOpt , dynamic_range > last ( size_type count ) const _NOEXCEPT
{
fail_fast_assert ( count <= this -> size ());
2015-09-14 16:34:26 -07:00
return { this -> data () + this -> size () - count , count };
2015-08-20 18:09:14 -07:00
}
template < size_t Offset , size_t Count >
_CONSTEXPR array_view < ValueTypeOpt , Count > sub () const _NOEXCEPT
{
2015-09-20 19:18:12 -07:00
static_assert ( bounds_type :: static_size == dynamic_range || (( Offset == 0 || Offset <= bounds_type :: static_size ) && Offset + Count <= bounds_type :: static_size ), "Index is out of bound" );
fail_fast_assert ( bounds_type :: static_size != dynamic_range || (( Offset == 0 || Offset <= this -> size ()) && Offset + Count <= this -> size ()));
2015-09-14 16:34:26 -07:00
return { this -> data () + Offset , Count };
2015-08-20 18:09:14 -07:00
}
2015-09-20 19:18:12 -07:00
_CONSTEXPR array_view < ValueTypeOpt , dynamic_range > sub ( size_type offset , size_type count = dynamic_range ) const _NOEXCEPT
2015-08-20 18:09:14 -07:00
{
2015-09-20 19:18:12 -07:00
fail_fast_assert (( offset == 0 || offset <= this -> size ()) && ( count == dynamic_range || ( offset + count ) <= this -> size ()));
return { this -> data () + offset , count == dynamic_range ? this -> length () - offset : count };
2015-08-20 18:09:14 -07:00
}
// size
_CONSTEXPR size_type length () const _NOEXCEPT
{
return this -> size ();
}
_CONSTEXPR size_type used_length () const _NOEXCEPT
{
return length ();
}
_CONSTEXPR size_type bytes () const _NOEXCEPT
{
return sizeof ( value_type ) * this -> size ();
}
_CONSTEXPR size_type used_bytes () const _NOEXCEPT
{
return bytes ();
}
// section
_CONSTEXPR strided_array_view < ValueTypeOpt , rank > section ( index_type origin , index_type extents ) const
{
2015-09-14 21:26:17 +00:00
size_type size = this -> bounds (). total_size () - this -> bounds (). linearize ( origin );
2015-08-30 23:30:15 -07:00
return { & this -> operator []( origin ), size , strided_bounds < rank , size_type > { extents , details :: make_stride ( Base :: bounds ())} };
}
2015-09-14 21:26:17 +00:00
2015-09-14 18:55:06 -07:00
_CONSTEXPR reference operator []( const index_type & idx ) const
2015-08-30 23:30:15 -07:00
{
return Base :: operator []( idx );
}
2015-09-14 21:26:17 +00:00
2015-09-14 18:55:06 -07:00
template < bool Enabled = ( rank > 1 ), typename Dummy = std :: enable_if_t < Enabled >>
2015-08-30 23:30:15 -07:00
_CONSTEXPR array_view < ValueTypeOpt , RestDimensions ... > operator []( size_type idx ) const
{
auto ret = Base :: operator []( idx );
return { ret . data (), ret . bounds () };
2015-08-20 18:09:14 -07:00
}
2015-08-27 18:13:49 -07:00
2015-08-30 23:30:15 -07:00
using Base :: operator == ;
using Base :: operator != ;
using Base :: operator < ;
using Base :: operator <= ;
using Base :: operator > ;
using Base :: operator >= ;
2015-08-20 18:09:14 -07:00
};
template < typename T , size_t ... Dimensions >
_CONSTEXPR auto as_array_view ( T * const & ptr , dim < Dimensions > ... args ) -> array_view < std :: remove_all_extents_t < T > , Dimensions ... >
{
return { reinterpret_cast < std :: remove_all_extents_t < T >*> ( ptr ), details :: static_as_array_view_helper < static_bounds < size_t , Dimensions ... >> ( args ..., details :: Sep {})};
}
template < typename T >
_CONSTEXPR auto as_array_view ( T * arr , size_t len ) -> typename details :: ArrayViewArrayTraits < T , size_t , dynamic_range >:: type
{
return { arr , len };
}
template < typename T , size_t N >
_CONSTEXPR auto as_array_view ( T ( & arr )[ N ]) -> typename details :: ArrayViewArrayTraits < T , size_t , N >:: type
{
return { arr };
}
template < typename T , size_t N >
_CONSTEXPR array_view < const T , N > as_array_view ( const std :: array < T , N > & arr )
{
return { arr };
}
template < typename T , size_t N >
_CONSTEXPR array_view < const T , N > as_array_view ( const std :: array < T , N > && ) = delete ;
template < typename T , size_t N >
_CONSTEXPR array_view < T , N > as_array_view ( std :: array < T , N > & arr )
{
return { arr };
}
template < typename T >
_CONSTEXPR array_view < T , dynamic_range > as_array_view ( T * begin , T * end )
{
return { begin , end };
}
template < typename Cont >
_CONSTEXPR auto as_array_view ( Cont & arr ) -> std :: enable_if_t <! details :: is_array_view < std :: decay_t < Cont >>:: value ,
array_view < std :: remove_reference_t < decltype ( arr . size (), * arr . data ()) > , dynamic_range >>
{
return { arr . data (), arr . size ()};
}
template < typename Cont >
_CONSTEXPR auto as_array_view ( Cont && arr ) -> std :: enable_if_t <! details :: is_array_view < std :: decay_t < Cont >>:: value ,
array_view < std :: remove_reference_t < decltype ( arr . size (), * arr . data ()) > , dynamic_range >> = delete ;
template < typename ValueTypeOpt , unsigned int Rank >
class strided_array_view : public basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type , strided_bounds < Rank , typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type >>
{
using Base = basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type , strided_bounds < Rank , typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type >> ;
2015-08-30 23:30:15 -07:00
template < typename OtherValueOpt , unsigned int OtherRank >
friend class strided_array_view ;
2015-08-20 18:09:14 -07:00
public :
using Base :: rank ;
using typename Base :: bounds_type ;
using typename Base :: size_type ;
using typename Base :: pointer ;
using typename Base :: value_type ;
using typename Base :: index_type ;
2015-08-30 23:30:15 -07:00
using typename Base :: iterator ;
using typename Base :: const_iterator ;
2015-09-14 19:08:03 -07:00
using typename Base :: reference ;
2015-08-30 23:30:15 -07:00
// from static array of size N
template < size_type N >
strided_array_view ( value_type ( & values )[ N ], bounds_type bounds ) : Base ( values , std :: move ( bounds ))
{
fail_fast_assert ( this -> bounds (). total_size () <= N , "Bounds cross data boundaries" );
}
2015-08-20 18:09:14 -07:00
2015-08-30 23:30:15 -07:00
// from raw data
strided_array_view ( pointer ptr , size_type size , bounds_type bounds ) : Base ( ptr , std :: move ( bounds ))
2015-08-20 18:09:14 -07:00
{
2015-08-30 23:30:15 -07:00
fail_fast_assert ( this -> bounds (). total_size () <= size , "Bounds cross data boundaries" );
2015-08-20 18:09:14 -07:00
}
2015-08-30 23:30:15 -07:00
// from array view
2015-08-20 18:09:14 -07:00
template < size_t ... Dimensions , typename Dummy = std :: enable_if < sizeof ...( Dimensions ) == Rank >>
2015-08-30 23:30:15 -07:00
strided_array_view ( array_view < ValueTypeOpt , Dimensions ... > av , bounds_type bounds ) : Base ( av . data (), std :: move ( bounds ))
{
fail_fast_assert ( this -> bounds (). total_size () <= av . bounds (). total_size (), "Bounds cross data boundaries" );
}
// convertible
template < typename OtherValueTypeOpt ,
typename BaseType = basic_array_view < typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: value_type , strided_bounds < Rank , typename details :: ArrayViewTypeTraits < ValueTypeOpt >:: size_type >> ,
typename OtherBaseType = basic_array_view < typename details :: ArrayViewTypeTraits < OtherValueTypeOpt >:: value_type , strided_bounds < Rank , typename details :: ArrayViewTypeTraits < OtherValueTypeOpt >:: size_type >> ,
typename Dummy = std :: enable_if_t < std :: is_convertible < OtherBaseType , BaseType >:: value >
>
_CONSTEXPR strided_array_view ( const strided_array_view < OtherValueTypeOpt , Rank > & av ) : Base ( static_cast < const typename strided_array_view < OtherValueTypeOpt , Rank >:: Base &> ( av )) // static_cast is required
2015-08-20 18:09:14 -07:00
{
}
2015-08-30 23:30:15 -07:00
// convert from bytes
2015-09-14 18:55:06 -07:00
template < typename OtherValueType >
strided_array_view < typename std :: enable_if < std :: is_same < value_type , const byte >:: value , OtherValueType >:: type , rank > as_strided_array_view () const
2015-08-30 23:30:15 -07:00
{
static_assert (( sizeof ( OtherValueType ) >= sizeof ( value_type )) && ( sizeof ( OtherValueType ) % sizeof ( value_type ) == 0 ), "OtherValueType should have a size to contain a multiple of ValueTypes" );
auto d = sizeof ( OtherValueType ) / sizeof ( value_type );
2015-09-14 21:26:17 +00:00
size_type size = this -> bounds (). total_size () / d ;
return { ( OtherValueType * ) this -> data (), size , bounds_type { resize_extent ( this -> bounds (). index_bounds (), d ), resize_stride ( this -> bounds (). strides (), d )} };
2015-08-30 23:30:15 -07:00
}
2015-08-20 18:09:14 -07:00
strided_array_view section ( index_type origin , index_type extents ) const
{
2015-09-14 21:26:17 +00:00
size_type size = this -> bounds (). total_size () - this -> bounds (). linearize ( origin );
2015-08-30 23:30:15 -07:00
return { & this -> operator []( origin ), size , bounds_type { extents , details :: make_stride ( Base :: bounds ())}};
}
_CONSTEXPR reference operator []( const index_type & idx ) const
2015-09-14 19:08:03 -07:00
{
return Base :: operator []( idx );
}
2015-08-30 23:30:15 -07:00
template < bool Enabled = ( rank > 1 ), typename Dummy = std :: enable_if_t < Enabled >>
_CONSTEXPR strided_array_view < value_type , rank - 1 > operator []( size_type idx ) const
{
auto ret = Base :: operator []( idx );
return { ret . data (), ret . bounds (). total_size (), ret . bounds () };
}
private :
static index_type resize_extent ( const index_type & extent , size_t d )
{
fail_fast_assert ( extent [ rank - 1 ] >= d && ( extent [ rank - 1 ] % d == 0 ), "The last dimension of the array needs to contain a multiple of new type elements" );
index_type ret = extent ;
ret [ rank - 1 ] /= d ;
return ret ;
}
template < bool Enabled = ( rank == 1 ), typename Dummy = std :: enable_if_t < Enabled >>
static index_type resize_stride ( const index_type & strides , size_t d , void * p = 0 )
{
fail_fast_assert ( strides [ rank - 1 ] == 1 , "Only strided arrays with regular strides can be resized" );
return strides ;
}
template < bool Enabled = ( rank > 1 ), typename Dummy = std :: enable_if_t < Enabled >>
static index_type resize_stride ( const index_type & strides , size_t d )
{
fail_fast_assert ( strides [ rank - 1 ] == 1 , "Only strided arrays with regular strides can be resized" );
fail_fast_assert ( strides [ rank - 2 ] >= d && ( strides [ rank - 2 ] % d == 0 ), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements" );
for ( int i = rank - 2 ; i >= 0 ; -- i )
{
fail_fast_assert (( strides [ i ] >= strides [ i + 1 ]) && ( strides [ i ] % strides [ i + 1 ] == 0 ), "Only strided arrays with regular strides can be resized" );
}
index_type ret = strides / d ;
ret [ rank - 1 ] = 1 ;
return ret ;
2015-08-20 18:09:14 -07:00
}
};
template < typename ArrayView >
class contiguous_array_view_iterator : public std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type >
{
using Base = std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type > ;
public :
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
private :
template < typename ValueType , typename Bounds >
friend class basic_array_view ;
pointer m_pdata ;
const ArrayView * m_validator ;
void validateThis () const
{
2015-09-14 15:41:40 -07:00
fail_fast_assert ( m_pdata >= m_validator -> m_pdata && m_pdata < m_validator -> m_pdata + m_validator -> size (), "iterator is out of range of the array" );
2015-08-20 18:09:14 -07:00
}
contiguous_array_view_iterator ( const ArrayView * container , bool isbegin = false ) :
m_pdata ( isbegin ? container -> m_pdata : container -> m_pdata + container -> size ()), m_validator ( container ) { }
public :
reference operator * () const _NOEXCEPT
{
validateThis ();
return * m_pdata ;
}
pointer operator -> () const _NOEXCEPT
{
validateThis ();
return m_pdata ;
}
contiguous_array_view_iterator & operator ++ () _NOEXCEPT
{
++ m_pdata ;
return * this ;
}
contiguous_array_view_iterator operator ++ ( int ) _NOEXCEPT
{
auto ret = * this ;
++ ( * this );
return ret ;
}
contiguous_array_view_iterator & operator -- () _NOEXCEPT
{
-- m_pdata ;
return * this ;
}
contiguous_array_view_iterator operator -- ( int ) _NOEXCEPT
{
auto ret = * this ;
-- ( * this );
return ret ;
}
contiguous_array_view_iterator operator + ( difference_type n ) const _NOEXCEPT
{
contiguous_array_view_iterator ret { * this };
return ret += n ;
}
contiguous_array_view_iterator & operator += ( difference_type n ) _NOEXCEPT
{
m_pdata += n ;
return * this ;
}
contiguous_array_view_iterator operator - ( difference_type n ) const _NOEXCEPT
{
contiguous_array_view_iterator ret { * this };
return ret -= n ;
}
contiguous_array_view_iterator & operator -= ( difference_type n ) _NOEXCEPT
{
return * this += - n ;
}
difference_type operator - ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata - rhs . m_pdata ;
}
reference operator []( difference_type n ) const _NOEXCEPT
{
return * ( * this + n );
}
bool operator == ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata == rhs . m_pdata ;
}
bool operator != ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
bool operator < ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata < rhs . m_pdata ;
}
bool operator <= ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs < * this );
}
bool operator > ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
return rhs < * this ;
}
bool operator >= ( const contiguous_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs > * this );
}
void swap ( contiguous_array_view_iterator & rhs ) _NOEXCEPT
{
std :: swap ( m_pdata , rhs . m_pdata );
std :: swap ( m_validator , rhs . m_validator );
}
};
template < typename ArrayView >
contiguous_array_view_iterator < ArrayView > operator + ( typename contiguous_array_view_iterator < ArrayView >:: difference_type n , const contiguous_array_view_iterator < ArrayView >& rhs ) _NOEXCEPT
{
return rhs + n ;
}
template < typename ArrayView >
class general_array_view_iterator : public std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type >
{
using Base = std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type > ;
public :
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
using typename Base :: value_type ;
private :
template < typename ValueType , typename Bounds >
friend class basic_array_view ;
const ArrayView * m_container ;
2015-08-30 23:30:15 -07:00
typename ArrayView :: bounds_type :: iterator m_itr ;
2015-08-20 18:09:14 -07:00
general_array_view_iterator ( const ArrayView * container , bool isbegin = false ) :
m_container ( container ), m_itr ( isbegin ? m_container -> bounds (). begin () : m_container -> bounds (). end ())
{
}
public :
reference operator * () const _NOEXCEPT
{
return ( * m_container )[ * m_itr ];
}
pointer operator -> () const _NOEXCEPT
{
return & ( * m_container )[ * m_itr ];
}
general_array_view_iterator & operator ++ () _NOEXCEPT
{
++ m_itr ;
return * this ;
}
general_array_view_iterator operator ++ ( int ) _NOEXCEPT
{
auto ret = * this ;
++ ( * this );
return ret ;
}
general_array_view_iterator & operator -- () _NOEXCEPT
{
-- m_itr ;
return * this ;
}
general_array_view_iterator operator -- ( int ) _NOEXCEPT
{
auto ret = * this ;
-- ( * this );
return ret ;
}
general_array_view_iterator operator + ( difference_type n ) const _NOEXCEPT
{
general_array_view_iterator ret { * this };
return ret += n ;
}
general_array_view_iterator & operator += ( difference_type n ) _NOEXCEPT
{
m_itr += n ;
return * this ;
}
general_array_view_iterator operator - ( difference_type n ) const _NOEXCEPT
{
general_array_view_iterator ret { * this };
return ret -= n ;
}
general_array_view_iterator & operator -= ( difference_type n ) _NOEXCEPT
{
return * this += - n ;
}
difference_type operator - ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr - rhs . m_itr ;
}
value_type operator []( difference_type n ) const _NOEXCEPT
{
return ( * m_container )[ m_itr [ n ]];;
}
bool operator == ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr == rhs . m_itr ;
}
bool operator != ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( * this == rhs );
}
bool operator < ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr < rhs . m_itr ;
}
bool operator <= ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs < * this );
}
bool operator > ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
return rhs < * this ;
}
bool operator >= ( const general_array_view_iterator & rhs ) const _NOEXCEPT
{
return ! ( rhs > * this );
}
void swap ( general_array_view_iterator & rhs ) _NOEXCEPT
{
std :: swap ( m_itr , rhs . m_itr );
std :: swap ( m_container , rhs . m_container );
}
};
template < typename ArrayView >
general_array_view_iterator < ArrayView > operator + ( typename general_array_view_iterator < ArrayView >:: difference_type n , const general_array_view_iterator < ArrayView >& rhs ) _NOEXCEPT
{
return rhs + n ;
}
} // namespace Guide
2015-09-21 03:09:33 -07:00
#if defined(_MSC_VER) && _MSC_VER <= 1800
2015-09-14 15:11:07 -07:00
#pragma warning(pop)
#endif // _MSC_VER <= 1800
2015-08-20 18:09:14 -07:00
#pragma pop_macro("_NOEXCEPT")