2015-08-20 21:09:14 -04: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
2015-09-24 21:08:34 -04:00
# ifndef GSL_ARRAY_VIEW_H
# define GSL_ARRAY_VIEW_H
2015-08-20 21:09:14 -04:00
# include <new>
# include <stdexcept>
# include <cstddef>
# include <cstdint>
# include <limits>
2015-10-15 16:19:24 -04:00
# include <numeric>
2015-08-20 21:09:14 -04:00
# include <type_traits>
# include <utility>
# include <array>
# include <iterator>
2015-09-25 20:01:29 -04:00
# include <algorithm>
2015-10-15 19:48:38 -04:00
# include <functional>
2015-08-20 21:09:14 -04:00
# include "fail_fast.h"
2015-10-01 00:54:08 -04:00
# ifdef _MSC_VER
// No MSVC does constexpr fully yet
2015-09-28 08:10:44 -04:00
# pragma push_macro("constexpr")
# define constexpr /* nothing */
2015-08-20 21:09:14 -04:00
2015-10-01 00:54:08 -04:00
// VS 2013 workarounds
# if _MSC_VER <= 1800
2015-08-20 21:09:14 -04:00
2015-10-01 00:54:08 -04:00
// noexcept is not understood
# ifndef GSL_THROWS_FOR_TESTING
# define noexcept /* nothing */
# endif
2015-08-20 21:09:14 -04:00
2015-10-01 00:54:08 -04:00
// turn off some misguided warnings
2015-09-14 18:11:07 -04:00
# pragma warning(push)
# pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
2015-10-01 00:54:08 -04:00
2015-09-14 18:11:07 -04:00
# endif // _MSC_VER <= 1800
2015-10-01 00:54:08 -04:00
# endif // _MSC_VER
// In order to test the library, we need it to throw exceptions that we can catch
# ifdef GSL_THROWS_FOR_TESTING
# define noexcept /* nothing */
# endif // GSL_THROWS_FOR_TESTING
2015-09-29 19:41:37 -04:00
namespace gsl {
2015-08-20 21:09:14 -04:00
/*
* * begin definitions of index and bounds
*/
namespace details
{
template < typename SizeType >
struct SizeTypeTraits
{
2015-10-16 20:30:48 -04:00
static const SizeType max_value = std : : numeric_limits < SizeType > : : max ( ) ;
2015-08-20 21:09:14 -04:00
} ;
}
2015-09-25 03:42:38 -04:00
template < size_t Rank , typename ValueType = size_t >
2015-10-05 15:34:23 -04:00
class index final
2015-08-20 21:09:14 -04:00
{
2015-10-05 15:34:23 -04:00
static_assert ( std : : is_integral < ValueType > : : value , " ValueType must be an integral type! " ) ;
static_assert ( Rank > 0 , " Rank must be greater than 0! " ) ;
2015-09-25 03:42:38 -04:00
template < size_t OtherRank , typename OtherValueType >
2015-08-31 02:30:15 -04:00
friend class index ;
2015-10-05 15:34:23 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-10-05 15:34:23 -04:00
static const size_t rank = Rank ;
using value_type = std : : remove_reference_t < ValueType > ;
using reference = std : : add_lvalue_reference_t < value_type > ;
using const_reference = std : : add_lvalue_reference_t < std : : add_const_t < value_type > > ;
2015-08-20 21:09:14 -04:00
2015-10-06 00:04:56 -04:00
constexpr index ( ) noexcept
{ }
2015-10-05 15:34:23 -04:00
constexpr index ( const value_type ( & values ) [ Rank ] ) noexcept
{
std : : copy ( values , values + Rank , elems ) ;
}
2015-10-16 20:30:48 -04:00
template < typename . . . Ts , bool Enabled = ( sizeof . . . ( Ts ) = = Rank ) , typename Dummy = std : : enable_if_t < Enabled , bool > >
constexpr index ( Ts . . . ds ) noexcept : elems { static_cast < value_type > ( ds ) . . . }
{ }
2015-10-05 15:34:23 -04:00
2015-10-06 00:04:56 -04:00
constexpr index ( const index & other ) noexcept = default ;
2015-10-05 15:34:23 -04:00
// copy from index over smaller domain
2015-10-06 00:04:56 -04:00
template < typename OtherValueType ,
bool Enabled = ( details : : SizeTypeTraits < OtherValueType > : : max_value < = details : : SizeTypeTraits < value_type > : : max_value ) ,
typename Other = std : : enable_if_t < Enabled , index < Rank , OtherValueType > > >
constexpr index ( const index < Rank , OtherValueType > & other ) noexcept
2015-10-05 15:34:23 -04:00
{
std : : copy ( other . elems , other . elems + Rank , elems ) ;
}
2015-08-20 21:09:14 -04:00
2015-10-05 15:34:23 -04:00
// copy from index over larger domain
2015-10-06 00:04:56 -04:00
template < typename OtherValueType ,
bool Enabled = ( details : : SizeTypeTraits < OtherValueType > : : max_value > details : : SizeTypeTraits < value_type > : : max_value ) ,
typename Other = std : : enable_if_t < Enabled , index < Rank , OtherValueType > > >
constexpr index ( const index < Rank , OtherValueType > & other , void * ptr = 0 ) noexcept
2015-10-05 15:34:23 -04:00
{
2015-10-06 00:04:56 -04:00
bool ok = std : : accumulate ( other . elems , other . elems + Rank , true ,
[ & ] ( bool b , OtherValueType val ) { return b & & ( val < = static_cast < OtherValueType > ( details : : SizeTypeTraits < value_type > : : max_value ) ) ; }
) ;
2015-10-05 15:34:23 -04:00
2015-10-06 00:04:56 -04:00
fail_fast_assert ( ok , " other value must fit in the new domain " ) ;
std : : transform ( other . elems , other . elems + rank , elems , [ & ] ( OtherValueType val ) { return static_cast < value_type > ( val ) ; } ) ;
2015-10-05 15:34:23 -04:00
}
constexpr index & operator = ( const index & rhs ) noexcept = default ;
// Preconditions: component_idx < rank
constexpr reference operator [ ] ( size_t component_idx )
{
fail_fast_assert ( component_idx < Rank , " Component index must be less than rank " ) ;
return elems [ component_idx ] ;
}
// Preconditions: component_idx < rank
constexpr const_reference operator [ ] ( size_t component_idx ) const noexcept
{
fail_fast_assert ( component_idx < Rank , " Component index must be less than rank " ) ;
return elems [ component_idx ] ;
}
constexpr bool operator = = ( const index & rhs ) const noexcept
{
return std : : equal ( elems , elems + rank , rhs . elems ) ;
}
constexpr bool operator ! = ( const index & rhs ) const noexcept
{
return ! ( this = = rhs ) ;
}
constexpr index operator + ( ) const noexcept
{
return * this ;
}
constexpr index operator - ( ) const noexcept
{
index ret = * this ;
std : : transform ( ret , ret + rank , ret , std : : negate < ValueType > { } ) ;
return ret ;
}
constexpr index operator + ( const index & rhs ) const noexcept
{
index ret = * this ;
ret + = rhs ;
return ret ;
}
constexpr index operator - ( const index & rhs ) const noexcept
{
index ret = * this ;
ret - = rhs ;
return ret ;
}
constexpr index & operator + = ( const index & rhs ) noexcept
{
std : : transform ( elems , elems + rank , rhs . elems , elems , std : : plus < ValueType > { } ) ;
return * this ;
}
constexpr index & operator - = ( const index & rhs ) noexcept
{
std : : transform ( elems , elems + rank , rhs . elems , elems , std : : minus < ValueType > { } ) ;
return * this ;
}
constexpr index operator * ( value_type v ) const noexcept
{
index ret = * this ;
ret * = v ;
return ret ;
}
constexpr index operator / ( value_type v ) const noexcept
{
index ret = * this ;
ret / = v ;
return ret ;
}
2015-10-06 00:04:56 -04:00
friend constexpr index operator * ( value_type v , const index & rhs ) noexcept
2015-10-05 15:34:23 -04:00
{
return rhs * v ;
}
constexpr index & operator * = ( value_type v ) noexcept
{
std : : transform ( elems , elems + rank , elems , [ v ] ( value_type x ) { return std : : multiplies < ValueType > { } ( x , v ) ; } ) ;
return * this ;
}
constexpr index & operator / = ( value_type v ) noexcept
{
std : : transform ( elems , elems + rank , elems , [ v ] ( value_type x ) { return std : : divides < ValueType > { } ( x , v ) ; } ) ;
return * this ;
}
2015-10-06 00:04:56 -04:00
2015-10-05 15:34:23 -04:00
private :
value_type elems [ Rank ] = { } ;
2015-08-20 21:09:14 -04:00
} ;
template < typename ValueType >
class index < 1 , ValueType >
{
2015-09-25 03:42:38 -04:00
template < size_t , typename OtherValueType >
2015-08-20 21:09:14 -04:00
friend class index ;
2015-10-05 15:34:23 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-09-25 03:42:38 -04:00
static const size_t rank = 1 ;
2015-10-05 15:34:23 -04:00
using value_type = std : : remove_reference_t < ValueType > ;
using reference = std : : add_lvalue_reference_t < value_type > ;
using const_reference = std : : add_lvalue_reference_t < std : : add_const_t < value_type > > ;
2015-08-20 21:09:14 -04:00
2015-10-06 00:04:56 -04:00
constexpr index ( ) noexcept : value ( 0 )
2015-10-05 15:34:23 -04:00
{ }
2015-10-06 00:04:56 -04:00
constexpr index ( value_type e ) noexcept : value ( e )
2015-10-05 15:34:23 -04:00
{ }
2015-10-06 00:04:56 -04:00
constexpr index ( const value_type ( & values ) [ 1 ] ) noexcept : index ( values [ 0 ] )
{ }
2015-08-20 21:09:14 -04:00
2015-10-05 15:34:23 -04:00
constexpr index ( const index & ) noexcept = default ;
2015-08-20 21:09:14 -04:00
2015-10-06 00:04:56 -04:00
template < typename OtherValueType ,
bool Enabled = ( details : : SizeTypeTraits < OtherValueType > : : max_value < = details : : SizeTypeTraits < value_type > : : max_value ) ,
typename Other = std : : enable_if_t < Enabled , index < 1 , OtherValueType > > >
constexpr index ( const index < 1 , OtherValueType > & other ) noexcept
2015-08-20 21:09:14 -04:00
{
value = static_cast < ValueType > ( other . value ) ;
}
2015-10-06 00:04:56 -04:00
template < typename OtherValueType ,
bool Enabled = ( details : : SizeTypeTraits < OtherValueType > : : max_value > details : : SizeTypeTraits < value_type > : : max_value ) ,
typename Other = std : : enable_if_t < Enabled , index < 1 , OtherValueType > > >
constexpr index ( const index < 1 , OtherValueType > & other , void * ptr = 0 ) noexcept
2015-10-05 15:34:23 -04:00
{
2015-10-06 00:04:56 -04:00
fail_fast_assert ( other . value < = static_cast < OtherValueType > ( details : : SizeTypeTraits < value_type > : : max_value ) ) ;
2015-10-05 15:34:23 -04:00
value = static_cast < value_type > ( other . value ) ;
}
// Preconditions: component_idx < 1
constexpr reference operator [ ] ( value_type component_idx ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
fail_fast_assert ( component_idx = = 0 , " Component index must be less than rank " ) ;
2015-08-20 21:09:14 -04:00
( void ) ( component_idx ) ;
return value ;
}
2015-10-05 15:34:23 -04:00
// Preconditions: component_idx < 1
constexpr const_reference operator [ ] ( value_type component_idx ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
fail_fast_assert ( component_idx = = 0 , " Component index must be less than rank " ) ;
2015-08-20 21:09:14 -04:00
( void ) ( component_idx ) ;
return value ;
}
2015-10-01 00:54:08 -04:00
constexpr bool operator = = ( const index & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return value = = rhs . value ;
}
2015-10-01 00:54:08 -04:00
constexpr bool operator ! = ( const index & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator + ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator - ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return index ( - value ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator + ( const index & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return index ( value + rhs . value ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator - ( const index & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return index ( value - rhs . value ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator + = ( const index & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
value + = rhs . value ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator - = ( const index & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
value - = rhs . value ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator + + ( ) noexcept
2015-08-20 21:09:14 -04:00
{
+ + value ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator + + ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
index ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator - - ( ) noexcept
2015-08-20 21:09:14 -04:00
{
- - value ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator - - ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
index ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator * ( value_type v ) const noexcept
2015-08-20 21:09:14 -04:00
{
return index ( value * v ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index operator / ( value_type v ) const noexcept
2015-08-20 21:09:14 -04:00
{
return index ( value / v ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator * = ( value_type v ) noexcept
2015-08-20 21:09:14 -04:00
{
value * = v ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr index & operator / = ( value_type v ) noexcept
2015-08-20 21:09:14 -04:00
{
value / = v ;
return * this ;
}
2015-10-06 00:04:56 -04:00
friend constexpr index operator * ( value_type v , const index & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-05 15:34:23 -04:00
return { rhs * v } ;
2015-08-20 21:09:14 -04:00
}
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 {
2015-09-25 03:42:38 -04:00
static const size_t Depth = 0 ;
static const size_t DynamicNum = 0 ;
2015-08-20 21:09:14 -04:00
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 >
2015-09-28 14:20:02 -04:00
BoundsRanges ( const OtherType & , bool /* firstLevel */ ) { }
2015-09-19 02:52:30 -04:00
BoundsRanges ( const SizeType * const ) { }
2015-08-20 21:09:14 -04:00
BoundsRanges ( ) = default ;
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim >
2015-08-20 21:09:14 -04:00
void serialize ( T & ) const {
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim >
2015-08-20 21:09:14 -04:00
SizeType linearize ( const T & ) const {
return 0 ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim >
2015-08-20 21:09:14 -04:00
ptrdiff_t contains ( const T & ) const {
return 0 ;
}
2015-10-01 00:54:08 -04:00
size_t totalSize ( ) const noexcept {
2015-08-20 21:09:14 -04:00
return TotalSize ;
}
2015-10-01 00:54:08 -04:00
bool operator = = ( const BoundsRanges & ) const noexcept
2015-08-20 21:09:14 -04:00
{
return true ;
}
} ;
template < typename SizeType , size_t . . . RestRanges >
struct BoundsRanges < SizeType , dynamic_range , RestRanges . . . > : BoundsRanges < SizeType , RestRanges . . . > {
using Base = BoundsRanges < SizeType , RestRanges . . . > ;
2015-09-25 03:42:38 -04:00
static const size_t Depth = Base : : Depth + 1 ;
static const size_t DynamicNum = Base : : DynamicNum + 1 ;
2015-08-20 21:09:14 -04:00
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 >
2015-09-28 14:20:02 -04:00
BoundsRanges ( const BoundsRanges < OtherSizeType , OtherRange , RestOtherRanges . . . > & other , bool /* firstLevel */ = true ) :
2015-08-20 21:09:14 -04:00
Base ( static_cast < const BoundsRanges < OtherSizeType , RestOtherRanges . . . > & > ( other ) , false ) , m_bound ( static_cast < SizeType > ( other . totalSize ( ) ) )
{
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
void serialize ( T & arr ) const {
arr [ Dim ] = elementNum ( ) ;
this - > Base : : template serialize < T , Dim + 1 > ( arr ) ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
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 ) ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
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 ;
}
2015-10-01 00:54:08 -04:00
size_t totalSize ( ) const noexcept {
2015-08-20 21:09:14 -04:00
return m_bound ;
}
2015-10-01 00:54:08 -04:00
SizeType elementNum ( ) const noexcept {
2015-08-20 21:09:14 -04:00
return static_cast < SizeType > ( totalSize ( ) / this - > Base : : totalSize ( ) ) ;
}
2015-10-01 00:54:08 -04:00
SizeType elementNum ( size_t dim ) const noexcept {
2015-08-20 21:09:14 -04:00
if ( dim > 0 )
return this - > Base : : elementNum ( dim - 1 ) ;
else
return elementNum ( ) ;
}
2015-10-01 00:54:08 -04:00
bool operator = = ( const BoundsRanges & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
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 . . . > ;
2015-09-25 03:42:38 -04:00
static const size_t Depth = Base : : Depth + 1 ;
static const size_t DynamicNum = Base : : DynamicNum ;
2015-08-20 21:09:14 -04:00
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 ( ) ) ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
void serialize ( T & arr ) const {
arr [ Dim ] = elementNum ( ) ;
this - > Base : : template serialize < T , Dim + 1 > ( arr ) ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
SizeType linearize ( const T & arr ) const {
2015-08-31 02:30:15 -04:00
fail_fast_assert ( arr [ Dim ] < CurrentRange , " Index is out of range " ) ;
2015-08-20 21:09:14 -04:00
return static_cast < SizeType > ( this - > Base : : totalSize ( ) ) * arr [ Dim ] + this - > Base : : template linearize < T , Dim + 1 > ( arr ) ;
}
2015-09-25 03:42:38 -04:00
template < typename T , size_t Dim = 0 >
2015-08-20 21:09:14 -04:00
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 ;
}
2015-10-01 00:54:08 -04:00
size_t totalSize ( ) const noexcept {
2015-08-20 21:09:14 -04:00
return CurrentRange * this - > Base : : totalSize ( ) ;
}
2015-10-01 00:54:08 -04:00
SizeType elementNum ( ) const noexcept {
2015-08-20 21:09:14 -04:00
return CurrentRange ;
}
2015-10-01 00:54:08 -04:00
SizeType elementNum ( size_t dim ) const noexcept {
2015-08-20 21:09:14 -04:00
if ( dim > 0 )
return this - > Base : : elementNum ( dim - 1 ) ;
else
return elementNum ( ) ;
}
2015-10-01 00:54:08 -04:00
bool operator = = ( const BoundsRanges & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
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 ) { }
2015-09-25 03:42:38 -04:00
template < size_t N >
2015-08-20 21:09:14 -04:00
const TypeChain & getObj ( std : : true_type )
{
return obj ;
}
2015-09-25 03:42:38 -04:00
template < size_t N , typename MyChain = TypeChain , typename MyBase = typename MyChain : : Base >
2015-08-20 21:09:14 -04:00
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 > ( ) ;
}
2015-09-25 03:42:38 -04:00
template < size_t N >
2015-08-20 21:09:14 -04:00
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 ) ;
}
2015-10-14 13:46:22 -04:00
template < size_t Rank , typename ValueType , bool Enabled = ( Rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , index < Rank - 1 , ValueType > > >
constexpr Ret shift_left ( const index < Rank , ValueType > & other ) noexcept
{
Ret ret ;
for ( size_t i = 0 ; i < Rank - 1 ; + + i )
{
ret [ i ] = other [ i + 1 ] ;
}
return ret ;
}
2015-08-20 21:09:14 -04:00
}
template < typename IndexType >
class bounds_iterator ;
template < typename SizeType , size_t . . . Ranges >
class static_bounds {
public :
2015-09-28 14:20:02 -04:00
static_bounds ( const details : : BoundsRanges < SizeType , Ranges . . . > & ) {
2015-08-20 21:09:14 -04:00
}
} ;
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 ;
2015-09-28 08:10:44 -04:00
constexpr static_bounds ( const MyRanges & range ) : m_ranges ( range ) { }
2015-08-20 21:09:14 -04:00
template < typename SizeType2 , size_t . . . Ranges2 >
friend class static_bounds ;
public :
2015-09-25 03:42:38 -04:00
static const size_t rank = MyRanges : : Depth ;
static const size_t dynamic_rank = MyRanges : : DynamicNum ;
2015-08-20 21:09:14 -04:00
static const SizeType static_size = static_cast < SizeType > ( MyRanges : : TotalSize ) ;
using size_type = SizeType ;
using index_type = index < rank , size_type > ;
2015-10-16 15:15:22 -04:00
using const_index_type = std : : add_const_t < index_type > ;
using iterator = bounds_iterator < const_index_type > ;
using const_iterator = bounds_iterator < const_index_type > ;
2015-08-20 21:09:14 -04:00
using difference_type = ptrdiff_t ;
using sliced_type = static_bounds < SizeType , RestRanges . . . > ;
using mapping_type = contiguous_mapping_tag ;
public :
2015-09-28 08:10:44 -04:00
constexpr static_bounds ( const static_bounds & ) = default ;
2015-08-20 21:09:14 -04:00
template < typename OtherSizeType , size_t . . . Ranges , typename Dummy = std : : enable_if_t <
details : : BoundsRangeConvertible < details : : BoundsRanges < OtherSizeType , Ranges . . . > , details : : BoundsRanges < SizeType , FirstRange , RestRanges . . . > > : : value > >
2015-09-28 08:10:44 -04:00
constexpr static_bounds ( const static_bounds < OtherSizeType , Ranges . . . > & other ) :
2015-08-20 21:09:14 -04:00
m_ranges ( other . m_ranges )
{
}
2015-09-28 08:10:44 -04:00
constexpr static_bounds ( std : : initializer_list < size_type > il ) : m_ranges ( il . begin ( ) )
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04: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 21:09:14 -04:00
}
2015-09-28 08:10:44 -04:00
constexpr static_bounds ( ) = default ;
2015-08-20 21:09:14 -04:00
2015-09-28 08:10:44 -04:00
constexpr static_bounds & operator = ( const static_bounds & otherBounds )
2015-08-20 21:09:14 -04:00
{
new ( & m_ranges ) MyRanges ( otherBounds . m_ranges ) ;
return * this ;
}
2015-10-01 00:54:08 -04:00
constexpr sliced_type slice ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return sliced_type { static_cast < const details : : BoundsRanges < SizeType , RestRanges . . . > & > ( m_ranges ) } ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type stride ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return rank > 1 ? slice ( ) . size ( ) : 1 ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type size ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return static_cast < size_type > ( m_ranges . totalSize ( ) ) ;
}
2015-08-31 02:30:15 -04:00
2015-10-01 00:54:08 -04:00
constexpr size_type total_size ( ) const noexcept
2015-08-31 02:30:15 -04:00
{
return static_cast < size_type > ( m_ranges . totalSize ( ) ) ;
}
2015-08-20 21:09:14 -04:00
2015-09-28 08:10:44 -04:00
constexpr size_type linearize ( const index_type & idx ) const
2015-08-20 21:09:14 -04:00
{
return m_ranges . linearize ( idx ) ;
}
2015-10-01 00:54:08 -04:00
constexpr bool contains ( const index_type & idx ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_ranges . contains ( idx ) ! = - 1 ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type operator [ ] ( size_t index ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_ranges . elementNum ( index ) ;
}
2015-09-25 03:42:38 -04:00
template < size_t Dim = 0 >
2015-10-01 00:54:08 -04:00
constexpr size_type extent ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
static_assert ( Dim < rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
2015-08-20 21:09:14 -04:00
return details : : createTypeListIndexer ( m_ranges ) . template get < Dim > ( ) . elementNum ( ) ;
}
2015-10-01 00:54:08 -04:00
constexpr index_type index_bounds ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-14 13:46:22 -04:00
size_type extents [ rank ] = { } ;
2015-08-20 21:09:14 -04:00
m_ranges . serialize ( extents ) ;
2015-10-05 15:34:23 -04:00
return { extents } ;
2015-08-20 21:09:14 -04:00
}
template < typename OtherSizeTypes , size_t . . . Ranges >
2015-10-01 00:54:08 -04:00
constexpr bool operator = = ( const static_bounds < OtherSizeTypes , Ranges . . . > & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return this - > size ( ) = = rhs . size ( ) ;
}
template < typename OtherSizeTypes , size_t . . . Ranges >
2015-10-01 00:54:08 -04:00
constexpr bool operator ! = ( const static_bounds < OtherSizeTypes , Ranges . . . > & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-01 00:54:08 -04:00
constexpr const_iterator begin ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return const_iterator ( * this , index_type { } ) ;
2015-08-20 21:09:14 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr const_iterator end ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return const_iterator ( * this , this - > index_bounds ( ) ) ;
}
} ;
2015-09-25 03:42:38 -04:00
template < size_t Rank , typename SizeType = size_t >
2015-10-05 15:34:23 -04:00
class strided_bounds
2015-08-20 21:09:14 -04:00
{
2015-09-25 03:42:38 -04:00
template < size_t OtherRank , typename OtherSizeType >
2015-08-31 02:30:15 -04:00
friend class strided_bounds ;
2015-08-20 21:09:14 -04:00
public :
2015-10-05 15:34:23 -04:00
static const size_t rank = Rank ;
2015-10-14 13:46:22 -04:00
using reference = SizeType & ;
using const_reference = const SizeType & ;
using size_type = SizeType ;
using difference_type = SizeType ;
using value_type = SizeType ;
2015-08-20 21:09:14 -04:00
using index_type = index < rank , size_type > ;
2015-10-16 15:15:22 -04:00
using const_index_type = std : : add_const_t < index_type > ;
using iterator = bounds_iterator < const_index_type > ;
using const_iterator = bounds_iterator < const_index_type > ;
2015-08-20 21:09:14 -04:00
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 ;
2015-10-05 15:34:23 -04:00
constexpr strided_bounds ( const strided_bounds & ) noexcept = default ;
2015-08-20 21:09:14 -04:00
template < typename OtherSizeType >
2015-10-05 15:34:23 -04:00
constexpr strided_bounds ( const strided_bounds < rank , OtherSizeType > & other ) noexcept
: m_extents ( other . extents ) , m_strides ( other . strides )
{ }
constexpr strided_bounds ( const index_type & extents , const index_type & strides ) noexcept
: m_extents ( extents ) , m_strides ( strides )
{ }
2015-10-01 00:54:08 -04:00
constexpr index_type strides ( ) const noexcept
2015-10-05 15:34:23 -04:00
{
return m_strides ;
2015-08-31 02:30:15 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr size_type total_size ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
size_type ret = 0 ;
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; + + i )
2015-10-05 15:34:23 -04:00
{
ret + = ( m_extents [ i ] - 1 ) * m_strides [ i ] ;
}
2015-08-31 02:30:15 -04:00
return ret + 1 ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type size ( ) const noexcept
2015-08-31 02:30:15 -04:00
{
size_type ret = 1 ;
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; + + i )
2015-10-05 15:34:23 -04:00
{
ret * = m_extents [ i ] ;
}
2015-08-20 21:09:14 -04:00
return ret ;
}
2015-10-01 00:54:08 -04:00
constexpr bool contains ( const index_type & idx ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; + + i )
2015-08-20 21:09:14 -04:00
{
2015-10-05 15:34:23 -04:00
if ( idx [ i ] < 0 | | idx [ i ] > = m_extents [ i ] )
2015-08-20 21:09:14 -04:00
return false ;
}
return true ;
}
2015-10-05 15:34:23 -04:00
constexpr size_type linearize ( const index_type & idx ) const noexcept
2015-08-20 21:09:14 -04:00
{
size_type ret = 0 ;
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; i + + )
2015-08-20 21:09:14 -04:00
{
2015-10-05 15:34:23 -04:00
fail_fast_assert ( idx [ i ] < m_extents [ i ] , " index is out of bounds of the array " ) ;
2015-08-31 02:30:15 -04:00
ret + = idx [ i ] * m_strides [ i ] ;
2015-08-20 21:09:14 -04:00
}
return ret ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type stride ( ) const noexcept
2015-08-31 02:30:15 -04:00
{
return m_strides [ 0 ] ;
}
template < bool Enabled = ( rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , sliced_type > >
2015-09-28 08:10:44 -04:00
constexpr sliced_type slice ( ) const
2015-08-20 21:09:14 -04:00
{
2015-10-06 00:04:56 -04:00
return { details : : shift_left ( m_extents ) , details : : shift_left ( m_strides ) } ;
2015-08-20 21:09:14 -04:00
}
2015-09-25 03:42:38 -04:00
template < size_t Dim = 0 >
2015-10-01 00:54:08 -04:00
constexpr size_type extent ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
static_assert ( Dim < Rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
2015-10-05 15:34:23 -04:00
return m_extents [ Dim ] ;
2015-08-20 21:09:14 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr index_type index_bounds ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-05 15:34:23 -04:00
return m_extents ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
constexpr const_iterator begin ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return const_iterator { * this , index_type { } } ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
constexpr const_iterator end ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return const_iterator { * this , index_bounds ( ) } ;
}
2015-08-31 02:30:15 -04:00
private :
2015-10-05 15:34:23 -04:00
index_type m_extents ;
2015-08-31 02:30:15 -04:00
index_type m_strides ;
2015-08-20 21:09:14 -04: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 > { } ;
2015-09-25 03:42:38 -04:00
template < size_t Rank , typename SizeType >
2015-08-20 21:09:14 -04:00
struct is_bounds < strided_bounds < Rank , SizeType > > : std : : integral_constant < bool , true > { } ;
template < typename IndexType >
2015-10-16 15:15:22 -04:00
class bounds_iterator : public std : : iterator < std : : random_access_iterator_tag , IndexType >
2015-08-20 21:09:14 -04:00
{
private :
2015-10-16 15:15:22 -04:00
using Base = std : : iterator < std : : random_access_iterator_tag , IndexType > ;
2015-08-20 21:09:14 -04:00
public :
2015-09-25 03:42:38 -04:00
static const size_t rank = IndexType : : rank ;
2015-08-20 21:09:14 -04:00
using typename Base : : reference ;
using typename Base : : pointer ;
using typename Base : : difference_type ;
using typename Base : : value_type ;
using index_type = value_type ;
2015-10-05 15:34:23 -04:00
using index_size_type = typename IndexType : : value_type ;
2015-08-20 21:09:14 -04:00
template < typename Bounds >
2015-10-16 15:15:22 -04:00
explicit bounds_iterator ( const Bounds & bnd , value_type curr ) noexcept
: boundary ( bnd . index_bounds ( ) ) , curr ( std : : move ( curr ) )
2015-08-20 21:09:14 -04:00
{
static_assert ( is_bounds < Bounds > : : value , " Bounds type must be provided " ) ;
}
2015-10-16 15:15:22 -04:00
constexpr reference operator * ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr ;
}
2015-10-16 15:15:22 -04:00
constexpr pointer operator - > ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return & curr ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator + + ( ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-09-25 03:42:38 -04:00
for ( size_t i = rank ; i - - > 0 ; )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
if ( curr [ i ] < boundary [ i ] - 1 )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
curr [ i ] + + ;
2015-08-20 21:09:14 -04:00
return * this ;
}
2015-10-16 15:15:22 -04:00
curr [ i ] = 0 ;
2015-08-20 21:09:14 -04:00
}
// If we're here we've wrapped over - set to past-the-end.
2015-10-16 15:15:22 -04:00
curr = boundary ;
2015-08-20 21:09:14 -04:00
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator + + ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator - - ( ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
if ( ! less ( curr , boundary ) )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
// if at the past-the-end, set to last element
for ( size_t i = 0 ; i < rank ; + + i )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
curr [ i ] = boundary [ i ] - 1 ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
return * this ;
}
for ( size_t i = rank ; i - - > 0 ; )
{
if ( curr [ i ] > = 1 )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
curr [ i ] - - ;
return * this ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
curr [ i ] = boundary [ i ] - 1 ;
2015-08-20 21:09:14 -04:00
}
// If we're here the preconditions were violated
// "pre: there exists s such that r == ++s"
fail_fast_assert ( false ) ;
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator - - ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator + ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
bounds_iterator ret { * this } ;
return ret + = n ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator + = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
auto linear_idx = linearize ( curr ) + n ;
2015-10-16 15:15:22 -04:00
std : : remove_const_t < value_type > stride ;
2015-08-20 21:09:14 -04:00
stride [ rank - 1 ] = 1 ;
2015-09-25 03:42:38 -04:00
for ( size_t i = rank - 1 ; i - - > 0 ; )
2015-08-20 21:09:14 -04:00
{
stride [ i ] = stride [ i + 1 ] * boundary [ i + 1 ] ;
}
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; + + i )
2015-08-20 21:09:14 -04:00
{
curr [ i ] = linear_idx / stride [ i ] ;
linear_idx = linear_idx % stride [ i ] ;
}
2015-10-16 15:15:22 -04:00
fail_fast_assert ( ! less ( curr , index_type { } ) & & ! less ( boundary , curr ) , " index is out of bounds of the array " ) ;
2015-08-20 21:09:14 -04:00
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator - ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
bounds_iterator ret { * this } ;
return ret - = n ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator - = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
return * this + = - n ;
}
2015-10-16 15:15:22 -04:00
constexpr difference_type operator - ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return linearize ( curr ) - linearize ( rhs . curr ) ;
}
2015-10-16 15:15:22 -04:00
constexpr reference operator [ ] ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
return * ( * this + n ) ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator = = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr = = rhs . curr ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator ! = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator < ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return less ( curr , rhs . curr ) ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
constexpr bool operator < = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs < * this ) ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator > ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return rhs < * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator > = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs > * this ) ;
}
2015-10-16 15:15:22 -04:00
2015-10-01 00:54:08 -04:00
void swap ( bounds_iterator & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
std : : swap ( boundary , rhs . boundary ) ;
std : : swap ( curr , rhs . curr ) ;
}
private :
2015-10-16 15:15:22 -04:00
constexpr bool less ( index_type & one , index_type & other ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-09-25 03:42:38 -04:00
for ( size_t i = 0 ; i < rank ; + + i )
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
if ( one [ i ] < other [ i ] )
return true ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
return false ;
}
constexpr index_size_type linearize ( const value_type & idx ) const noexcept
{
// TODO: Smarter impl.
// Check if past-the-end
2015-08-20 21:09:14 -04:00
index_size_type multiplier = 1 ;
index_size_type res = 0 ;
2015-10-16 15:15:22 -04:00
if ( ! less ( idx , boundary ) )
2015-08-20 21:09:14 -04:00
{
res = 1 ;
2015-09-25 03:42:38 -04:00
for ( size_t i = rank ; i - - > 0 ; )
2015-08-20 21:09:14 -04:00
{
res + = ( idx [ i ] - 1 ) * multiplier ;
multiplier * = boundary [ i ] ;
}
}
else
{
2015-09-25 03:42:38 -04:00
for ( size_t i = rank ; i - - > 0 ; )
2015-08-20 21:09:14 -04:00
{
res + = idx [ i ] * multiplier ;
multiplier * = boundary [ i ] ;
}
}
return res ;
}
2015-10-16 15:15:22 -04:00
2015-08-20 21:09:14 -04:00
value_type boundary ;
2015-10-16 15:15:22 -04:00
std : : remove_const_t < value_type > curr ;
2015-08-20 21:09:14 -04:00
} ;
template < typename SizeType >
2015-10-16 15:15:22 -04:00
class bounds_iterator < index < 1 , SizeType > > : public std : : iterator < std : : random_access_iterator_tag , index < 1 , SizeType > >
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
using Base = std : : iterator < std : : random_access_iterator_tag , index < 1 , SizeType > > ;
2015-08-20 21:09:14 -04:00
public :
using typename Base : : reference ;
using typename Base : : pointer ;
using typename Base : : difference_type ;
using typename Base : : value_type ;
using index_type = value_type ;
2015-10-05 15:34:23 -04:00
using index_size_type = typename index_type : : value_type ;
2015-08-20 21:09:14 -04:00
template < typename Bounds >
2015-10-16 15:15:22 -04:00
constexpr explicit bounds_iterator ( const Bounds & , value_type curr ) noexcept
: curr ( std : : move ( curr ) )
2015-08-20 21:09:14 -04:00
{ }
2015-10-16 15:15:22 -04:00
constexpr reference operator * ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr ;
}
2015-10-16 15:15:22 -04:00
constexpr pointer operator - > ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
& curr ;
2015-08-20 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator + + ( ) noexcept
2015-08-20 21:09:14 -04:00
{
+ + curr ;
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator + + ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator - - ( ) noexcept
2015-08-20 21:09:14 -04:00
{
curr - - ;
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator - - ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator + ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
bounds_iterator ret { * this } ;
return ret + = n ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator + = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
curr + = n ;
return * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator operator - ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
bounds_iterator ret { * this } ;
return ret - = n ;
}
2015-10-16 15:15:22 -04:00
constexpr bounds_iterator & operator - = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
return * this + = - n ;
}
2015-10-16 15:15:22 -04:00
constexpr difference_type operator - ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr [ 0 ] - rhs . curr [ 0 ] ;
}
2015-10-16 15:15:22 -04:00
constexpr reference operator [ ] ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr + n ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator = = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr = = rhs . curr ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator ! = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator < ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return curr [ 0 ] < rhs . curr [ 0 ] ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator < = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs < * this ) ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator > ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return rhs < * this ;
}
2015-10-16 15:15:22 -04:00
constexpr bool operator > = ( const bounds_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs > * this ) ;
}
2015-10-16 15:15:22 -04:00
constexpr void swap ( bounds_iterator & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
std : : swap ( curr , rhs . curr ) ;
}
2015-10-16 15:15:22 -04:00
2015-08-20 21:09:14 -04:00
private :
2015-10-16 15:15:22 -04:00
std : : remove_const_t < value_type > curr ;
2015-08-20 21:09:14 -04:00
} ;
template < typename IndexType >
2015-10-01 00:54:08 -04:00
bounds_iterator < IndexType > operator + ( typename bounds_iterator < IndexType > : : difference_type n , const bounds_iterator < IndexType > & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
return rhs + n ;
}
/*
* * begin definitions of basic_array_view
*/
namespace details
{
template < typename Bounds >
2015-10-01 00:54:08 -04:00
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-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
return bnd . strides ( ) ;
2015-08-20 21:09:14 -04:00
}
2015-09-27 19:53:58 -04:00
// Make a stride vector from bounds, assuming contiguous memory.
2015-08-20 21:09:14 -04:00
template < typename Bounds >
2015-10-01 00:54:08 -04:00
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
2015-08-20 21:09:14 -04:00
{
auto extents = bnd . index_bounds ( ) ;
2015-10-14 13:46:22 -04:00
typename Bounds : : size_type stride [ Bounds : : rank ] = { } ;
2015-10-05 15:34:23 -04:00
stride [ Bounds : : rank - 1 ] = 1 ;
2015-10-06 00:04:56 -04:00
for ( size_t i = 1 ; i < Bounds : : rank ; + + i )
2015-10-05 15:34:23 -04:00
{
2015-10-06 00:04:56 -04:00
stride [ Bounds : : rank - i - 1 ] = stride [ Bounds : : rank - i ] * extents [ Bounds : : rank - i ] ;
2015-10-05 15:34:23 -04:00
}
return { stride } ;
2015-08-20 21:09:14 -04:00
}
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 :
2015-09-25 03:42:38 -04:00
static const size_t rank = BoundsType : : rank ;
2015-08-20 21:09:14 -04:00
using bounds_type = BoundsType ;
using size_type = typename bounds_type : : size_type ;
using index_type = typename bounds_type : : index_type ;
using value_type = ValueType ;
2015-10-16 15:15:22 -04:00
using const_value_type = std : : add_const_t < value_type > ;
2015-08-20 21:09:14 -04:00
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 > > ;
2015-10-16 15:15:22 -04:00
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_value_type , BoundsType > > , general_array_view_iterator < basic_array_view < const_value_type , BoundsType > > > ;
2015-08-20 21:09:14 -04:00
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 :
2015-10-01 00:54:08 -04:00
constexpr bounds_type bounds ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_bounds ;
}
2015-09-25 03:42:38 -04:00
template < size_t Dim = 0 >
2015-10-01 00:54:08 -04:00
constexpr size_type extent ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
static_assert ( Dim < rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
2015-08-20 21:09:14 -04:00
return m_bounds . template extent < Dim > ( ) ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type size ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_bounds . size ( ) ;
}
2015-09-28 08:10:44 -04:00
constexpr reference operator [ ] ( const index_type & idx ) const
2015-08-20 21:09:14 -04:00
{
return m_pdata [ m_bounds . linearize ( idx ) ] ;
}
2015-10-01 00:54:08 -04:00
constexpr pointer data ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_pdata ;
}
2015-08-31 02:30:15 -04:00
template < bool Enabled = ( rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , sliced_type > >
2015-09-28 08:10:44 -04:00
constexpr Ret operator [ ] ( size_type idx ) const
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
fail_fast_assert ( idx < m_bounds . size ( ) , " index is out of bounds of the array " ) ;
2015-08-20 21:09:14 -04:00
const size_type ridx = idx * m_bounds . stride ( ) ;
2015-08-31 02:30:15 -04:00
fail_fast_assert ( ridx < m_bounds . total_size ( ) , " index is out of bounds of the underlying data " ) ;
2015-08-20 21:09:14 -04:00
return Ret { m_pdata + ridx , m_bounds . slice ( ) } ;
}
2015-10-01 00:54:08 -04:00
constexpr operator bool ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return m_pdata ! = nullptr ;
}
2015-09-28 08:10:44 -04:00
constexpr iterator begin ( ) const
2015-08-20 21:09:14 -04:00
{
return iterator { this , true } ;
}
2015-09-28 08:10:44 -04:00
constexpr iterator end ( ) const
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return iterator { this , false } ;
2015-08-20 21:09:14 -04:00
}
2015-09-28 08:10:44 -04:00
constexpr const_iterator cbegin ( ) const
2015-08-20 21:09:14 -04:00
{
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > * > ( this ) , true } ;
}
2015-09-28 08:10:44 -04:00
constexpr const_iterator cend ( ) const
2015-08-20 21:09:14 -04:00
{
2015-10-16 15:15:22 -04:00
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > * > ( this ) , false } ;
2015-08-20 21:09:14 -04:00
}
2015-09-28 08:10:44 -04:00
constexpr reverse_iterator rbegin ( ) const
2015-08-20 21:09:14 -04:00
{
return reverse_iterator { end ( ) } ;
}
2015-09-28 08:10:44 -04:00
constexpr reverse_iterator rend ( ) const
2015-08-20 21:09:14 -04:00
{
return reverse_iterator { begin ( ) } ;
}
2015-09-28 08:10:44 -04:00
constexpr const_reverse_iterator crbegin ( ) const
2015-08-20 21:09:14 -04:00
{
return const_reverse_iterator { cend ( ) } ;
}
2015-09-28 08:10:44 -04:00
constexpr const_reverse_iterator crend ( ) const
2015-08-20 21:09:14 -04:00
{
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-10-01 00:54:08 -04:00
constexpr bool operator = = ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-27 21:13:49 -04:00
{
2015-08-31 02:30:15 -04:00
return m_bounds . size ( ) = = other . m_bounds . size ( ) & &
( m_pdata = = other . m_pdata | | std : : equal ( this - > begin ( ) , this - > end ( ) , other . begin ( ) ) ) ;
2015-08-27 21:13:49 -04:00
}
2015-08-31 02:30:15 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr bool operator ! = ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-31 02:30:15 -04:00
{
return ! ( * this = = other ) ;
}
2015-08-27 21:13:49 -04:00
2015-08-31 02:30:15 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr bool operator < ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-31 02:30:15 -04:00
{
return std : : lexicographical_compare ( this - > begin ( ) , this - > end ( ) , other . begin ( ) , other . end ( ) ) ;
}
2015-08-27 21:13:49 -04:00
2015-08-31 02:30:15 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr bool operator < = ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-31 02:30:15 -04:00
{
return ! ( other < * this ) ;
}
2015-08-27 21:13:49 -04:00
2015-08-31 02:30:15 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr bool operator > ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-31 02:30:15 -04:00
{
return ( other < * this ) ;
}
2015-08-27 21:13:49 -04:00
2015-08-31 02:30:15 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr bool operator > = ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-08-31 02:30:15 -04:00
{
return ! ( * this < other ) ;
}
2015-08-20 21:09:14 -04: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 > >
2015-10-01 00:54:08 -04:00
constexpr basic_array_view ( const basic_array_view < OtherValueType , OtherBounds > & other ) noexcept
2015-08-20 21:09:14 -04:00
: m_pdata ( other . m_pdata ) , m_bounds ( other . m_bounds )
{
}
protected :
2015-10-01 00:54:08 -04:00
constexpr basic_array_view ( pointer data , bounds_type bound ) noexcept
2015-08-20 21:09:14 -04:00
: m_pdata ( data )
, m_bounds ( std : : move ( bound ) )
{
fail_fast_assert ( ( m_bounds . size ( ) > 0 & & data ! = nullptr ) | | m_bounds . size ( ) = = 0 ) ;
}
template < typename T >
2015-10-01 00:54:08 -04:00
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
2015-08-20 21:09:14 -04:00
: 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 >
2015-09-28 08:10:44 -04:00
constexpr basic_array_view < value_type , DestBounds > as_array_view ( const DestBounds & bounds )
2015-08-20 21:09:14 -04:00
{
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 ;
2015-09-25 03:42:38 -04:00
template < typename ValueTypeOpt , size_t Rank >
2015-08-20 21:09:14 -04:00
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
{ } ;
2015-09-25 03:42:38 -04:00
template < typename ValueType , size_t Rank >
2015-08-20 21:09:14 -04:00
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-31 02:30:15 -04:00
using Base = basic_array_view < typename details : : ArrayViewTypeTraits < ValueTypeOpt > : : value_type ,
2015-09-14 19:34:26 -04:00
static_bounds < typename details : : ArrayViewTypeTraits < ValueTypeOpt > : : size_type , FirstDimension , RestDimensions . . . > > ;
2015-08-20 21:09:14 -04: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-31 02:30:15 -04:00
using typename Base : : iterator ;
using typename Base : : const_iterator ;
2015-09-14 17:26:17 -04:00
using typename Base : : reference ;
2015-09-14 18:41:40 -04:00
using Base : : rank ;
2015-08-20 21:09:14 -04:00
public :
// basic
2015-09-28 08:10:44 -04:00
constexpr array_view ( pointer ptr , bounds_type bounds ) : Base ( ptr , std : : move ( bounds ) )
2015-08-20 21:09:14 -04:00
{
}
2015-09-28 08:10:44 -04:00
constexpr array_view ( std : : nullptr_t ) : Base ( nullptr , bounds_type { } )
2015-08-20 21:09:14 -04:00
{
}
2015-09-28 08:10:44 -04:00
constexpr array_view ( std : : nullptr_t , size_type size ) : Base ( nullptr , bounds_type { } )
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( size = = 0 ) ;
}
// default
template < size_t DynamicRank = bounds_type : : dynamic_rank , typename Dummy = std : : enable_if_t < DynamicRank ! = 0 > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( ) : Base ( nullptr , bounds_type ( ) )
2015-08-20 21:09:14 -04:00
{
}
2015-08-31 02:30:15 -04:00
2015-08-20 21:09:14 -04: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 19:34:26 -04: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 > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( T * const & data , size_type size ) : Base ( data , typename Helper : : bounds_type { size } )
2015-08-20 21:09:14 -04: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 19:34:26 -04:00
& & std : : is_convertible < typename Helper : : bounds_type , typename Base : : bounds_type > : : value > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( T ( & arr ) [ N ] ) : Base ( arr , typename Helper : : bounds_type ( ) )
2015-08-20 21:09:14 -04: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-31 02:30:15 -04:00
& & std : : is_convertible < typename Helper : : bounds_type , typename Base : : bounds_type > : : value > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( T ( & arr ) [ N ] , size_type size ) : Base ( arr , typename Helper : : bounds_type { size } )
2015-08-20 21:09:14 -04: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 > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( std : : array < std : : remove_const_t < value_type > , N > & arr ) : Base ( arr . data ( ) , static_bounds < size_type , N > ( ) )
2015-08-20 21:09:14 -04:00
{
}
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 > >
2015-09-28 08:10:44 -04:00
constexpr array_view ( const std : : array < std : : remove_const_t < value_type > , N > & arr ) : Base ( arr . data ( ) , static_bounds < size_type , N > ( ) )
2015-08-20 21:09:14 -04:00
{
}
// 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
2015-09-28 08:10:44 -04:00
constexpr array_view ( pointer begin , Ptr end ) : Base ( begin , details : : newBoundsHelper < typename Base : : bounds_type > ( static_cast < pointer > ( end ) - begin ) )
2015-08-20 21:09:14 -04:00
{
}
// 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 19:34:26 -04:00
& & std : : is_convertible < DataType ( * ) [ ] , typename Base : : value_type ( * ) [ ] > : : value
2015-08-31 02:30:15 -04: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 21:09:14 -04:00
>
2015-09-28 08:10:44 -04:00
constexpr array_view ( Cont & cont ) : Base ( static_cast < pointer > ( cont . data ( ) ) , details : : newBoundsHelper < typename Base : : bounds_type > ( cont . size ( ) ) )
2015-08-20 21:09:14 -04:00
{
}
2015-08-31 02:30:15 -04:00
2015-09-28 08:10:44 -04:00
constexpr array_view ( const array_view & ) = default ;
2015-08-31 02:30:15 -04:00
2015-08-20 21:09:14 -04: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 >
>
2015-09-28 08:10:44 -04:00
constexpr array_view ( const array_view < OtherValueTypeOpt , OtherDimensions . . . > & av ) : Base ( static_cast < const typename array_view < OtherValueTypeOpt , OtherDimensions . . . > : : Base & > ( av ) ) { } // static_cast is required
2015-08-20 21:09:14 -04:00
// reshape
template < typename . . . Dimensions2 >
2015-09-28 08:10:44 -04:00
constexpr array_view < ValueTypeOpt , Dimensions2 : : value . . . > as_array_view ( Dimensions2 . . . dims )
2015-08-20 21:09:14 -04:00
{
static_assert ( sizeof . . . ( Dimensions2 ) > 0 , " the target array_view must have at least one dimension. " ) ;
2015-08-31 02:30:15 -04:00
using BoundsType = typename array_view < ValueTypeOpt , ( Dimensions2 : : value ) . . . > : : bounds_type ;
2015-08-20 21:09:14 -04:00
auto tobounds = details : : static_as_array_view_helper < BoundsType > ( dims . . . , details : : Sep { } ) ;
details : : verifyBoundsReshape ( this - > bounds ( ) , tobounds ) ;
2015-09-14 19:34:26 -04:00
return { this - > data ( ) , tobounds } ;
2015-08-20 21:09:14 -04:00
}
// to bytes array
template < bool Enabled = std : : is_standard_layout < std : : decay_t < typename details : : ArrayViewTypeTraits < ValueTypeOpt > : : value_type > > : : value >
2015-10-01 00:54:08 -04:00
constexpr auto as_bytes ( ) const noexcept - >
2015-08-20 21:09:14 -04: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 19:34:26 -04:00
return { reinterpret_cast < const byte * > ( this - > data ( ) ) , this - > bytes ( ) } ;
2015-08-20 21:09:14 -04:00
}
template < bool Enabled = std : : is_standard_layout < std : : decay_t < typename details : : ArrayViewTypeTraits < ValueTypeOpt > : : value_type > > : : value >
2015-10-01 00:54:08 -04:00
constexpr auto as_writeable_bytes ( ) const noexcept - >
2015-08-20 21:09:14 -04: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 19:34:26 -04:00
return { reinterpret_cast < byte * > ( this - > data ( ) ) , this - > bytes ( ) } ;
2015-08-20 21:09:14 -04:00
}
2015-09-14 19:34:26 -04:00
2015-08-20 21:09:14 -04: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 > >
2015-10-01 00:54:08 -04:00
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 ) ) >
2015-08-20 21:09:14 -04:00
{
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 19:34:26 -04:00
return { reinterpret_cast < const U * > ( this - > data ( ) ) , this - > bytes ( ) / sizeof ( U ) } ;
2015-08-20 21:09:14 -04:00
}
template < typename U , bool IsByte = std : : is_same < value_type , byte > : : value , typename Dummy = std : : enable_if_t < IsByte & & sizeof . . . ( RestDimensions ) = = 0 > >
2015-10-01 00:54:08 -04:00
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 ) ) >
2015-08-20 21:09:14 -04:00
{
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 19:34:26 -04:00
return { reinterpret_cast < U * > ( this - > data ( ) ) , this - > bytes ( ) / sizeof ( U ) } ;
2015-08-20 21:09:14 -04:00
}
2015-08-31 02:30:15 -04:00
2015-08-20 21:09:14 -04:00
// section on linear space
template < size_t Count >
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , Count > first ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
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 19:34:26 -04:00
return { this - > data ( ) , Count } ;
2015-08-20 21:09:14 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , dynamic_range > first ( size_type count ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( count < = this - > size ( ) ) ;
2015-09-14 19:34:26 -04:00
return { this - > data ( ) , count } ;
2015-08-20 21:09:14 -04:00
}
template < size_t Count >
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , Count > last ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
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 19:34:26 -04:00
return { this - > data ( ) + this - > size ( ) - Count , Count } ;
2015-08-20 21:09:14 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , dynamic_range > last ( size_type count ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( count < = this - > size ( ) ) ;
2015-09-14 19:34:26 -04:00
return { this - > data ( ) + this - > size ( ) - count , count } ;
2015-08-20 21:09:14 -04:00
}
template < size_t Offset , size_t Count >
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , Count > sub ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-09-20 22:18:12 -04: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 19:34:26 -04:00
return { this - > data ( ) + Offset , Count } ;
2015-08-20 21:09:14 -04:00
}
2015-10-01 00:54:08 -04:00
constexpr array_view < ValueTypeOpt , dynamic_range > sub ( size_type offset , size_type count = dynamic_range ) const noexcept
2015-08-20 21:09:14 -04:00
{
2015-09-20 22:18:12 -04: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 21:09:14 -04:00
}
// size
2015-10-01 00:54:08 -04:00
constexpr size_type length ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return this - > size ( ) ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type used_length ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return length ( ) ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type bytes ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return sizeof ( value_type ) * this - > size ( ) ;
}
2015-10-01 00:54:08 -04:00
constexpr size_type used_bytes ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
return bytes ( ) ;
}
// section
2015-09-28 08:10:44 -04:00
constexpr strided_array_view < ValueTypeOpt , rank > section ( index_type origin , index_type extents ) const
2015-08-20 21:09:14 -04:00
{
2015-09-14 17:26:17 -04:00
size_type size = this - > bounds ( ) . total_size ( ) - this - > bounds ( ) . linearize ( origin ) ;
2015-08-31 02:30:15 -04:00
return { & this - > operator [ ] ( origin ) , size , strided_bounds < rank , size_type > { extents , details : : make_stride ( Base : : bounds ( ) ) } } ;
}
2015-09-14 17:26:17 -04:00
2015-09-28 08:10:44 -04:00
constexpr reference operator [ ] ( const index_type & idx ) const
2015-08-31 02:30:15 -04:00
{
return Base : : operator [ ] ( idx ) ;
}
2015-09-14 17:26:17 -04:00
2015-09-14 21:55:06 -04:00
template < bool Enabled = ( rank > 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
2015-09-28 08:10:44 -04:00
constexpr array_view < ValueTypeOpt , RestDimensions . . . > operator [ ] ( size_type idx ) const
2015-08-31 02:30:15 -04:00
{
auto ret = Base : : operator [ ] ( idx ) ;
return { ret . data ( ) , ret . bounds ( ) } ;
2015-08-20 21:09:14 -04:00
}
2015-08-27 21:13:49 -04:00
2015-08-31 02:30:15 -04:00
using Base : : operator = = ;
using Base : : operator ! = ;
using Base : : operator < ;
using Base : : operator < = ;
using Base : : operator > ;
using Base : : operator > = ;
2015-08-20 21:09:14 -04:00
} ;
template < typename T , size_t . . . Dimensions >
2015-09-28 08:10:44 -04:00
constexpr auto as_array_view ( T * const & ptr , dim < Dimensions > . . . args ) - > array_view < std : : remove_all_extents_t < T > , Dimensions . . . >
2015-08-20 21:09:14 -04:00
{
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 >
2015-09-28 08:10:44 -04:00
constexpr auto as_array_view ( T * arr , size_t len ) - > typename details : : ArrayViewArrayTraits < T , size_t , dynamic_range > : : type
2015-08-20 21:09:14 -04:00
{
return { arr , len } ;
}
template < typename T , size_t N >
2015-09-28 08:10:44 -04:00
constexpr auto as_array_view ( T ( & arr ) [ N ] ) - > typename details : : ArrayViewArrayTraits < T , size_t , N > : : type
2015-08-20 21:09:14 -04:00
{
return { arr } ;
}
template < typename T , size_t N >
2015-09-28 08:10:44 -04:00
constexpr array_view < const T , N > as_array_view ( const std : : array < T , N > & arr )
2015-08-20 21:09:14 -04:00
{
return { arr } ;
}
template < typename T , size_t N >
2015-09-28 08:10:44 -04:00
constexpr array_view < const T , N > as_array_view ( const std : : array < T , N > & & ) = delete ;
2015-08-20 21:09:14 -04:00
template < typename T , size_t N >
2015-09-28 08:10:44 -04:00
constexpr array_view < T , N > as_array_view ( std : : array < T , N > & arr )
2015-08-20 21:09:14 -04:00
{
return { arr } ;
}
template < typename T >
2015-09-28 08:10:44 -04:00
constexpr array_view < T , dynamic_range > as_array_view ( T * begin , T * end )
2015-08-20 21:09:14 -04:00
{
return { begin , end } ;
}
template < typename Cont >
2015-09-28 08:10:44 -04:00
constexpr auto as_array_view ( Cont & arr ) - > std : : enable_if_t < ! details : : is_array_view < std : : decay_t < Cont > > : : value ,
2015-08-20 21:09:14 -04:00
array_view < std : : remove_reference_t < decltype ( arr . size ( ) , * arr . data ( ) ) > , dynamic_range > >
{
return { arr . data ( ) , arr . size ( ) } ;
}
template < typename Cont >
2015-09-28 08:10:44 -04:00
constexpr auto as_array_view ( Cont & & arr ) - > std : : enable_if_t < ! details : : is_array_view < std : : decay_t < Cont > > : : value ,
2015-08-20 21:09:14 -04:00
array_view < std : : remove_reference_t < decltype ( arr . size ( ) , * arr . data ( ) ) > , dynamic_range > > = delete ;
2015-09-25 03:42:38 -04:00
template < typename ValueTypeOpt , size_t Rank >
2015-08-20 21:09:14 -04:00
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-31 02:30:15 -04:00
2015-09-25 03:42:38 -04:00
template < typename OtherValueOpt , size_t OtherRank >
2015-08-31 02:30:15 -04:00
friend class strided_array_view ;
2015-08-20 21:09:14 -04: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-31 02:30:15 -04:00
using typename Base : : iterator ;
using typename Base : : const_iterator ;
2015-09-14 22:08:03 -04:00
using typename Base : : reference ;
2015-08-31 02:30:15 -04: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 21:09:14 -04:00
2015-08-31 02:30:15 -04:00
// from raw data
strided_array_view ( pointer ptr , size_type size , bounds_type bounds ) : Base ( ptr , std : : move ( bounds ) )
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
fail_fast_assert ( this - > bounds ( ) . total_size ( ) < = size , " Bounds cross data boundaries " ) ;
2015-08-20 21:09:14 -04:00
}
2015-08-31 02:30:15 -04:00
// from array view
2015-08-20 21:09:14 -04:00
template < size_t . . . Dimensions , typename Dummy = std : : enable_if < sizeof . . . ( Dimensions ) = = Rank > >
2015-08-31 02:30:15 -04:00
strided_array_view ( array_view < ValueTypeOpt , Dimensions . . . > av , bounds_type bounds ) : Base ( av . data ( ) , std : : move ( bounds ) )
2015-08-20 21:09:14 -04:00
{
2015-08-31 02:30:15 -04:00
fail_fast_assert ( this - > bounds ( ) . total_size ( ) < = av . bounds ( ) . total_size ( ) , " Bounds cross data boundaries " ) ;
2015-08-20 21:09:14 -04:00
}
2015-08-31 02:30:15 -04:00
// 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 >
>
2015-09-28 08:10:44 -04:00
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-31 02:30:15 -04:00
{
}
// convert from bytes
2015-09-14 21:55:06 -04: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-31 02:30:15 -04: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 17:26:17 -04: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-31 02:30:15 -04:00
}
2015-08-20 21:09:14 -04:00
strided_array_view section ( index_type origin , index_type extents ) const
{
2015-09-14 17:26:17 -04:00
size_type size = this - > bounds ( ) . total_size ( ) - this - > bounds ( ) . linearize ( origin ) ;
2015-08-31 02:30:15 -04:00
return { & this - > operator [ ] ( origin ) , size , bounds_type { extents , details : : make_stride ( Base : : bounds ( ) ) } } ;
}
2015-09-28 08:10:44 -04:00
constexpr reference operator [ ] ( const index_type & idx ) const
2015-09-14 22:08:03 -04:00
{
return Base : : operator [ ] ( idx ) ;
}
2015-08-31 02:30:15 -04:00
template < bool Enabled = ( rank > 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
2015-09-28 08:10:44 -04:00
constexpr strided_array_view < value_type , rank - 1 > operator [ ] ( size_type idx ) const
2015-08-31 02:30:15 -04:00
{
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 > >
2015-09-28 14:20:02 -04:00
static index_type resize_stride ( const index_type & strides , size_t , void * = 0 )
2015-08-31 02:30:15 -04:00
{
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 " ) ;
2015-09-27 19:53:58 -04:00
for ( size_t i = rank - 1 ; i > 0 ; - - i )
fail_fast_assert ( ( strides [ i - 1 ] > = strides [ i ] ) & & ( strides [ i - 1 ] % strides [ i ] = = 0 ) , " Only strided arrays with regular strides can be resized " ) ;
2015-08-31 02:30:15 -04:00
index_type ret = strides / d ;
ret [ rank - 1 ] = 1 ;
return ret ;
2015-08-20 21:09:14 -04: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 18:41:40 -04: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 21:09:14 -04:00
}
2015-10-16 15:15:22 -04:00
contiguous_array_view_iterator ( const ArrayView * container , bool isbegin ) :
m_pdata ( isbegin ? container - > m_pdata : container - > m_pdata + container - > size ( ) ) , m_validator ( container ) { }
2015-08-20 21:09:14 -04:00
public :
2015-10-01 00:54:08 -04:00
reference operator * ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
validateThis ( ) ;
return * m_pdata ;
}
2015-10-01 00:54:08 -04:00
pointer operator - > ( ) const noexcept
2015-08-20 21:09:14 -04:00
{
validateThis ( ) ;
return m_pdata ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator & operator + + ( ) noexcept
2015-08-20 21:09:14 -04:00
{
+ + m_pdata ;
return * this ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator operator + + ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator & operator - - ( ) noexcept
2015-08-20 21:09:14 -04:00
{
- - m_pdata ;
return * this ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator operator - - ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator operator + ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
contiguous_array_view_iterator ret { * this } ;
return ret + = n ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator & operator + = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
m_pdata + = n ;
return * this ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator operator - ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
contiguous_array_view_iterator ret { * this } ;
return ret - = n ;
}
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator & operator - = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
return * this + = - n ;
}
2015-10-01 00:54:08 -04:00
difference_type operator - ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata - rhs . m_pdata ;
}
2015-10-01 00:54:08 -04:00
reference operator [ ] ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
return * ( * this + n ) ;
}
2015-10-01 00:54:08 -04:00
bool operator = = ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata = = rhs . m_pdata ;
}
2015-10-01 00:54:08 -04:00
bool operator ! = ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-01 00:54:08 -04:00
bool operator < ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata < rhs . m_pdata ;
}
2015-10-01 00:54:08 -04:00
bool operator < = ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs < * this ) ;
}
2015-10-01 00:54:08 -04:00
bool operator > ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return rhs < * this ;
}
2015-10-01 00:54:08 -04:00
bool operator > = ( const contiguous_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs > * this ) ;
}
2015-10-01 00:54:08 -04:00
void swap ( contiguous_array_view_iterator & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
std : : swap ( m_pdata , rhs . m_pdata ) ;
std : : swap ( m_validator , rhs . m_validator ) ;
}
} ;
template < typename ArrayView >
2015-10-01 00:54:08 -04:00
contiguous_array_view_iterator < ArrayView > operator + ( typename contiguous_array_view_iterator < ArrayView > : : difference_type n , const contiguous_array_view_iterator < ArrayView > & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
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-31 02:30:15 -04:00
typename ArrayView : : bounds_type : : iterator m_itr ;
2015-10-16 15:15:22 -04:00
general_array_view_iterator ( const ArrayView * container , bool isbegin ) :
2015-08-20 21:09:14 -04:00
m_container ( container ) , m_itr ( isbegin ? m_container - > bounds ( ) . begin ( ) : m_container - > bounds ( ) . end ( ) )
{
}
public :
2015-10-16 15:15:22 -04:00
reference operator * ( ) noexcept
2015-08-20 21:09:14 -04:00
{
return ( * m_container ) [ * m_itr ] ;
}
2015-10-16 15:15:22 -04:00
pointer operator - > ( ) noexcept
2015-08-20 21:09:14 -04:00
{
return & ( * m_container ) [ * m_itr ] ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator & operator + + ( ) noexcept
2015-08-20 21:09:14 -04:00
{
+ + m_itr ;
return * this ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator operator + + ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator & operator - - ( ) noexcept
2015-08-20 21:09:14 -04:00
{
- - m_itr ;
return * this ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator operator - - ( int ) noexcept
2015-08-20 21:09:14 -04:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator operator + ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
general_array_view_iterator ret { * this } ;
return ret + = n ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator & operator + = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
m_itr + = n ;
return * this ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator operator - ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
general_array_view_iterator ret { * this } ;
return ret - = n ;
}
2015-10-01 00:54:08 -04:00
general_array_view_iterator & operator - = ( difference_type n ) noexcept
2015-08-20 21:09:14 -04:00
{
return * this + = - n ;
}
2015-10-01 00:54:08 -04:00
difference_type operator - ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr - rhs . m_itr ;
}
2015-10-01 00:54:08 -04:00
value_type operator [ ] ( difference_type n ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ( * m_container ) [ m_itr [ n ] ] ; ;
}
2015-10-01 00:54:08 -04:00
bool operator = = ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr = = rhs . m_itr ;
}
2015-10-01 00:54:08 -04:00
bool operator ! = ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( * this = = rhs ) ;
}
2015-10-01 00:54:08 -04:00
bool operator < ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr < rhs . m_itr ;
}
2015-10-01 00:54:08 -04:00
bool operator < = ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs < * this ) ;
}
2015-10-01 00:54:08 -04:00
bool operator > ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return rhs < * this ;
}
2015-10-01 00:54:08 -04:00
bool operator > = ( const general_array_view_iterator & rhs ) const noexcept
2015-08-20 21:09:14 -04:00
{
return ! ( rhs > * this ) ;
}
2015-10-01 00:54:08 -04:00
void swap ( general_array_view_iterator & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
std : : swap ( m_itr , rhs . m_itr ) ;
std : : swap ( m_container , rhs . m_container ) ;
}
} ;
template < typename ArrayView >
2015-10-01 00:54:08 -04:00
general_array_view_iterator < ArrayView > operator + ( typename general_array_view_iterator < ArrayView > : : difference_type n , const general_array_view_iterator < ArrayView > & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
return rhs + n ;
}
2015-09-29 19:41:37 -04:00
} // namespace gsl
2015-08-20 21:09:14 -04:00
2015-10-01 00:54:08 -04:00
# ifdef _MSC_VER
2015-09-28 08:10:44 -04:00
# undef constexpr
# pragma pop_macro("constexpr")
2015-10-01 00:54:08 -04:00
# if _MSC_VER <= 1800
2015-09-14 18:11:07 -04:00
# pragma warning(pop)
2015-10-01 00:54:08 -04:00
# ifndef GSL_THROWS_FOR_TESTING
# pragma undef noexcept
# endif // GSL_THROWS_FOR_TESTING
2015-09-14 18:11:07 -04:00
# endif // _MSC_VER <= 1800
2015-10-01 00:54:08 -04:00
# endif // _MSC_VER
# if defined(GSL_THROWS_FOR_TESTING)
# undef noexcept
# endif // GSL_THROWS_FOR_TESTING
2015-09-24 21:08:34 -04:00
# endif // GSL_ARRAY_VIEW_H