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-11-04 15:42:27 -05:00
# ifndef GSL_SPAN_H
# define GSL_SPAN_H
2015-09-24 21:08:34 -04:00
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-11-03 21:56:55 -05:00
# pragma push_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
# define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
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
{
2015-11-03 22:17:11 -05:00
template < typename SizeType >
struct SizeTypeTraits
{
static const SizeType max_value = std : : numeric_limits < SizeType > : : max ( ) ;
} ;
2015-10-16 20:40:57 -04:00
2015-11-03 22:17:11 -05:00
template < typename . . . Ts >
class are_integral : public std : : integral_constant < bool , true > { } ;
2015-10-16 20:40:57 -04:00
2015-11-03 22:17:11 -05:00
template < typename T , typename . . . Ts >
class are_integral < T , Ts . . . > : public std : : integral_constant < bool , std : : is_integral < T > : : value & & are_integral < Ts . . . > : : value > { } ;
2015-08-20 21:09:14 -04:00
}
2015-10-15 17:29:35 -04:00
template < size_t Rank >
2015-10-05 15:34:23 -04:00
class index final
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
static_assert ( Rank > 0 , " Rank must be greater than 0! " ) ;
2015-10-05 15:34:23 -04:00
2015-11-03 22:17:11 -05:00
template < size_t OtherRank >
friend class index ;
2015-10-05 15:34:23 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
static const size_t rank = Rank ;
using value_type = std : : ptrdiff_t ;
2015-10-23 22:49:17 -04:00
using size_type = value_type ;
2015-11-03 22:17:11 -05:00
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-11-03 22:17:11 -05:00
constexpr index ( ) noexcept
{ }
2015-10-06 00:04:56 -04:00
2015-11-03 22:17:11 -05:00
constexpr index ( const value_type ( & values ) [ Rank ] ) noexcept
{
std : : copy ( values , values + Rank , elems ) ;
}
2015-10-05 15:34:23 -04:00
2015-11-03 21:56:55 -05:00
# ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
2015-11-03 22:17:11 -05:00
template < typename T , typename . . . Ts ,
2015-11-03 21:56:55 -05:00
typename = std : : enable_if_t < ( ( sizeof . . . ( Ts ) + 1 ) = = Rank ) & &
std : : is_integral < T > : : value & &
details : : are_integral < Ts . . . > : : value > >
constexpr index ( T t , Ts . . . ds ) : index ( { static_cast < value_type > ( t ) , static_cast < value_type > ( ds ) . . . } )
{ }
# else
2015-11-03 22:17:11 -05:00
template < typename . . . Ts ,
2015-11-03 21:56:55 -05:00
typename = std : : enable_if_t < ( sizeof . . . ( Ts ) = = Rank ) & & details : : are_integral < Ts . . . > : : value > >
2015-11-03 22:17:11 -05:00
constexpr index ( Ts . . . ds ) noexcept : elems { static_cast < value_type > ( ds ) . . . }
2015-11-03 21:56:55 -05:00
{ }
# endif
2015-10-05 15:34:23 -04:00
2015-11-03 22:17:11 -05:00
constexpr index ( const index & other ) noexcept = default ;
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 < value_type > { } ) ;
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 < value_type > { } ) ;
return * this ;
}
constexpr index & operator - = ( const index & rhs ) noexcept
{
std : : transform ( elems , elems + rank , rhs . elems , elems , std : : minus < value_type > { } ) ;
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 ;
}
friend constexpr index operator * ( value_type v , const index & rhs ) noexcept
{
return rhs * v ;
}
constexpr index & operator * = ( value_type v ) noexcept
{
std : : transform ( elems , elems + rank , elems , [ v ] ( value_type x ) { return std : : multiplies < value_type > { } ( x , v ) ; } ) ;
return * this ;
}
constexpr index & operator / = ( value_type v ) noexcept
{
std : : transform ( elems , elems + rank , elems , [ v ] ( value_type x ) { return std : : divides < value_type > { } ( x , v ) ; } ) ;
return * this ;
}
2015-10-06 00:04:56 -04:00
2015-10-05 15:34:23 -04:00
private :
2015-11-03 22:17:11 -05:00
value_type elems [ Rank ] = { } ;
2015-08-20 21:09:14 -04:00
} ;
# ifndef _MSC_VER
2015-10-15 17:29:35 -04:00
2015-08-20 21:09:14 -04:00
struct static_bounds_dynamic_range_t
{
2015-11-03 22:17:11 -05:00
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 ;
}
2015-10-15 17:29:35 -04:00
2015-08-20 21:09:14 -04:00
} ;
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
{
2015-11-03 22:17:11 -05:00
return right = = left ;
2015-08-20 21:09:14 -04:00
}
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
{
2015-11-03 22:17:11 -05:00
return right ! = left ;
2015-08-20 21:09:14 -04:00
}
constexpr static_bounds_dynamic_range_t dynamic_range { } ;
# else
2015-10-15 17:29:35 -04:00
const std : : ptrdiff_t dynamic_range = - 1 ;
2015-08-20 21:09:14 -04:00
# endif
struct generalized_mapping_tag { } ;
struct contiguous_mapping_tag : generalized_mapping_tag { } ;
namespace details
{
2015-11-03 22:17:11 -05:00
template < std : : ptrdiff_t Left , std : : ptrdiff_t Right >
struct LessThan
{
static const bool value = Left < Right ;
} ;
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < std : : ptrdiff_t . . . Ranges >
struct BoundsRanges {
using size_type = std : : ptrdiff_t ;
static const size_type Depth = 0 ;
static const size_type DynamicNum = 0 ;
static const size_type CurrentRange = 1 ;
static const size_type TotalSize = 1 ;
2015-10-15 17:29:35 -04:00
2015-10-23 22:49:17 -04:00
// TODO : following signature is for work around VS bug
template < typename OtherRange >
2015-11-03 22:17:11 -05:00
BoundsRanges ( const OtherRange & , bool /* firstLevel */ )
2015-10-23 22:49:17 -04:00
{ }
2015-11-03 22:17:11 -05:00
BoundsRanges ( const BoundsRanges & ) = default ;
2015-11-12 02:46:21 -05:00
BoundsRanges & operator = ( const BoundsRanges & ) = default ;
2015-11-03 22:17:11 -05:00
BoundsRanges ( const std : : ptrdiff_t * const ) { }
BoundsRanges ( ) = default ;
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < typename T , size_t Dim >
void serialize ( T & ) const
2015-10-15 17:29:35 -04:00
{ }
2015-11-03 22:17:11 -05:00
template < typename T , size_t Dim >
size_type linearize ( const T & ) const
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
return 0 ;
}
template < typename T , size_t Dim >
bool contains ( const T & ) const
{
return 0 ;
}
2015-10-15 17:29:35 -04:00
2015-11-03 22:17:11 -05:00
size_type totalSize ( ) const noexcept
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
return TotalSize ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
bool operator = = ( const BoundsRanges & ) const noexcept
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
return true ;
}
} ;
template < std : : ptrdiff_t . . . RestRanges >
struct BoundsRanges < dynamic_range , RestRanges . . . > : BoundsRanges < RestRanges . . . > {
using Base = BoundsRanges < RestRanges . . . > ;
using size_type = std : : ptrdiff_t ;
static const size_t Depth = Base : : Depth + 1 ;
static const size_t DynamicNum = Base : : DynamicNum + 1 ;
static const size_type CurrentRange = dynamic_range ;
static const size_type TotalSize = dynamic_range ;
const size_type m_bound ;
BoundsRanges ( const BoundsRanges & ) = default ;
BoundsRanges ( const std : : ptrdiff_t * const arr ) : Base ( arr + 1 ) , m_bound ( * arr * this - > Base : : totalSize ( ) )
{
fail_fast_assert ( 0 < = * arr ) ;
}
BoundsRanges ( ) : m_bound ( 0 ) { }
template < std : : ptrdiff_t OtherRange , std : : ptrdiff_t . . . RestOtherRanges >
BoundsRanges ( const BoundsRanges < OtherRange , RestOtherRanges . . . > & other , bool /* firstLevel */ = true ) :
Base ( static_cast < const BoundsRanges < RestOtherRanges . . . > & > ( other ) , false ) , m_bound ( other . totalSize ( ) )
{ }
template < typename T , size_t Dim = 0 >
void serialize ( T & arr ) const
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
arr [ Dim ] = elementNum ( ) ;
this - > Base : : template serialize < T , Dim + 1 > ( arr ) ;
}
2015-10-15 17:29:35 -04:00
2015-11-03 22:17:11 -05:00
template < typename T , size_t Dim = 0 >
size_type linearize ( const T & arr ) const
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
const size_type index = this - > Base : : totalSize ( ) * arr [ Dim ] ;
fail_fast_assert ( index < m_bound ) ;
return index + this - > Base : : template linearize < T , Dim + 1 > ( arr ) ;
}
template < typename T , size_t Dim = 0 >
size_type contains ( const T & arr ) const
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
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 cur < m_bound ? cur + last : - 1 ;
}
size_type totalSize ( ) const noexcept
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
return m_bound ;
}
2015-10-15 17:29:35 -04:00
size_type elementNum ( ) const noexcept
{
2015-11-03 22:17:11 -05:00
return totalSize ( ) / this - > Base : : totalSize ( ) ;
}
2015-10-15 17:29:35 -04:00
size_type elementNum ( size_t dim ) const noexcept
{
2015-11-03 22:17:11 -05:00
if ( dim > 0 )
return this - > Base : : elementNum ( dim - 1 ) ;
else
return elementNum ( ) ;
}
bool operator = = ( const BoundsRanges & rhs ) const noexcept
{
return m_bound = = rhs . m_bound & & static_cast < const Base & > ( * this ) = = static_cast < const Base & > ( rhs ) ;
}
} ;
template < std : : ptrdiff_t CurRange , std : : ptrdiff_t . . . RestRanges >
struct BoundsRanges < CurRange , RestRanges . . . > : BoundsRanges < RestRanges . . . >
{
using Base = BoundsRanges < RestRanges . . . > ;
using size_type = std : : ptrdiff_t ;
static const size_t Depth = Base : : Depth + 1 ;
static const size_t DynamicNum = Base : : DynamicNum ;
static const size_type CurrentRange = CurRange ;
static const size_type TotalSize = Base : : TotalSize = = dynamic_range ? dynamic_range : CurrentRange * Base : : TotalSize ;
BoundsRanges ( const BoundsRanges & ) = default ;
BoundsRanges ( const std : : ptrdiff_t * const arr ) : Base ( arr ) { }
BoundsRanges ( ) = default ;
template < std : : ptrdiff_t OtherRange , std : : ptrdiff_t . . . RestOtherRanges >
BoundsRanges ( const BoundsRanges < OtherRange , RestOtherRanges . . . > & other , bool firstLevel = true ) : Base ( static_cast < const BoundsRanges < RestOtherRanges . . . > & > ( other ) , false )
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
fail_fast_assert ( ( firstLevel & & totalSize ( ) < = other . totalSize ( ) ) | | totalSize ( ) = = other . totalSize ( ) ) ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < typename T , size_t Dim = 0 >
void serialize ( T & arr ) const
{
arr [ Dim ] = elementNum ( ) ;
this - > Base : : template serialize < T , Dim + 1 > ( arr ) ;
}
template < typename T , size_t Dim = 0 >
size_type linearize ( const T & arr ) const
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
fail_fast_assert ( arr [ Dim ] < CurrentRange , " Index is out of range " ) ;
return this - > Base : : totalSize ( ) * arr [ Dim ] + this - > Base : : template linearize < T , Dim + 1 > ( arr ) ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < typename T , size_t Dim = 0 >
2015-10-15 17:29:35 -04:00
size_type contains ( const T & arr ) const
{
2015-11-03 22:17:11 -05:00
if ( arr [ Dim ] > = CurrentRange )
return - 1 ;
const size_type last = this - > Base : : template contains < T , Dim + 1 > ( arr ) ;
if ( last = = - 1 )
return - 1 ;
return this - > Base : : totalSize ( ) * arr [ Dim ] + last ;
}
size_type totalSize ( ) const noexcept
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
return CurrentRange * this - > Base : : totalSize ( ) ;
}
2015-08-20 21:09:14 -04:00
2015-10-15 17:29:35 -04:00
size_type elementNum ( ) const noexcept
{
2015-11-03 22:17:11 -05:00
return CurrentRange ;
}
size_type elementNum ( size_t dim ) const noexcept
{
if ( dim > 0 )
return this - > Base : : elementNum ( dim - 1 ) ;
else
return elementNum ( ) ;
}
bool operator = = ( const BoundsRanges & rhs ) const noexcept
{
return static_cast < const Base & > ( * this ) = = static_cast < const Base & > ( rhs ) ;
}
} ;
template < typename SourceType , typename TargetType , size_t Rank >
struct BoundsRangeConvertible2 ;
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 , std : : ptrdiff_t Rank = TargetType : : Depth >
struct BoundsRangeConvertible : decltype ( helpBoundsRangeConvertible < Rank - 1 > ( SourceType ( ) , TargetType ( ) ,
std : : integral_constant < bool , SourceType : : Depth = = TargetType : : Depth
& & ( ! LessThan < SourceType : : CurrentRange , TargetType : : CurrentRange > : : value | | TargetType : : CurrentRange = = dynamic_range | | SourceType : : CurrentRange = = dynamic_range ) > ( ) ) )
{ } ;
template < typename SourceType , typename TargetType >
struct BoundsRangeConvertible < SourceType , TargetType , 0 > : std : : true_type { } ;
template < typename TypeChain >
struct TypeListIndexer
{
const TypeChain & obj ;
TypeListIndexer ( const TypeChain & obj ) : obj ( obj ) { }
template < size_t N >
const TypeChain & getObj ( std : : true_type )
{
return obj ;
}
template < size_t N , typename MyChain = TypeChain , typename MyBase = typename MyChain : : Base >
auto getObj ( std : : false_type ) - > decltype ( TypeListIndexer < MyBase > ( static_cast < const MyBase & > ( obj ) ) . template get < N > ( ) )
{
return TypeListIndexer < MyBase > ( static_cast < const MyBase & > ( obj ) ) . template get < N > ( ) ;
}
template < size_t N >
auto get ( ) - > decltype ( getObj < N - 1 > ( std : : integral_constant < bool , true > ( ) ) )
{
return getObj < N - 1 > ( std : : integral_constant < bool , N = = 0 > ( ) ) ;
}
} ;
template < typename TypeChain >
TypeListIndexer < TypeChain > createTypeListIndexer ( const TypeChain & obj )
{
return TypeListIndexer < TypeChain > ( obj ) ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < size_t Rank , bool Enabled = ( Rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , index < Rank - 1 > > >
constexpr Ret shift_left ( const index < Rank > & other ) noexcept
{
Ret ret { } ;
for ( size_t i = 0 ; i < Rank - 1 ; + + i )
2015-10-15 17:29:35 -04:00
{
2015-11-03 22:17:11 -05:00
ret [ i ] = other [ i + 1 ] ;
}
return ret ;
}
2015-08-20 21:09:14 -04:00
}
template < typename IndexType >
class bounds_iterator ;
2015-10-15 17:29:35 -04:00
template < std : : ptrdiff_t . . . Ranges >
class static_bounds
{
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
static_bounds ( const details : : BoundsRanges < Ranges . . . > & ) {
}
2015-08-20 21:09:14 -04:00
} ;
2015-10-15 17:29:35 -04:00
template < std : : ptrdiff_t FirstRange , std : : ptrdiff_t . . . RestRanges >
class static_bounds < FirstRange , RestRanges . . . >
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
using MyRanges = details : : BoundsRanges < FirstRange , RestRanges . . . > ;
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
MyRanges m_ranges ;
constexpr static_bounds ( const MyRanges & range ) : m_ranges ( range )
2015-10-15 17:29:35 -04:00
{ }
2015-11-03 22:17:11 -05:00
template < std : : ptrdiff_t . . . OtherRanges >
friend class static_bounds ;
2015-10-15 17:29:35 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
static const size_t rank = MyRanges : : Depth ;
static const size_t dynamic_rank = MyRanges : : DynamicNum ;
static const std : : ptrdiff_t static_size = MyRanges : : TotalSize ;
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
using size_type = std : : ptrdiff_t ;
using index_type = index < rank > ;
2015-10-28 19:53:53 -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 > ;
using difference_type = std : : ptrdiff_t ;
2015-11-03 22:17:11 -05:00
using sliced_type = static_bounds < RestRanges . . . > ;
using mapping_type = contiguous_mapping_tag ;
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
constexpr static_bounds ( const static_bounds & ) = default ;
template < std : : ptrdiff_t . . . Ranges , typename Dummy = std : : enable_if_t <
details : : BoundsRangeConvertible < details : : BoundsRanges < Ranges . . . > , details : : BoundsRanges < FirstRange , RestRanges . . . > > : : value > >
2015-10-15 17:29:35 -04:00
constexpr static_bounds ( const static_bounds < Ranges . . . > & other ) : m_ranges ( other . m_ranges )
{ }
2015-10-28 19:53:53 -04:00
2015-11-03 22:17:11 -05:00
constexpr static_bounds ( std : : initializer_list < size_type > il ) : m_ranges ( ( const std : : ptrdiff_t * ) il . begin ( ) )
{
fail_fast_assert ( ( MyRanges : : DynamicNum = = 0 & & il . size ( ) = = 1 & & * il . begin ( ) = = static_size ) | | MyRanges : : DynamicNum = = il . size ( ) , " Size of the initializer list must match the rank of the array " ) ;
fail_fast_assert ( m_ranges . totalSize ( ) < = PTRDIFF_MAX , " Size of the range is larger than the max element of the size type " ) ;
}
constexpr static_bounds ( ) = default ;
constexpr static_bounds & operator = ( const static_bounds & otherBounds )
{
new ( & m_ranges ) MyRanges ( otherBounds . m_ranges ) ;
return * this ;
}
constexpr sliced_type slice ( ) const noexcept
{
return sliced_type { static_cast < const details : : BoundsRanges < RestRanges . . . > & > ( m_ranges ) } ;
}
constexpr size_type stride ( ) const noexcept
{
return rank > 1 ? slice ( ) . size ( ) : 1 ;
}
constexpr size_type size ( ) const noexcept
{
return m_ranges . totalSize ( ) ;
}
constexpr size_type total_size ( ) const noexcept
{
return m_ranges . totalSize ( ) ;
}
constexpr size_type linearize ( const index_type & idx ) const
{
return m_ranges . linearize ( idx ) ;
}
constexpr bool contains ( const index_type & idx ) const noexcept
{
return m_ranges . contains ( idx ) ! = - 1 ;
}
constexpr size_type operator [ ] ( size_t index ) const noexcept
{
return m_ranges . elementNum ( index ) ;
}
template < size_t Dim = 0 >
constexpr size_type extent ( ) const noexcept
{
static_assert ( Dim < rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
return details : : createTypeListIndexer ( m_ranges ) . template get < Dim > ( ) . elementNum ( ) ;
}
constexpr index_type index_bounds ( ) const noexcept
{
size_type extents [ rank ] = { } ;
m_ranges . serialize ( extents ) ;
return { extents } ;
}
template < std : : ptrdiff_t . . . Ranges >
constexpr bool operator = = ( const static_bounds < Ranges . . . > & rhs ) const noexcept
{
return this - > size ( ) = = rhs . size ( ) ;
}
template < std : : ptrdiff_t . . . Ranges >
constexpr bool operator ! = ( const static_bounds < Ranges . . . > & rhs ) const noexcept
{
return ! ( * this = = rhs ) ;
}
constexpr const_iterator begin ( ) const noexcept
{
return const_iterator ( * this , index_type { } ) ;
}
constexpr const_iterator end ( ) const noexcept
{
return const_iterator ( * this , this - > index_bounds ( ) ) ;
}
2015-08-20 21:09:14 -04:00
} ;
2015-10-15 17:29:35 -04:00
template < size_t Rank >
2015-10-23 22:49:17 -04:00
class strided_bounds
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
template < size_t OtherRank >
friend class strided_bounds ;
2015-08-31 02:30:15 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
static const size_t rank = Rank ;
2015-10-23 22:49:17 -04:00
using value_type = std : : ptrdiff_t ;
2015-11-03 22:17:11 -05:00
using reference = std : : add_lvalue_reference_t < value_type > ;
using const_reference = std : : add_const_t < reference > ;
using size_type = value_type ;
using difference_type = value_type ;
using index_type = index < rank > ;
2015-10-28 19:53:53 -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 > ;
static const value_type dynamic_rank = rank ;
2015-11-03 22:17:11 -05:00
static const value_type 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-15 19:38:53 -04:00
2015-11-03 22:17:11 -05:00
constexpr strided_bounds ( const strided_bounds & ) noexcept = default ;
2015-08-20 21:09:14 -04:00
2015-11-12 02:44:41 -05:00
constexpr strided_bounds & operator = ( const strided_bounds & ) noexcept = default ;
2015-10-15 17:29:35 -04:00
constexpr strided_bounds ( const value_type ( & values ) [ rank ] , index_type strides )
2015-10-23 22:49:17 -04:00
: m_extents ( values ) , m_strides ( std : : move ( strides ) )
2015-10-15 17:29:35 -04:00
{ }
2015-11-03 22:17:11 -05:00
constexpr strided_bounds ( const index_type & extents , const index_type & strides ) noexcept
: m_extents ( extents ) , m_strides ( strides )
{ }
constexpr index_type strides ( ) const noexcept
{
return m_strides ;
}
constexpr size_type total_size ( ) const noexcept
{
size_type ret = 0 ;
for ( size_t i = 0 ; i < rank ; + + i )
{
ret + = ( m_extents [ i ] - 1 ) * m_strides [ i ] ;
}
return ret + 1 ;
}
2015-10-15 17:29:35 -04:00
constexpr size_type size ( ) const noexcept
2015-11-03 22:17:11 -05:00
{
size_type ret = 1 ;
for ( size_t i = 0 ; i < rank ; + + i )
{
ret * = m_extents [ i ] ;
}
return ret ;
}
2015-10-15 17:29:35 -04:00
constexpr bool contains ( const index_type & idx ) const noexcept
2015-11-03 22:17:11 -05:00
{
for ( size_t i = 0 ; i < rank ; + + i )
{
if ( idx [ i ] < 0 | | idx [ i ] > = m_extents [ i ] )
return false ;
}
return true ;
}
constexpr size_type linearize ( const index_type & idx ) const noexcept
{
size_type ret = 0 ;
for ( size_t i = 0 ; i < rank ; i + + )
{
fail_fast_assert ( idx [ i ] < m_extents [ i ] , " index is out of bounds of the array " ) ;
ret + = idx [ i ] * m_strides [ i ] ;
}
return ret ;
}
2015-10-15 17:29:35 -04:00
constexpr size_type stride ( ) const noexcept
2015-11-03 22:17:11 -05:00
{
return m_strides [ 0 ] ;
}
2015-10-15 17:29:35 -04:00
template < bool Enabled = ( rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , sliced_type > >
2015-11-03 22:17:11 -05:00
constexpr sliced_type slice ( ) const
{
return { details : : shift_left ( m_extents ) , details : : shift_left ( m_strides ) } ;
}
2015-10-15 17:29:35 -04:00
template < size_t Dim = 0 >
2015-11-03 22:17:11 -05:00
constexpr size_type extent ( ) const noexcept
{
static_assert ( Dim < Rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
return m_extents [ Dim ] ;
}
2015-10-15 17:29:35 -04:00
constexpr index_type index_bounds ( ) const noexcept
2015-11-03 22:17:11 -05:00
{
return m_extents ;
}
constexpr const_iterator begin ( ) const noexcept
{
return const_iterator { * this , index_type { } } ;
}
constexpr const_iterator end ( ) const noexcept
{
return const_iterator { * this , index_bounds ( ) } ;
}
2015-10-15 17:29:35 -04:00
2015-08-31 02:30:15 -04:00
private :
2015-11-03 22:17:11 -05:00
index_type m_extents ;
index_type m_strides ;
2015-08-20 21:09:14 -04:00
} ;
template < typename T >
struct is_bounds : std : : integral_constant < bool , false > { } ;
2015-10-15 17:29:35 -04:00
template < std : : ptrdiff_t . . . Ranges >
struct is_bounds < static_bounds < Ranges . . . > > : std : : integral_constant < bool , true > { } ;
template < size_t Rank >
struct is_bounds < strided_bounds < Rank > > : std : : integral_constant < bool , true > { } ;
2015-08-20 21:09:14 -04:00
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-11-03 22:17:11 -05:00
using Base = std : : iterator < std : : random_access_iterator_tag , IndexType > ;
2015-10-16 15:15:22 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
static const size_t rank = IndexType : : rank ;
using typename Base : : reference ;
using typename Base : : pointer ;
using typename Base : : difference_type ;
using typename Base : : value_type ;
using index_type = value_type ;
using index_size_type = typename IndexType : : value_type ;
template < typename Bounds >
explicit bounds_iterator ( const Bounds & bnd , value_type curr ) noexcept
: boundary ( bnd . index_bounds ( ) ) , curr ( std : : move ( curr ) )
{
static_assert ( is_bounds < Bounds > : : value , " Bounds type must be provided " ) ;
}
constexpr reference operator * ( ) const noexcept
{
return curr ;
}
constexpr pointer operator - > ( ) const noexcept
{
return & curr ;
}
constexpr bounds_iterator & operator + + ( ) noexcept
{
for ( size_t i = rank ; i - - > 0 ; )
{
if ( curr [ i ] < boundary [ i ] - 1 )
{
curr [ i ] + + ;
return * this ;
}
curr [ i ] = 0 ;
}
// If we're here we've wrapped over - set to past-the-end.
curr = boundary ;
return * this ;
}
constexpr bounds_iterator operator + + ( int ) noexcept
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
constexpr bounds_iterator & operator - - ( ) noexcept
{
if ( ! less ( curr , boundary ) )
{
// if at the past-the-end, set to last element
for ( size_t i = 0 ; i < rank ; + + i )
{
curr [ i ] = boundary [ i ] - 1 ;
}
return * this ;
}
for ( size_t i = rank ; i - - > 0 ; )
{
if ( curr [ i ] > = 1 )
{
curr [ i ] - - ;
return * this ;
}
curr [ i ] = boundary [ i ] - 1 ;
}
// If we're here the preconditions were violated
// "pre: there exists s such that r == ++s"
fail_fast_assert ( false ) ;
return * this ;
}
constexpr bounds_iterator operator - - ( int ) noexcept
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
constexpr bounds_iterator operator + ( difference_type n ) const noexcept
{
bounds_iterator ret { * this } ;
return ret + = n ;
}
constexpr bounds_iterator & operator + = ( difference_type n ) noexcept
{
auto linear_idx = linearize ( curr ) + n ;
std : : remove_const_t < value_type > stride = 0 ;
stride [ rank - 1 ] = 1 ;
for ( size_t i = rank - 1 ; i - - > 0 ; )
{
stride [ i ] = stride [ i + 1 ] * boundary [ i + 1 ] ;
}
for ( size_t i = 0 ; i < rank ; + + i )
{
curr [ i ] = linear_idx / stride [ i ] ;
linear_idx = linear_idx % stride [ i ] ;
}
fail_fast_assert ( ! less ( curr , index_type { } ) & & ! less ( boundary , curr ) , " index is out of bounds of the array " ) ;
return * this ;
}
constexpr bounds_iterator operator - ( difference_type n ) const noexcept
{
bounds_iterator ret { * this } ;
return ret - = n ;
}
constexpr bounds_iterator & operator - = ( difference_type n ) noexcept
{
return * this + = - n ;
}
constexpr difference_type operator - ( const bounds_iterator & rhs ) const noexcept
{
return linearize ( curr ) - linearize ( rhs . curr ) ;
}
constexpr value_type operator [ ] ( difference_type n ) const noexcept
{
return * ( * this + n ) ;
}
constexpr bool operator = = ( const bounds_iterator & rhs ) const noexcept
{
return curr = = rhs . curr ;
}
constexpr bool operator ! = ( const bounds_iterator & rhs ) const noexcept
{
return ! ( * this = = rhs ) ;
}
constexpr bool operator < ( const bounds_iterator & rhs ) const noexcept
{
return less ( curr , rhs . curr ) ;
}
constexpr bool operator < = ( const bounds_iterator & rhs ) const noexcept
{
return ! ( rhs < * this ) ;
}
constexpr bool operator > ( const bounds_iterator & rhs ) const noexcept
{
return rhs < * this ;
}
constexpr bool operator > = ( const bounds_iterator & rhs ) const noexcept
{
return ! ( rhs > * this ) ;
}
void swap ( bounds_iterator & rhs ) noexcept
{
std : : swap ( boundary , rhs . boundary ) ;
std : : swap ( curr , rhs . curr ) ;
}
2015-08-20 21:09:14 -04:00
private :
2015-11-03 22:17:11 -05:00
constexpr bool less ( index_type & one , index_type & other ) const noexcept
{
for ( size_t i = 0 ; i < rank ; + + i )
{
if ( one [ i ] < other [ i ] )
return true ;
}
return false ;
}
constexpr index_size_type linearize ( const value_type & idx ) const noexcept
{
// TODO: Smarter impl.
// Check if past-the-end
index_size_type multiplier = 1 ;
index_size_type res = 0 ;
if ( ! less ( idx , boundary ) )
{
res = 1 ;
for ( size_t i = rank ; i - - > 0 ; )
{
res + = ( idx [ i ] - 1 ) * multiplier ;
multiplier * = boundary [ i ] ;
}
}
else
{
for ( size_t i = rank ; i - - > 0 ; )
{
res + = idx [ i ] * multiplier ;
multiplier * = boundary [ i ] ;
}
}
return res ;
}
value_type boundary ;
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
{
2015-11-03 22:17:11 -05:00
return rhs + n ;
2015-08-20 21:09:14 -04:00
}
2015-10-15 17:29:35 -04:00
//
2015-11-04 15:42:27 -05:00
// begin definitions of basic_span
2015-10-15 17:29:35 -04:00
//
2015-08-20 21:09:14 -04:00
namespace details
{
2015-11-03 22:17:11 -05:00
template < typename Bounds >
constexpr std : : enable_if_t < std : : is_same < typename Bounds : : mapping_type , generalized_mapping_tag > : : value , typename Bounds : : index_type > make_stride ( const Bounds & bnd ) noexcept
{
return bnd . strides ( ) ;
}
// Make a stride vector from bounds, assuming contiguous memory.
template < typename Bounds >
constexpr std : : enable_if_t < std : : is_same < typename Bounds : : mapping_type , contiguous_mapping_tag > : : value , typename Bounds : : index_type > make_stride ( const Bounds & bnd ) noexcept
{
auto extents = bnd . index_bounds ( ) ;
typename Bounds : : size_type stride [ Bounds : : rank ] = { } ;
stride [ Bounds : : rank - 1 ] = 1 ;
for ( size_t i = 1 ; i < Bounds : : rank ; + + i )
{
stride [ Bounds : : rank - i - 1 ] = stride [ Bounds : : rank - i ] * extents [ Bounds : : rank - i ] ;
}
return { stride } ;
}
template < typename BoundsSrc , typename BoundsDest >
void verifyBoundsReshape ( const BoundsSrc & src , const BoundsDest & dest )
{
static_assert ( is_bounds < BoundsSrc > : : value & & is_bounds < BoundsDest > : : value , " The src type and dest type must be bounds " ) ;
static_assert ( std : : is_same < typename BoundsSrc : : mapping_type , contiguous_mapping_tag > : : value , " The source type must be a contiguous bounds " ) ;
static_assert ( BoundsDest : : static_size = = dynamic_range | | BoundsSrc : : static_size = = dynamic_range | | BoundsDest : : static_size = = BoundsSrc : : static_size , " The source bounds must have same size as dest bounds " ) ;
fail_fast_assert ( src . size ( ) = = dest . size ( ) ) ;
}
2015-08-20 21:09:14 -04:00
} // namespace details
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
class contiguous_span_iterator ;
2015-08-20 21:09:14 -04:00
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
class general_span_iterator ;
2015-08-20 21:09:14 -04:00
enum class byte : std : : uint8_t { } ;
template < typename ValueType , typename BoundsType >
2015-11-04 15:42:27 -05:00
class basic_span
2015-08-20 21:09:14 -04:00
{
public :
2015-11-03 22:17:11 -05:00
static const size_t rank = BoundsType : : rank ;
using bounds_type = BoundsType ;
using size_type = typename bounds_type : : size_type ;
using index_type = typename bounds_type : : index_type ;
using value_type = ValueType ;
using const_value_type = std : : add_const_t < value_type > ;
using pointer = ValueType * ;
using reference = ValueType & ;
2015-11-04 15:42:27 -05:00
using iterator = std : : conditional_t < std : : is_same < typename BoundsType : : mapping_type , contiguous_mapping_tag > : : value , contiguous_span_iterator < basic_span > , general_span_iterator < basic_span > > ;
using const_iterator = std : : conditional_t < std : : is_same < typename BoundsType : : mapping_type , contiguous_mapping_tag > : : value , contiguous_span_iterator < basic_span < const_value_type , BoundsType > > , general_span_iterator < basic_span < const_value_type , BoundsType > > > ;
2015-11-03 22:17:11 -05:00
using reverse_iterator = std : : reverse_iterator < iterator > ;
using const_reverse_iterator = std : : reverse_iterator < const_iterator > ;
2015-11-04 15:42:27 -05:00
using sliced_type = std : : conditional_t < rank = = 1 , value_type , basic_span < value_type , typename BoundsType : : sliced_type > > ;
2015-08-20 21:09:14 -04:00
private :
2015-11-03 22:17:11 -05:00
pointer m_pdata ;
bounds_type m_bounds ;
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
constexpr bounds_type bounds ( ) const noexcept
{
return m_bounds ;
}
template < size_t Dim = 0 >
constexpr size_type extent ( ) const noexcept
{
static_assert ( Dim < rank , " dimension should be less than rank (dimension count starts from 0) " ) ;
return m_bounds . template extent < Dim > ( ) ;
}
constexpr size_type size ( ) const noexcept
{
return m_bounds . size ( ) ;
}
constexpr reference operator [ ] ( const index_type & idx ) const
{
return m_pdata [ m_bounds . linearize ( idx ) ] ;
}
constexpr pointer data ( ) const noexcept
{
return m_pdata ;
}
template < bool Enabled = ( rank > 1 ) , typename Ret = std : : enable_if_t < Enabled , sliced_type > >
constexpr Ret operator [ ] ( size_type idx ) const
{
fail_fast_assert ( idx < m_bounds . size ( ) , " index is out of bounds of the array " ) ;
const size_type ridx = idx * m_bounds . stride ( ) ;
fail_fast_assert ( ridx < m_bounds . total_size ( ) , " index is out of bounds of the underlying data " ) ;
return Ret { m_pdata + ridx , m_bounds . slice ( ) } ;
}
constexpr operator bool ( ) const noexcept
{
return m_pdata ! = nullptr ;
}
constexpr iterator begin ( ) const
{
return iterator { this , true } ;
}
constexpr iterator end ( ) const
{
return iterator { this , false } ;
}
constexpr const_iterator cbegin ( ) const
{
2015-11-04 15:42:27 -05:00
return const_iterator { reinterpret_cast < const basic_span < const value_type , bounds_type > * > ( this ) , true } ;
2015-11-03 22:17:11 -05:00
}
constexpr const_iterator cend ( ) const
{
2015-11-04 15:42:27 -05:00
return const_iterator { reinterpret_cast < const basic_span < const value_type , bounds_type > * > ( this ) , false } ;
2015-11-03 22:17:11 -05:00
}
constexpr reverse_iterator rbegin ( ) const
{
return reverse_iterator { end ( ) } ;
}
constexpr reverse_iterator rend ( ) const
{
return reverse_iterator { begin ( ) } ;
}
constexpr const_reverse_iterator crbegin ( ) const
{
return const_reverse_iterator { cend ( ) } ;
}
constexpr const_reverse_iterator crend ( ) const
{
return const_reverse_iterator { cbegin ( ) } ;
}
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std : : enable_if_t < std : : is_same < std : : remove_cv_t < value_type > , std : : remove_cv_t < OtherValueType > > : : value > >
2015-11-04 15:42:27 -05:00
constexpr bool operator = = ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return m_bounds . size ( ) = = other . m_bounds . size ( ) & &
( m_pdata = = other . m_pdata | | std : : equal ( this - > begin ( ) , this - > end ( ) , other . begin ( ) ) ) ;
}
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-11-04 15:42:27 -05:00
constexpr bool operator ! = ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( * this = = other ) ;
}
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-11-04 15:42:27 -05:00
constexpr bool operator < ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return std : : lexicographical_compare ( this - > begin ( ) , this - > end ( ) , other . begin ( ) , other . end ( ) ) ;
}
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-11-04 15:42:27 -05:00
constexpr bool operator < = ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( other < * this ) ;
}
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-11-04 15:42:27 -05:00
constexpr bool operator > ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ( other < * this ) ;
}
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-11-04 15:42:27 -05:00
constexpr bool operator > = ( const basic_span < OtherValueType , OtherBoundsType > & other ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( * this < other ) ;
}
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
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-11-04 15:42:27 -05:00
constexpr basic_span ( const basic_span < OtherValueType , OtherBounds > & other ) noexcept
2015-11-03 22:17:11 -05:00
: m_pdata ( other . m_pdata ) , m_bounds ( other . m_bounds )
{
}
2015-08-20 21:09:14 -04:00
protected :
2015-11-04 15:42:27 -05:00
constexpr basic_span ( pointer data , bounds_type bound ) noexcept
2015-11-03 22:17:11 -05: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-11-04 15:42:27 -05:00
constexpr basic_span ( T * data , std : : enable_if_t < std : : is_same < value_type , std : : remove_all_extents_t < T > > : : value , bounds_type > bound ) noexcept
2015-11-03 22:17:11 -05: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-11-04 15:42:27 -05:00
constexpr basic_span < value_type , DestBounds > as_span ( const DestBounds & bounds )
2015-11-03 22:17:11 -05:00
{
details : : verifyBoundsReshape ( m_bounds , bounds ) ;
return { m_pdata , bounds } ;
}
2015-08-20 21:09:14 -04:00
private :
2015-11-03 22:17:11 -05:00
friend iterator ;
friend const_iterator ;
template < typename ValueType2 , typename BoundsType2 >
2015-11-04 15:42:27 -05:00
friend class basic_span ;
2015-08-20 21:09:14 -04:00
} ;
2015-10-15 17:29:35 -04:00
template < std : : ptrdiff_t DimSize = dynamic_range >
2015-08-20 21:09:14 -04:00
struct dim
{
2015-11-03 22:17:11 -05:00
static const std : : ptrdiff_t value = DimSize ;
2015-08-20 21:09:14 -04:00
} ;
template < >
struct dim < dynamic_range >
{
2015-11-03 22:17:11 -05:00
static const std : : ptrdiff_t value = dynamic_range ;
const std : : ptrdiff_t dvalue ;
dim ( std : : ptrdiff_t size ) : dvalue ( size ) { }
2015-08-20 21:09:14 -04:00
} ;
2015-10-15 17:29:35 -04:00
template < typename ValueType , std : : ptrdiff_t FirstDimension = dynamic_range , std : : ptrdiff_t . . . RestDimensions >
2015-11-04 15:42:27 -05:00
class span ;
2015-10-15 17:29:35 -04:00
template < typename ValueType , size_t Rank >
2015-11-04 15:42:27 -05:00
class strided_span ;
2015-08-20 21:09:14 -04:00
namespace details
{
2015-11-03 22:17:11 -05:00
template < typename T , typename = std : : true_type >
struct ArrayViewTypeTraits
{
using value_type = T ;
using size_type = size_t ;
} ;
template < typename Traits >
2015-11-04 15:42:27 -05:00
struct ArrayViewTypeTraits < Traits , typename std : : is_reference < typename Traits : : span_traits & > : : type >
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
using value_type = typename Traits : : span_traits : : value_type ;
using size_type = typename Traits : : span_traits : : size_type ;
2015-11-03 22:17:11 -05:00
} ;
template < typename T , std : : ptrdiff_t . . . Ranks >
struct ArrayViewArrayTraits {
2015-11-04 15:42:27 -05:00
using type = span < T , Ranks . . . > ;
2015-11-03 22:17:11 -05:00
using value_type = T ;
using bounds_type = static_bounds < Ranks . . . > ;
using pointer = T * ;
using reference = T & ;
} ;
template < typename T , std : : ptrdiff_t N , std : : ptrdiff_t . . . Ranks >
struct ArrayViewArrayTraits < T [ N ] , Ranks . . . > : ArrayViewArrayTraits < T , Ranks . . . , N > { } ;
template < typename BoundsType >
BoundsType newBoundsHelperImpl ( std : : ptrdiff_t totalSize , std : : true_type ) // dynamic size
{
fail_fast_assert ( totalSize < = PTRDIFF_MAX ) ;
return BoundsType { totalSize } ;
}
template < typename BoundsType >
BoundsType newBoundsHelperImpl ( std : : ptrdiff_t totalSize , std : : false_type ) // static size
{
fail_fast_assert ( BoundsType : : static_size = = totalSize ) ;
return { } ;
}
template < typename BoundsType >
BoundsType newBoundsHelper ( std : : ptrdiff_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 >
2015-11-04 15:42:27 -05:00
T static_as_span_helper ( Sep , Args . . . args )
2015-11-03 22:17:11 -05:00
{
return T { static_cast < typename T : : size_type > ( args ) . . . } ;
}
template < typename T , typename Arg , typename . . . Args >
2015-11-04 15:42:27 -05:00
std : : enable_if_t < ! std : : is_same < Arg , dim < dynamic_range > > : : value & & ! std : : is_same < Arg , Sep > : : value , T > static_as_span_helper ( Arg , Args . . . args )
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
return static_as_span_helper < T > ( args . . . ) ;
2015-11-03 22:17:11 -05:00
}
template < typename T , typename . . . Args >
2015-11-04 15:42:27 -05:00
T static_as_span_helper ( dim < dynamic_range > val , Args . . . args )
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
return static_as_span_helper < T > ( args . . . , val . dvalue ) ;
2015-11-03 22:17:11 -05:00
}
template < typename . . . Dimensions >
2015-11-04 15:42:27 -05:00
struct static_as_span_static_bounds_helper
2015-11-03 22:17:11 -05:00
{
using type = static_bounds < ( Dimensions : : value ) . . . > ;
} ;
template < typename T >
2015-11-04 15:42:27 -05:00
struct is_span_oracle : std : : false_type
2015-11-03 22:17:11 -05:00
{ } ;
template < typename ValueType , std : : ptrdiff_t FirstDimension , std : : ptrdiff_t . . . RestDimensions >
2015-11-04 15:42:27 -05:00
struct is_span_oracle < span < ValueType , FirstDimension , RestDimensions . . . > > : std : : true_type
2015-11-03 22:17:11 -05:00
{ } ;
2015-11-03 21:11:49 -05:00
template < typename ValueType , std : : ptrdiff_t Rank >
2015-11-04 15:42:27 -05:00
struct is_span_oracle < strided_span < ValueType , Rank > > : std : : true_type
2015-11-03 22:17:11 -05:00
{ } ;
2015-10-15 17:29:35 -04:00
template < typename T >
2015-11-04 15:42:27 -05:00
struct is_span : is_span_oracle < std : : remove_cv_t < T > >
2015-11-03 22:17:11 -05:00
{ } ;
2015-08-20 21:09:14 -04:00
}
2015-10-15 17:29:35 -04:00
template < typename ValueType , std : : ptrdiff_t FirstDimension , std : : ptrdiff_t . . . RestDimensions >
2015-11-04 15:42:27 -05:00
class span : public basic_span < ValueType , static_bounds < FirstDimension , RestDimensions . . . > >
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
template < typename ValueType2 , std : : ptrdiff_t FirstDimension2 ,
std : : ptrdiff_t . . . RestDimensions2 >
2015-11-04 15:42:27 -05:00
friend class span ;
2015-10-15 17:29:35 -04:00
2015-11-04 15:42:27 -05:00
using Base = basic_span < ValueType , static_bounds < FirstDimension , RestDimensions . . . > > ;
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
using typename Base : : bounds_type ;
using typename Base : : size_type ;
using typename Base : : pointer ;
using typename Base : : value_type ;
using typename Base : : index_type ;
using typename Base : : iterator ;
using typename Base : : const_iterator ;
using typename Base : : reference ;
using Base : : rank ;
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
// basic
2015-11-04 15:42:27 -05:00
constexpr span ( pointer ptr , size_type size ) : Base ( ptr , bounds_type { size } )
2015-10-15 17:29:35 -04:00
{ }
2015-11-04 15:42:27 -05:00
constexpr span ( pointer ptr , bounds_type bounds ) : Base ( ptr , std : : move ( bounds ) )
2015-10-15 17:29:35 -04:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-04 15:42:27 -05:00
constexpr span ( std : : nullptr_t ) : Base ( nullptr , bounds_type { } )
2015-11-03 22:17:11 -05:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-04 15:42:27 -05:00
constexpr span ( std : : nullptr_t , size_type size ) : Base ( nullptr , bounds_type { } )
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( size = = 0 ) ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
// default
template < std : : ptrdiff_t DynamicRank = bounds_type : : dynamic_rank , typename = std : : enable_if_t < DynamicRank ! = 0 > >
2015-11-04 15:42:27 -05:00
constexpr span ( ) : Base ( nullptr , bounds_type ( ) )
2015-11-03 22:17:11 -05:00
{ }
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05: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 , dynamic_range >
2015-10-23 22:49:17 -04:00
/*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], typename Base::value_type (*)[]>::value>*/ >
2015-11-04 15:42:27 -05:00
constexpr span ( T * const & data , size_type size ) : Base ( data , typename Helper : : bounds_type { size } )
2015-11-03 22:17:11 -05:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
// from n-dimensions static array
template < typename T , size_t N , typename Helper = details : : ArrayViewArrayTraits < T , N > ,
2015-11-03 21:11:49 -05:00
typename = std : : enable_if_t < std : : is_convertible < typename Helper : : value_type ( * ) [ ] , typename Base : : value_type ( * ) [ ] > : : value > >
2015-11-04 15:42:27 -05:00
constexpr span ( T ( & arr ) [ N ] ) : Base ( arr , typename Helper : : bounds_type ( ) )
2015-11-03 22:17:11 -05:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
// from n-dimensions static array with size
template < typename T , size_t N , typename Helper = details : : ArrayViewArrayTraits < T , N > ,
typename = std : : enable_if_t < std : : is_convertible < typename Helper : : value_type ( * ) [ ] , typename Base : : value_type ( * ) [ ] > : : value >
2015-10-15 17:29:35 -04:00
>
2015-11-04 15:42:27 -05:00
constexpr span ( T ( & arr ) [ N ] , size_type size ) : Base ( arr , typename Helper : : bounds_type { size } )
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( size < = N ) ;
}
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
// from std array
template < size_t N ,
2015-10-15 17:29:35 -04:00
typename Dummy = std : : enable_if_t < std : : is_convertible < static_bounds < N > , typename Base : : bounds_type > : : value >
>
2015-11-04 15:42:27 -05:00
constexpr span ( std : : array < std : : remove_const_t < value_type > , N > & arr ) : Base ( arr . data ( ) , static_bounds < N > ( ) )
2015-11-03 22:17:11 -05:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
template < size_t N ,
2015-10-15 17:29:35 -04:00
typename Dummy = std : : enable_if_t < std : : is_convertible < static_bounds < N > , typename Base : : bounds_type > : : value
& & std : : is_const < value_type > : : value >
>
2015-11-04 15:42:27 -05:00
constexpr span ( const std : : array < std : : remove_const_t < value_type > , N > & arr ) : Base ( arr . data ( ) , static_bounds < N > ( ) )
2015-11-03 22:17:11 -05:00
{ }
2015-10-15 17:29:35 -04:00
2015-11-03 22:17:11 -05: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 >
2015-10-15 17:29:35 -04:00
> // remove literal 0 case
2015-11-04 15:42:27 -05:00
constexpr span ( pointer begin , Ptr end ) : Base ( begin , details : : newBoundsHelper < typename Base : : bounds_type > ( static_cast < pointer > ( end ) - begin ) )
2015-11-03 22:17:11 -05:00
{ }
// from containers. It must has .size() and .data() two function signatures
template < typename Cont , typename DataType = typename Cont : : value_type ,
2015-11-04 15:42:27 -05:00
typename Dummy = std : : enable_if_t < ! details : : is_span < Cont > : : value
2015-11-03 22:17:11 -05:00
& & std : : is_convertible < DataType ( * ) [ ] , typename Base : : value_type ( * ) [ ] > : : value
& & std : : is_same < std : : decay_t < decltype ( std : : declval < Cont > ( ) . size ( ) , * std : : declval < Cont > ( ) . data ( ) ) > , DataType > : : value >
>
2015-11-04 15:42:27 -05:00
constexpr span ( Cont & cont ) : Base ( static_cast < pointer > ( cont . data ( ) ) , details : : newBoundsHelper < typename Base : : bounds_type > ( cont . size ( ) ) )
2015-11-03 22:17:11 -05:00
{ }
2015-11-04 15:42:27 -05:00
constexpr span ( const span & ) = default ;
2015-11-03 22:17:11 -05:00
// convertible
template < typename OtherValueType , std : : ptrdiff_t . . . OtherDimensions ,
2015-11-04 15:42:27 -05:00
typename BaseType = basic_span < ValueType , static_bounds < FirstDimension , RestDimensions . . . > > ,
typename OtherBaseType = basic_span < OtherValueType , static_bounds < OtherDimensions . . . > > ,
2015-11-03 22:17:11 -05:00
typename Dummy = std : : enable_if_t < std : : is_convertible < OtherBaseType , BaseType > : : value >
>
2015-11-04 15:42:27 -05:00
constexpr span ( const span < OtherValueType , OtherDimensions . . . > & av )
: Base ( static_cast < const typename span < OtherValueType , OtherDimensions . . . > : : Base & > ( av ) )
2015-10-15 17:29:35 -04:00
{ }
2015-08-20 21:09:14 -04:00
2015-11-03 22:17:11 -05:00
// reshape
2015-11-03 15:44:09 -05:00
// DimCount here is a workaround for a bug in MSVC 2015
template < typename . . . Dimensions2 , size_t DimCount = sizeof . . . ( Dimensions2 ) , typename = std : : enable_if_t < ( DimCount > 0 ) > >
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , Dimensions2 : : value . . . > as_span ( Dimensions2 . . . dims )
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
using BoundsType = typename span < ValueType , ( Dimensions2 : : value ) . . . > : : bounds_type ;
auto tobounds = details : : static_as_span_helper < BoundsType > ( dims . . . , details : : Sep { } ) ;
2015-11-03 22:17:11 -05:00
details : : verifyBoundsReshape ( this - > bounds ( ) , tobounds ) ;
return { this - > data ( ) , tobounds } ;
}
// to bytes array
template < bool Enabled = std : : is_standard_layout < std : : decay_t < ValueType > > : : value >
2015-11-04 15:42:27 -05:00
auto as_bytes ( ) const noexcept - > span < const byte >
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
static_assert ( Enabled , " The value_type of span must be standarded layout " ) ;
2015-11-03 22:17:11 -05:00
return { reinterpret_cast < const byte * > ( this - > data ( ) ) , this - > bytes ( ) } ;
}
template < bool Enabled = std : : is_standard_layout < std : : decay_t < ValueType > > : : value >
2015-11-04 15:42:27 -05:00
auto as_writeable_bytes ( ) const noexcept - > span < byte >
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
static_assert ( Enabled , " The value_type of span must be standarded layout " ) ;
2015-11-03 22:17:11 -05:00
return { reinterpret_cast < byte * > ( this - > data ( ) ) , this - > bytes ( ) } ;
}
2015-08-20 21:09:14 -04:00
2015-10-15 17:29:35 -04:00
// from bytes array
2015-11-03 22:17:11 -05:00
template < typename U , bool IsByte = std : : is_same < value_type , const byte > : : value , typename = std : : enable_if_t < IsByte & & sizeof . . . ( RestDimensions ) = = 0 > >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( ) const noexcept - > span < const U , ( Base : : bounds_type : : static_size ! = dynamic_range ? static_cast < std : : ptrdiff_t > ( static_cast < size_t > ( Base : : bounds_type : : static_size ) / sizeof ( U ) ) : dynamic_range ) >
2015-11-03 22:17:11 -05:00
{
static_assert ( std : : is_standard_layout < U > : : value & & ( Base : : bounds_type : : static_size = = dynamic_range | | Base : : bounds_type : : static_size % static_cast < size_type > ( 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 & & ( this - > bytes ( ) / sizeof ( U ) ) < PTRDIFF_MAX ) ;
return { reinterpret_cast < const U * > ( this - > data ( ) ) , this - > bytes ( ) / static_cast < size_type > ( sizeof ( U ) ) } ;
}
template < typename U , bool IsByte = std : : is_same < value_type , byte > : : value , typename = std : : enable_if_t < IsByte & & sizeof . . . ( RestDimensions ) = = 0 > >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( ) const noexcept - > span < U , ( Base : : bounds_type : : static_size ! = dynamic_range ? static_cast < ptrdiff_t > ( static_cast < size_t > ( Base : : bounds_type : : static_size ) / sizeof ( U ) ) : dynamic_range ) >
2015-11-03 22:17:11 -05:00
{
static_assert ( std : : is_standard_layout < U > : : value & & ( Base : : bounds_type : : static_size = = dynamic_range | | Base : : bounds_type : : static_size % static_cast < size_t > ( 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 ) ;
return { reinterpret_cast < U * > ( this - > data ( ) ) , this - > bytes ( ) / static_cast < size_type > ( sizeof ( U ) ) } ;
}
// section on linear space
template < std : : ptrdiff_t Count >
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , Count > first ( ) const noexcept
2015-11-03 22:17:11 -05: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
return { this - > data ( ) , Count } ;
}
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , dynamic_range > first ( size_type count ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( count < = this - > size ( ) ) ;
return { this - > data ( ) , count } ;
}
template < std : : ptrdiff_t Count >
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , Count > last ( ) const noexcept
2015-11-03 22:17:11 -05: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 ( ) ) ;
return { this - > data ( ) + this - > size ( ) - Count , Count } ;
}
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , dynamic_range > last ( size_type count ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( count < = this - > size ( ) ) ;
return { this - > data ( ) + this - > size ( ) - count , count } ;
}
template < std : : ptrdiff_t Offset , std : : ptrdiff_t Count >
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , Count > sub ( ) const noexcept
2015-11-03 22:17:11 -05: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 ( ) ) ) ;
return { this - > data ( ) + Offset , Count } ;
}
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , dynamic_range > sub ( size_type offset , size_type count = dynamic_range ) const noexcept
2015-11-03 22:17:11 -05: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 } ;
}
// size
constexpr size_type length ( ) const noexcept
{
return this - > size ( ) ;
}
constexpr size_type used_length ( ) const noexcept
{
return length ( ) ;
}
constexpr size_type bytes ( ) const noexcept
{
return sizeof ( value_type ) * this - > size ( ) ;
}
constexpr size_type used_bytes ( ) const noexcept
{
return bytes ( ) ;
}
// section
2015-11-04 15:42:27 -05:00
constexpr strided_span < ValueType , rank > section ( index_type origin , index_type extents ) const
2015-11-03 22:17:11 -05:00
{
size_type size = this - > bounds ( ) . total_size ( ) - this - > bounds ( ) . linearize ( origin ) ;
return { & this - > operator [ ] ( origin ) , size , strided_bounds < rank > { extents , details : : make_stride ( Base : : bounds ( ) ) } } ;
}
constexpr reference operator [ ] ( const index_type & idx ) const
{
return Base : : operator [ ] ( idx ) ;
}
template < bool Enabled = ( rank > 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
2015-11-04 15:42:27 -05:00
constexpr span < ValueType , RestDimensions . . . > operator [ ] ( size_type idx ) const
2015-11-03 22:17:11 -05:00
{
auto ret = Base : : operator [ ] ( idx ) ;
return { ret . data ( ) , ret . bounds ( ) } ;
}
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
} ;
2015-10-15 17:29:35 -04:00
template < typename T , std : : ptrdiff_t . . . Dimensions >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( T * const & ptr , dim < Dimensions > . . . args ) - > span < std : : remove_all_extents_t < T > , Dimensions . . . >
2015-08-20 21:09:14 -04:00
{
2015-11-04 15:42:27 -05:00
return { reinterpret_cast < std : : remove_all_extents_t < T > * > ( ptr ) , details : : static_as_span_helper < static_bounds < Dimensions . . . > > ( args . . . , details : : Sep { } ) } ;
2015-08-20 21:09:14 -04:00
}
template < typename T >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( T * arr , std : : ptrdiff_t len ) - > typename details : : ArrayViewArrayTraits < T , dynamic_range > : : type
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return { reinterpret_cast < std : : remove_all_extents_t < T > * > ( arr ) , len } ;
2015-08-20 21:09:14 -04:00
}
template < typename T , size_t N >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( T ( & arr ) [ N ] ) - > typename details : : ArrayViewArrayTraits < T , N > : : type
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return { arr } ;
2015-08-20 21:09:14 -04:00
}
template < typename T , size_t N >
2015-11-04 15:42:27 -05:00
constexpr span < const T , N > as_span ( const std : : array < T , N > & arr )
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return { arr } ;
2015-08-20 21:09:14 -04:00
}
template < typename T , size_t N >
2015-11-04 15:42:27 -05:00
constexpr span < const T , N > as_span ( const std : : array < T , N > & & ) = delete ;
2015-08-20 21:09:14 -04:00
template < typename T , size_t N >
2015-11-04 15:42:27 -05:00
constexpr span < T , N > as_span ( std : : array < T , N > & arr )
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return { arr } ;
2015-08-20 21:09:14 -04:00
}
template < typename T >
2015-11-04 15:42:27 -05:00
constexpr span < T , dynamic_range > as_span ( T * begin , T * end )
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return { begin , end } ;
2015-08-20 21:09:14 -04:00
}
template < typename Cont >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( Cont & arr ) - > std : : enable_if_t < ! details : : is_span < std : : decay_t < Cont > > : : value ,
span < std : : remove_reference_t < decltype ( arr . size ( ) , * arr . data ( ) ) > , dynamic_range > >
2015-08-20 21:09:14 -04:00
{
2015-10-23 22:49:17 -04:00
fail_fast_assert ( arr . size ( ) < PTRDIFF_MAX ) ;
2015-11-03 22:17:11 -05:00
return { arr . data ( ) , static_cast < std : : ptrdiff_t > ( arr . size ( ) ) } ;
2015-08-20 21:09:14 -04:00
}
template < typename Cont >
2015-11-04 15:42:27 -05:00
constexpr auto as_span ( Cont & & arr ) - > std : : enable_if_t < ! details : : is_span < std : : decay_t < Cont > > : : value ,
span < std : : remove_reference_t < decltype ( arr . size ( ) , * arr . data ( ) ) > , dynamic_range > > = delete ;
2015-08-20 21:09:14 -04:00
2015-10-15 17:29:35 -04:00
template < typename ValueType , size_t Rank >
2015-11-04 15:42:27 -05:00
class strided_span : public basic_span < ValueType , strided_bounds < Rank > >
2015-08-20 21:09:14 -04:00
{
2015-11-04 15:42:27 -05:00
using Base = basic_span < ValueType , strided_bounds < Rank > > ;
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
template < typename OtherValue , size_t OtherRank >
2015-11-04 15:42:27 -05:00
friend class strided_span ;
2015-10-15 17:29:35 -04:00
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
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 ;
using typename Base : : iterator ;
using typename Base : : const_iterator ;
using typename Base : : reference ;
// from static array of size N
template < size_type N >
2015-11-04 15:42:27 -05:00
strided_span ( value_type ( & values ) [ N ] , bounds_type bounds ) : Base ( values , std : : move ( bounds ) )
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( this - > bounds ( ) . total_size ( ) < = N , " Bounds cross data boundaries " ) ;
}
// from raw data
2015-11-04 15:42:27 -05:00
strided_span ( pointer ptr , size_type size , bounds_type bounds ) : Base ( ptr , std : : move ( bounds ) )
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( this - > bounds ( ) . total_size ( ) < = size , " Bounds cross data boundaries " ) ;
}
// from array view
template < std : : ptrdiff_t . . . Dimensions , typename Dummy = std : : enable_if < sizeof . . . ( Dimensions ) = = Rank > >
2015-11-04 15:42:27 -05:00
strided_span ( span < ValueType , Dimensions . . . > av , bounds_type bounds ) : Base ( av . data ( ) , std : : move ( bounds ) )
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( this - > bounds ( ) . total_size ( ) < = av . bounds ( ) . total_size ( ) , " Bounds cross data boundaries " ) ;
}
// convertible
template < typename OtherValueType ,
2015-11-04 15:42:27 -05:00
typename BaseType = basic_span < ValueType , strided_bounds < Rank > > ,
typename OtherBaseType = basic_span < OtherValueType , strided_bounds < Rank > > ,
2015-11-03 22:17:11 -05:00
typename Dummy = std : : enable_if_t < std : : is_convertible < OtherBaseType , BaseType > : : value >
>
2015-11-04 15:42:27 -05:00
constexpr strided_span ( const strided_span < OtherValueType , Rank > & av ) : Base ( static_cast < const typename strided_span < OtherValueType , Rank > : : Base & > ( av ) ) // static_cast is required
2015-10-15 17:29:35 -04:00
{ }
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
// convert from bytes
template < typename OtherValueType >
2015-11-04 15:42:27 -05:00
strided_span < typename std : : enable_if < std : : is_same < value_type , const byte > : : value , OtherValueType > : : type , rank > as_strided_span ( ) const
2015-11-03 22:17:11 -05: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 = static_cast < size_type > ( sizeof ( OtherValueType ) / sizeof ( value_type ) ) ;
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-11-04 15:42:27 -05:00
strided_span section ( index_type origin , index_type extents ) const
2015-11-03 22:17:11 -05:00
{
size_type size = this - > bounds ( ) . total_size ( ) - this - > bounds ( ) . linearize ( origin ) ;
return { & this - > operator [ ] ( origin ) , size , bounds_type { extents , details : : make_stride ( Base : : bounds ( ) ) } } ;
}
constexpr reference operator [ ] ( const index_type & idx ) const
{
return Base : : operator [ ] ( idx ) ;
}
template < bool Enabled = ( rank > 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
2015-11-04 15:42:27 -05:00
constexpr strided_span < value_type , rank - 1 > operator [ ] ( size_type idx ) const
2015-11-03 22:17:11 -05:00
{
auto ret = Base : : operator [ ] ( idx ) ;
return { ret . data ( ) , ret . bounds ( ) . total_size ( ) , ret . bounds ( ) } ;
}
2015-08-31 02:30:15 -04:00
private :
2015-11-03 22:17:11 -05:00
static index_type resize_extent ( const index_type & extent , std : : ptrdiff_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 " ) ;
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
index_type ret = extent ;
ret [ rank - 1 ] / = d ;
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
return ret ;
}
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
template < bool Enabled = ( rank = = 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
static index_type resize_stride ( const index_type & strides , std : : ptrdiff_t , void * = 0 )
{
fail_fast_assert ( strides [ rank - 1 ] = = 1 , " Only strided arrays with regular strides can be resized " ) ;
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
return strides ;
}
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
template < bool Enabled = ( rank > 1 ) , typename Dummy = std : : enable_if_t < Enabled > >
static index_type resize_stride ( const index_type & strides , std : : ptrdiff_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-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05: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
2015-11-03 22:17:11 -05:00
index_type ret = strides / d ;
ret [ rank - 1 ] = 1 ;
2015-08-31 02:30:15 -04:00
2015-11-03 22:17:11 -05:00
return ret ;
}
2015-08-20 21:09:14 -04:00
} ;
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
class contiguous_span_iterator : public std : : iterator < std : : random_access_iterator_tag , typename ArrayView : : value_type >
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
using Base = std : : iterator < std : : random_access_iterator_tag , typename ArrayView : : value_type > ;
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
using typename Base : : reference ;
using typename Base : : pointer ;
using typename Base : : difference_type ;
2015-10-15 17:29:35 -04:00
2015-08-20 21:09:14 -04:00
private :
2015-11-03 22:17:11 -05:00
template < typename ValueType , typename Bounds >
2015-11-04 15:42:27 -05:00
friend class basic_span ;
2015-10-15 17:29:35 -04:00
pointer m_pdata ;
2015-11-03 22:17:11 -05:00
const ArrayView * m_validator ;
void validateThis ( ) const
{
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-11-04 15:42:27 -05:00
contiguous_span_iterator ( const ArrayView * container , bool isbegin ) :
2015-11-03 22:17:11 -05:00
m_pdata ( isbegin ? container - > m_pdata : container - > m_pdata + container - > size ( ) ) , m_validator ( container ) { }
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
reference operator * ( ) const noexcept
{
validateThis ( ) ;
return * m_pdata ;
}
pointer operator - > ( ) const noexcept
{
validateThis ( ) ;
return m_pdata ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator & operator + + ( ) noexcept
2015-11-03 22:17:11 -05:00
{
+ + m_pdata ;
return * this ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator operator + + ( int ) noexcept
2015-11-03 22:17:11 -05:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator & operator - - ( ) noexcept
2015-11-03 22:17:11 -05:00
{
- - m_pdata ;
return * this ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator operator - - ( int ) noexcept
2015-11-03 22:17:11 -05:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator operator + ( difference_type n ) const noexcept
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
contiguous_span_iterator ret { * this } ;
2015-11-03 22:17:11 -05:00
return ret + = n ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator & operator + = ( difference_type n ) noexcept
2015-11-03 22:17:11 -05:00
{
m_pdata + = n ;
return * this ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator operator - ( difference_type n ) const noexcept
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
contiguous_span_iterator ret { * this } ;
2015-11-03 22:17:11 -05:00
return ret - = n ;
}
2015-11-04 15:42:27 -05:00
contiguous_span_iterator & operator - = ( difference_type n ) noexcept
2015-11-03 22:17:11 -05:00
{
return * this + = - n ;
}
2015-11-04 15:42:27 -05:00
difference_type operator - ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata - rhs . m_pdata ;
}
reference operator [ ] ( difference_type n ) const noexcept
{
return * ( * this + n ) ;
}
2015-11-04 15:42:27 -05:00
bool operator = = ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata = = rhs . m_pdata ;
}
2015-11-04 15:42:27 -05:00
bool operator ! = ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( * this = = rhs ) ;
}
2015-11-04 15:42:27 -05:00
bool operator < ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_validator = = rhs . m_validator ) ;
return m_pdata < rhs . m_pdata ;
}
2015-11-04 15:42:27 -05:00
bool operator < = ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( rhs < * this ) ;
}
2015-11-04 15:42:27 -05:00
bool operator > ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return rhs < * this ;
}
2015-11-04 15:42:27 -05:00
bool operator > = ( const contiguous_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( rhs > * this ) ;
}
2015-11-04 15:42:27 -05:00
void swap ( contiguous_span_iterator & rhs ) noexcept
2015-11-03 22:17:11 -05:00
{
std : : swap ( m_pdata , rhs . m_pdata ) ;
std : : swap ( m_validator , rhs . m_validator ) ;
}
2015-08-20 21:09:14 -04:00
} ;
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
contiguous_span_iterator < ArrayView > operator + ( typename contiguous_span_iterator < ArrayView > : : difference_type n , const contiguous_span_iterator < ArrayView > & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return rhs + n ;
2015-08-20 21:09:14 -04:00
}
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
class general_span_iterator : public std : : iterator < std : : random_access_iterator_tag , typename ArrayView : : value_type >
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
using Base = std : : iterator < std : : random_access_iterator_tag , typename ArrayView : : value_type > ;
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
using typename Base : : reference ;
using typename Base : : pointer ;
using typename Base : : difference_type ;
using typename Base : : value_type ;
2015-08-20 21:09:14 -04:00
private :
2015-11-03 22:17:11 -05:00
template < typename ValueType , typename Bounds >
2015-11-04 15:42:27 -05:00
friend class basic_span ;
2015-11-03 22:17:11 -05:00
2015-10-15 17:29:35 -04:00
const ArrayView * m_container ;
2015-11-03 22:17:11 -05:00
typename ArrayView : : bounds_type : : iterator m_itr ;
2015-11-04 15:42:27 -05:00
general_span_iterator ( const ArrayView * container , bool isbegin ) :
2015-11-03 22:17:11 -05:00
m_container ( container ) , m_itr ( isbegin ? m_container - > bounds ( ) . begin ( ) : m_container - > bounds ( ) . end ( ) )
{ }
2015-08-20 21:09:14 -04:00
public :
2015-11-03 22:17:11 -05:00
reference operator * ( ) noexcept
{
return ( * m_container ) [ * m_itr ] ;
}
pointer operator - > ( ) noexcept
{
return & ( * m_container ) [ * m_itr ] ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator & operator + + ( ) noexcept
2015-11-03 22:17:11 -05:00
{
+ + m_itr ;
return * this ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator operator + + ( int ) noexcept
2015-11-03 22:17:11 -05:00
{
auto ret = * this ;
+ + ( * this ) ;
return ret ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator & operator - - ( ) noexcept
2015-11-03 22:17:11 -05:00
{
- - m_itr ;
return * this ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator operator - - ( int ) noexcept
2015-11-03 22:17:11 -05:00
{
auto ret = * this ;
- - ( * this ) ;
return ret ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator operator + ( difference_type n ) const noexcept
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
general_span_iterator ret { * this } ;
2015-11-03 22:17:11 -05:00
return ret + = n ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator & operator + = ( difference_type n ) noexcept
2015-11-03 22:17:11 -05:00
{
m_itr + = n ;
return * this ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator operator - ( difference_type n ) const noexcept
2015-11-03 22:17:11 -05:00
{
2015-11-04 15:42:27 -05:00
general_span_iterator ret { * this } ;
2015-11-03 22:17:11 -05:00
return ret - = n ;
}
2015-11-04 15:42:27 -05:00
general_span_iterator & operator - = ( difference_type n ) noexcept
2015-11-03 22:17:11 -05:00
{
return * this + = - n ;
}
2015-11-04 15:42:27 -05:00
difference_type operator - ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr - rhs . m_itr ;
}
value_type operator [ ] ( difference_type n ) const noexcept
{
return ( * m_container ) [ m_itr [ n ] ] ; ;
}
2015-11-04 15:42:27 -05:00
bool operator = = ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr = = rhs . m_itr ;
}
2015-11-04 15:42:27 -05:00
bool operator ! = ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( * this = = rhs ) ;
}
2015-11-04 15:42:27 -05:00
bool operator < ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
fail_fast_assert ( m_container = = rhs . m_container ) ;
return m_itr < rhs . m_itr ;
}
2015-11-04 15:42:27 -05:00
bool operator < = ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( rhs < * this ) ;
}
2015-11-04 15:42:27 -05:00
bool operator > ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return rhs < * this ;
}
2015-11-04 15:42:27 -05:00
bool operator > = ( const general_span_iterator & rhs ) const noexcept
2015-11-03 22:17:11 -05:00
{
return ! ( rhs > * this ) ;
}
2015-11-04 15:42:27 -05:00
void swap ( general_span_iterator & rhs ) noexcept
2015-11-03 22:17:11 -05:00
{
std : : swap ( m_itr , rhs . m_itr ) ;
std : : swap ( m_container , rhs . m_container ) ;
}
2015-08-20 21:09:14 -04:00
} ;
template < typename ArrayView >
2015-11-04 15:42:27 -05:00
general_span_iterator < ArrayView > operator + ( typename general_span_iterator < ArrayView > : : difference_type n , const general_span_iterator < ArrayView > & rhs ) noexcept
2015-08-20 21:09:14 -04:00
{
2015-11-03 22:17:11 -05:00
return rhs + n ;
2015-08-20 21:09:14 -04:00
}
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-11-03 21:56:55 -05:00
# undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
# pragma pop_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
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
2015-11-04 15:42:27 -05:00
# endif // GSL_SPAN_H