2015-08-20 18:09:14 -07:00
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
2015-09-24 18:08:34 -07:00
#ifndef GSL_ARRAY_VIEW_H
#define GSL_ARRAY_VIEW_H
2015-08-20 18:09:14 -07:00
#include <new>
#include <stdexcept>
#include <cstddef>
#include <cstdint>
#include <limits>
2015-10-15 13:19:24 -07:00
#include <numeric>
2015-08-20 18:09:14 -07:00
#include <type_traits>
#include <utility>
#include <array>
#include <iterator>
2015-09-25 17:01:29 -07:00
#include <algorithm>
2015-10-15 16:48:38 -07:00
#include <functional>
2015-08-20 18:09:14 -07:00
#include "fail_fast.h"
2015-09-30 21:54:08 -07:00
#ifdef _MSC_VER
// No MSVC does constexpr fully yet
2015-09-28 05:10:44 -07:00
#pragma push_macro("constexpr")
#define constexpr /* nothing */
2015-09-30 21:54:08 -07:00
// VS 2013 workarounds
#if _MSC_VER <= 1800
2015-11-03 18:56:55 -08:00
#pragma push_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
#define GSL_MSVC_HAS_VARIADIC_CTOR_BUG
2015-09-30 21:54:08 -07:00
// noexcept is not understood
#ifndef GSL_THROWS_FOR_TESTING
#define noexcept /* nothing */
2015-08-20 18:09:14 -07:00
#endif
2015-09-30 21:54:08 -07:00
// turn off some misguided warnings
2015-09-14 15:11:07 -07:00
#pragma warning(push)
#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
2015-09-30 21:54:08 -07:00
2015-09-14 15:11:07 -07:00
#endif // _MSC_VER <= 1800
2015-09-30 21:54:08 -07: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 16:41:37 -07:00
namespace gsl {
2015-08-20 18:09:14 -07:00
/*
** begin definitions of index and bounds
*/
namespace details
{
2015-11-03 19:17:11 -08:00
template < typename SizeType >
struct SizeTypeTraits
{
static const SizeType max_value = std :: numeric_limits < SizeType >:: max ();
};
2015-10-16 17:40:57 -07:00
2015-11-03 19:17:11 -08:00
template < typename ... Ts >
class are_integral : public std :: integral_constant < bool , true > {};
2015-10-16 17:40:57 -07:00
2015-11-03 19:17:11 -08: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 18:09:14 -07:00
}
2015-10-15 14:29:35 -07:00
template < size_t Rank >
2015-10-05 12:34:23 -07:00
class index final
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
static_assert ( Rank > 0 , "Rank must be greater than 0!" );
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
template < size_t OtherRank >
friend class index ;
2015-10-05 12:34:23 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
static const size_t rank = Rank ;
using value_type = std :: ptrdiff_t ;
2015-10-23 19:49:17 -07:00
using size_type = value_type ;
2015-11-03 19:17:11 -08: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 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr index () noexcept
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr index ( const value_type ( & values )[ Rank ]) noexcept
{
std :: copy ( values , values + Rank , elems );
}
2015-08-20 18:09:14 -07:00
2015-11-03 18:56:55 -08:00
#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
2015-11-03 19:17:11 -08:00
template < typename T , typename ... Ts ,
2015-11-03 18:56:55 -08: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 19:17:11 -08:00
template < typename ... Ts ,
2015-11-03 18:56:55 -08:00
typename = std :: enable_if_t < ( sizeof ...( Ts ) == Rank ) && details :: are_integral < Ts ... >:: value >>
2015-11-03 19:17:11 -08:00
constexpr index ( Ts ... ds ) noexcept : elems { static_cast < value_type > ( ds )... }
2015-11-03 18:56:55 -08:00
{}
#endif
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index ( const index & other ) noexcept = default ;
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index & operator = ( const index & rhs ) noexcept = default ;
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
// 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 ];
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
// 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 ];
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator == ( const index & rhs ) const noexcept
{
return std :: equal ( elems , elems + rank , rhs . elems );
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator != ( const index & rhs ) const noexcept
{
return ! ( this == rhs );
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator + () const noexcept
{
return * this ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator - () const noexcept
{
index ret = * this ;
std :: transform ( ret , ret + rank , ret , std :: negate < value_type > {});
return ret ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator + ( const index & rhs ) const noexcept
{
index ret = * this ;
ret += rhs ;
return ret ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator - ( const index & rhs ) const noexcept
{
index ret = * this ;
ret -= rhs ;
return ret ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index & operator += ( const index & rhs ) noexcept
{
std :: transform ( elems , elems + rank , rhs . elems , elems , std :: plus < value_type > {});
return * this ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index & operator -= ( const index & rhs ) noexcept
{
std :: transform ( elems , elems + rank , rhs . elems , elems , std :: minus < value_type > {});
return * this ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator * ( value_type v ) const noexcept
{
index ret = * this ;
ret *= v ;
return ret ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
constexpr index operator / ( value_type v ) const noexcept
{
index ret = * this ;
ret /= v ;
return ret ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
friend constexpr index operator * ( value_type v , const index & rhs ) noexcept
{
return rhs * v ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
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 ;
}
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
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-05 21:04:56 -07:00
2015-10-05 12:34:23 -07:00
private :
2015-11-03 19:17:11 -08:00
value_type elems [ Rank ] = {};
2015-08-20 18:09:14 -07:00
};
#ifndef _MSC_VER
struct static_bounds_dynamic_range_t
{
2015-11-03 19:17:11 -08: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 );
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
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 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
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 14:29:35 -07:00
2015-08-20 18:09:14 -07: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 19:17:11 -08:00
return right == left ;
2015-08-20 18:09:14 -07: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 19:17:11 -08:00
return right != left ;
2015-08-20 18:09:14 -07:00
}
constexpr static_bounds_dynamic_range_t dynamic_range {};
#else
2015-10-15 14:29:35 -07:00
const std :: ptrdiff_t dynamic_range = - 1 ;
2015-08-20 18:09:14 -07:00
#endif
struct generalized_mapping_tag {};
struct contiguous_mapping_tag : generalized_mapping_tag {};
namespace details
{
2015-11-03 19:17:11 -08:00
template < std :: ptrdiff_t Left , std :: ptrdiff_t Right >
struct LessThan
{
static const bool value = Left < Right ;
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08: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-08-20 18:09:14 -07:00
2015-10-23 19:49:17 -07:00
// TODO : following signature is for work around VS bug
template < typename OtherRange >
2015-11-03 19:17:11 -08:00
BoundsRanges ( const OtherRange & , bool /* firstLevel */ )
2015-10-23 19:49:17 -07:00
{}
2015-11-03 19:17:11 -08:00
BoundsRanges ( const BoundsRanges & ) = default ;
BoundsRanges ( const std :: ptrdiff_t * const ) { }
BoundsRanges () = default ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename T , size_t Dim >
void serialize ( T & ) const
2015-10-15 14:29:35 -07:00
{}
2015-11-03 19:17:11 -08:00
template < typename T , size_t Dim >
size_type linearize ( const T & ) const
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return 0 ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename T , size_t Dim >
bool contains ( const T & ) const
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return 0 ;
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
size_type totalSize () const noexcept
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return TotalSize ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
bool operator == ( const BoundsRanges & ) const noexcept
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return true ;
}
};
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
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
{
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 14:29:35 -07:00
{
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
{
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return m_bound ;
}
2015-10-15 14:29:35 -07:00
size_type elementNum () const noexcept
{
2015-11-03 19:17:11 -08:00
return totalSize () / this -> Base :: totalSize ();
}
2015-10-15 14:29:35 -07:00
size_type elementNum ( size_t dim ) const noexcept
{
2015-11-03 19:17:11 -08:00
if ( dim > 0 )
return this -> Base :: elementNum ( dim - 1 );
else
return elementNum ();
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
bool operator == ( const BoundsRanges & rhs ) const noexcept
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return m_bound == rhs . m_bound && static_cast < const Base &> ( * this ) == static_cast < const Base &> ( rhs );
}
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 )
{
fail_fast_assert (( firstLevel && totalSize () <= other . totalSize ()) || totalSize () == other . totalSize ());
}
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 14:29:35 -07:00
{
2015-11-03 19:17:11 -08: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 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename T , size_t Dim = 0 >
2015-10-15 14:29:35 -07:00
size_type contains ( const T & arr ) const
{
2015-11-03 19:17:11 -08: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 ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
size_type totalSize () const noexcept
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
return CurrentRange * this -> Base :: totalSize ();
}
2015-08-20 18:09:14 -07:00
2015-10-15 14:29:35 -07:00
size_type elementNum () const noexcept
{
2015-11-03 19:17:11 -08:00
return CurrentRange ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
size_type elementNum ( size_t dim ) const noexcept
2015-10-15 14:29:35 -07:00
{
2015-11-03 19:17:11 -08:00
if ( dim > 0 )
return this -> Base :: elementNum ( dim - 1 );
else
return elementNum ();
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
bool operator == ( const BoundsRanges & rhs ) const noexcept
{
return static_cast < const Base &> ( * this ) == static_cast < const Base &> ( rhs );
}
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename SourceType , typename TargetType , size_t Rank >
struct BoundsRangeConvertible2 ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 ) > ()))
{};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename SourceType , typename TargetType >
struct BoundsRangeConvertible2 < SourceType , TargetType , 0 > : std :: true_type {};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 {};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 > ());
}
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename TypeChain >
TypeListIndexer < TypeChain > createTypeListIndexer ( const TypeChain & obj )
{
return TypeListIndexer < TypeChain > ( obj );
}
2015-10-14 10:46:22 -07:00
2015-11-03 19:17:11 -08: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 )
{
ret [ i ] = other [ i + 1 ];
}
return ret ;
}
2015-08-20 18:09:14 -07:00
}
template < typename IndexType >
class bounds_iterator ;
2015-10-15 14:29:35 -07:00
template < std :: ptrdiff_t ... Ranges >
class static_bounds
{
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
static_bounds ( const details :: BoundsRanges < Ranges ... >& ) {
}
2015-08-20 18:09:14 -07:00
};
2015-10-15 14:29:35 -07:00
template < std :: ptrdiff_t FirstRange , std :: ptrdiff_t ... RestRanges >
class static_bounds < FirstRange , RestRanges ... >
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
using MyRanges = details :: BoundsRanges < FirstRange , RestRanges ... > ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
MyRanges m_ranges ;
constexpr static_bounds ( const MyRanges & range ) : m_ranges ( range )
2015-10-15 14:29:35 -07:00
{}
2015-11-03 19:17:11 -08:00
template < std :: ptrdiff_t ... OtherRanges >
friend class static_bounds ;
2015-10-15 14:29:35 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
using size_type = std :: ptrdiff_t ;
using index_type = index < rank > ;
2015-10-28 16:53:53 -07: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 19:17:11 -08:00
using sliced_type = static_bounds < RestRanges ... > ;
using mapping_type = contiguous_mapping_tag ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
constexpr static_bounds ( const static_bounds < Ranges ... >& other ) : m_ranges ( other . m_ranges )
{}
2015-10-28 16:53:53 -07:00
2015-11-03 19:17:11 -08: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 ;
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr static_bounds & operator = ( const static_bounds & otherBounds )
{
new ( & m_ranges ) MyRanges ( otherBounds . m_ranges );
return * this ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr sliced_type slice () const noexcept
{
return sliced_type { static_cast < const details :: BoundsRanges < RestRanges ... > &> ( m_ranges )};
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr size_type stride () const noexcept
{
return rank > 1 ? slice (). size () : 1 ;
}
constexpr size_type size () const noexcept
{
return m_ranges . totalSize ();
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
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 18:09:14 -07:00
};
2015-10-15 14:29:35 -07:00
template < size_t Rank >
2015-10-23 19:49:17 -07:00
class strided_bounds
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
template < size_t OtherRank >
friend class strided_bounds ;
2015-08-30 23:30:15 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
static const size_t rank = Rank ;
2015-10-23 19:49:17 -07:00
using value_type = std :: ptrdiff_t ;
2015-11-03 19:17:11 -08: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 16:53:53 -07: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 19:17:11 -08: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 16:38:53 -07:00
2015-11-03 19:17:11 -08:00
constexpr strided_bounds ( const strided_bounds & ) noexcept = default ;
2015-08-20 18:09:14 -07:00
2015-10-15 14:29:35 -07:00
constexpr strided_bounds ( const value_type ( & values )[ rank ], index_type strides )
2015-10-23 19:49:17 -07:00
: m_extents ( values ), m_strides ( std :: move ( strides ))
2015-10-15 14:29:35 -07:00
{}
2015-11-03 19:17:11 -08:00
constexpr strided_bounds ( const index_type & extents , const index_type & strides ) noexcept
: m_extents ( extents ), m_strides ( strides )
{}
2015-10-15 16:38:53 -07:00
2015-11-03 19:17:11 -08:00
constexpr index_type strides () const noexcept
{
return m_strides ;
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
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 14:29:35 -07:00
constexpr size_type size () const noexcept
2015-11-03 19:17:11 -08:00
{
size_type ret = 1 ;
for ( size_t i = 0 ; i < rank ; ++ i )
{
ret *= m_extents [ i ];
}
return ret ;
}
2015-10-15 14:29:35 -07:00
constexpr bool contains ( const index_type & idx ) const noexcept
2015-11-03 19:17:11 -08:00
{
for ( size_t i = 0 ; i < rank ; ++ i )
{
if ( idx [ i ] < 0 || idx [ i ] >= m_extents [ i ])
return false ;
}
return true ;
}
2015-10-15 16:38:53 -07:00
2015-11-03 19:17:11 -08:00
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 14:29:35 -07:00
constexpr size_type stride () const noexcept
2015-11-03 19:17:11 -08:00
{
return m_strides [ 0 ];
}
2015-10-15 14:29:35 -07:00
template < bool Enabled = ( rank > 1 ), typename Ret = std :: enable_if_t < Enabled , sliced_type >>
2015-11-03 19:17:11 -08:00
constexpr sliced_type slice () const
{
return { details :: shift_left ( m_extents ), details :: shift_left ( m_strides ) };
}
2015-10-15 14:29:35 -07:00
template < size_t Dim = 0 >
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
constexpr index_type index_bounds () const noexcept
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
2015-08-30 23:30:15 -07:00
private :
2015-11-03 19:17:11 -08:00
index_type m_extents ;
index_type m_strides ;
2015-08-20 18:09:14 -07:00
};
template < typename T >
struct is_bounds : std :: integral_constant < bool , false > {};
2015-10-15 14:29:35 -07: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 18:09:14 -07:00
template < typename IndexType >
2015-10-16 12:15:22 -07:00
class bounds_iterator : public std :: iterator < std :: random_access_iterator_tag , IndexType >
2015-08-20 18:09:14 -07:00
{
private :
2015-11-03 19:17:11 -08:00
using Base = std :: iterator < std :: random_access_iterator_tag , IndexType > ;
2015-10-16 12:15:22 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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" );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr reference operator * () const noexcept
{
return curr ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr pointer operator -> () const noexcept
{
return & curr ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
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 ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bounds_iterator operator ++ ( int ) noexcept
{
auto ret = * this ;
++ ( * this );
return ret ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
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 ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bounds_iterator operator -- ( int ) noexcept
{
auto ret = * this ;
-- ( * this );
return ret ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bounds_iterator operator + ( difference_type n ) const noexcept
{
bounds_iterator ret { * this };
return ret += n ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
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 ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bounds_iterator operator - ( difference_type n ) const noexcept
{
bounds_iterator ret { * this };
return ret -= n ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bounds_iterator & operator -= ( difference_type n ) noexcept
{
return * this += - n ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr difference_type operator - ( const bounds_iterator & rhs ) const noexcept
{
return linearize ( curr ) - linearize ( rhs . curr );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr value_type operator []( difference_type n ) const noexcept
{
return * ( * this + n );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator == ( const bounds_iterator & rhs ) const noexcept
{
return curr == rhs . curr ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator != ( const bounds_iterator & rhs ) const noexcept
{
return ! ( * this == rhs );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator < ( const bounds_iterator & rhs ) const noexcept
{
return less ( curr , rhs . curr );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator <= ( const bounds_iterator & rhs ) const noexcept
{
return ! ( rhs < * this );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator > ( const bounds_iterator & rhs ) const noexcept
{
return rhs < * this ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
constexpr bool operator >= ( const bounds_iterator & rhs ) const noexcept
{
return ! ( rhs > * this );
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
void swap ( bounds_iterator & rhs ) noexcept
{
std :: swap ( boundary , rhs . boundary );
std :: swap ( curr , rhs . curr );
}
2015-08-20 18:09:14 -07:00
private :
2015-11-03 19:17:11 -08: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 ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
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 ;
}
2015-10-16 12:15:22 -07:00
2015-11-03 19:17:11 -08:00
value_type boundary ;
std :: remove_const_t < value_type > curr ;
2015-08-20 18:09:14 -07:00
};
template < typename IndexType >
2015-09-30 21:54:08 -07:00
bounds_iterator < IndexType > operator + ( typename bounds_iterator < IndexType >:: difference_type n , const bounds_iterator < IndexType >& rhs ) noexcept
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return rhs + n ;
2015-08-20 18:09:14 -07:00
}
2015-10-15 14:29:35 -07:00
//
// begin definitions of basic_array_view
//
2015-08-20 18:09:14 -07:00
namespace details
{
2015-11-03 19:17:11 -08: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 ();
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// 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 ] = {};
2015-10-05 12:34:23 -07:00
2015-11-03 19:17:11 -08:00
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 };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08: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 ());
}
2015-08-20 18:09:14 -07:00
} // 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-11-03 19:17:11 -08: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 & ;
using iterator = std :: conditional_t < std :: is_same < typename BoundsType :: mapping_type , contiguous_mapping_tag >:: value , contiguous_array_view_iterator < basic_array_view > , general_array_view_iterator < basic_array_view >> ;
using const_iterator = std :: conditional_t < std :: is_same < typename BoundsType :: mapping_type , contiguous_mapping_tag >:: value , contiguous_array_view_iterator < basic_array_view < const_value_type , BoundsType >> , general_array_view_iterator < basic_array_view < const_value_type , BoundsType >>> ;
using reverse_iterator = std :: reverse_iterator < iterator > ;
using const_reverse_iterator = std :: reverse_iterator < const_iterator > ;
using sliced_type = std :: conditional_t < rank == 1 , value_type , basic_array_view < value_type , typename BoundsType :: sliced_type >> ;
2015-08-20 18:09:14 -07:00
private :
2015-11-03 19:17:11 -08:00
pointer m_pdata ;
bounds_type m_bounds ;
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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 ();
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
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 ()};
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr operator bool () const noexcept
{
return m_pdata != nullptr ;
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr iterator begin () const
{
return iterator { this , true };
}
constexpr iterator end () const
{
return iterator { this , false };
}
constexpr const_iterator cbegin () const
{
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > *> ( this ), true };
}
constexpr const_iterator cend () const
{
return const_iterator { reinterpret_cast < const basic_array_view < const value_type , bounds_type > *> ( this ), false };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08: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 ()};
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator == ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return m_bounds . size () == other . m_bounds . size () &&
( m_pdata == other . m_pdata || std :: equal ( this -> begin (), this -> end (), other . begin ()));
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator != ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return ! ( * this == other );
}
2015-08-27 18:13:49 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator < ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return std :: lexicographical_compare ( this -> begin (), this -> end (), other . begin (), other . end ());
}
2015-08-27 18:13:49 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator <= ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return ! ( other < * this );
}
2015-08-27 18:13:49 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator > ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return ( other < * this );
}
2015-08-27 18:13:49 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValueType , typename OtherBoundsType , typename Dummy = std :: enable_if_t < std :: is_same < std :: remove_cv_t < value_type > , std :: remove_cv_t < OtherValueType >>:: value >>
constexpr bool operator >= ( const basic_array_view < OtherValueType , OtherBoundsType > & other ) const noexcept
{
return ! ( * this < other );
}
2015-08-27 18:13:49 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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 >>
constexpr basic_array_view ( const basic_array_view < OtherValueType , OtherBounds > & other ) noexcept
: m_pdata ( other . m_pdata ), m_bounds ( other . m_bounds )
{
}
2015-08-20 18:09:14 -07:00
protected :
2015-11-03 19:17:11 -08:00
constexpr basic_array_view ( pointer data , bounds_type bound ) noexcept
: m_pdata ( data )
, m_bounds ( std :: move ( bound ))
{
fail_fast_assert (( m_bounds . size () > 0 && data != nullptr ) || m_bounds . size () == 0 );
}
template < typename T >
constexpr basic_array_view ( T * data , std :: enable_if_t < std :: is_same < value_type , std :: remove_all_extents_t < T >>:: value , bounds_type > bound ) noexcept
: m_pdata ( reinterpret_cast < pointer > ( data ))
, m_bounds ( std :: move ( bound ))
{
fail_fast_assert (( m_bounds . size () > 0 && data != nullptr ) || m_bounds . size () == 0 );
}
template < typename DestBounds >
constexpr basic_array_view < value_type , DestBounds > as_array_view ( const DestBounds & bounds )
{
details :: verifyBoundsReshape ( m_bounds , bounds );
return { m_pdata , bounds };
}
2015-08-20 18:09:14 -07:00
private :
2015-11-03 19:17:11 -08:00
friend iterator ;
friend const_iterator ;
template < typename ValueType2 , typename BoundsType2 >
friend class basic_array_view ;
2015-08-20 18:09:14 -07:00
};
2015-10-15 14:29:35 -07:00
template < std :: ptrdiff_t DimSize = dynamic_range >
2015-08-20 18:09:14 -07:00
struct dim
{
2015-11-03 19:17:11 -08:00
static const std :: ptrdiff_t value = DimSize ;
2015-08-20 18:09:14 -07:00
};
template <>
struct dim < dynamic_range >
{
2015-11-03 19:17:11 -08:00
static const std :: ptrdiff_t value = dynamic_range ;
const std :: ptrdiff_t dvalue ;
dim ( std :: ptrdiff_t size ) : dvalue ( size ) {}
2015-08-20 18:09:14 -07:00
};
2015-10-15 14:29:35 -07:00
template < typename ValueType , std :: ptrdiff_t FirstDimension = dynamic_range , std :: ptrdiff_t ... RestDimensions >
2015-08-20 18:09:14 -07:00
class array_view ;
2015-10-15 14:29:35 -07:00
template < typename ValueType , size_t Rank >
2015-08-20 18:09:14 -07:00
class strided_array_view ;
namespace details
{
2015-11-03 19:17:11 -08:00
template < typename T , typename = std :: true_type >
struct ArrayViewTypeTraits
{
using value_type = T ;
using size_type = size_t ;
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 ;
};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename T , std :: ptrdiff_t ... Ranks >
struct ArrayViewArrayTraits {
using type = array_view < T , Ranks ... > ;
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 > {};
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
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 >
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 );
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename ... Dimensions >
struct static_as_array_view_static_bounds_helper
{
using type = static_bounds < ( Dimensions :: value )... > ;
};
2015-08-20 18:09:14 -07:00
2015-10-15 14:29:35 -07:00
template < typename T >
2015-11-03 19:17:11 -08:00
struct is_array_view_oracle : std :: false_type
{};
template < typename ValueType , std :: ptrdiff_t FirstDimension , std :: ptrdiff_t ... RestDimensions >
struct is_array_view_oracle < array_view < ValueType , FirstDimension , RestDimensions ... >> : std :: true_type
{};
template < typename ValueType , std :: ptrdiff_t Rank >
struct is_array_view_oracle < strided_array_view < ValueType , Rank >> : std :: true_type
{};
template < typename T >
struct is_array_view : is_array_view_oracle < std :: remove_cv_t < T >>
{};
2015-08-20 18:09:14 -07:00
}
2015-10-15 14:29:35 -07:00
template < typename ValueType , std :: ptrdiff_t FirstDimension , std :: ptrdiff_t ... RestDimensions >
class array_view : public basic_array_view < ValueType , static_bounds < FirstDimension , RestDimensions ... >>
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
template < typename ValueType2 , std :: ptrdiff_t FirstDimension2 ,
std :: ptrdiff_t ... RestDimensions2 >
friend class array_view ;
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
using Base = basic_array_view < ValueType , static_bounds < FirstDimension , RestDimensions ... >> ;
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
// basic
2015-10-15 14:29:35 -07:00
constexpr array_view ( pointer ptr , size_type size ) : Base ( ptr , bounds_type { size })
{}
constexpr array_view ( pointer ptr , bounds_type bounds ) : Base ( ptr , std :: move ( bounds ))
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view ( std :: nullptr_t ) : Base ( nullptr , bounds_type {})
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view ( std :: nullptr_t , size_type size ) : Base ( nullptr , bounds_type {})
{
fail_fast_assert ( size == 0 );
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// default
template < std :: ptrdiff_t DynamicRank = bounds_type :: dynamic_rank , typename = std :: enable_if_t < DynamicRank != 0 >>
constexpr array_view () : Base ( nullptr , bounds_type ())
{}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08: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 19:49:17 -07:00
/*typename Dummy = std::enable_if_t<std::is_convertible<Helper::value_type (*)[], typename Base::value_type (*)[]>::value>*/ >
2015-11-03 19:17:11 -08:00
constexpr array_view ( T * const & data , size_type size ) : Base ( data , typename Helper :: bounds_type { size })
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// from n-dimensions static array
template < typename T , size_t N , typename Helper = details :: ArrayViewArrayTraits < T , N > ,
2015-11-04 02:11:49 +00:00
typename = std :: enable_if_t < std :: is_convertible < typename Helper :: value_type ( * )[], typename Base :: value_type ( * )[] >:: value >>
2015-11-03 19:17:11 -08:00
constexpr array_view ( T ( & arr )[ N ]) : Base ( arr , typename Helper :: bounds_type ())
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
>
2015-11-04 02:11:49 +00:00
constexpr array_view ( T ( & arr )[ N ], size_type size ) : Base ( arr , typename Helper :: bounds_type { size })
2015-11-03 19:17:11 -08:00
{
fail_fast_assert ( size <= N );
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// from std array
template < size_t N ,
2015-10-15 14:29:35 -07:00
typename Dummy = std :: enable_if_t < std :: is_convertible < static_bounds < N > , typename Base :: bounds_type >:: value >
>
2015-11-03 19:17:11 -08:00
constexpr array_view ( std :: array < std :: remove_const_t < value_type > , N > & arr ) : Base ( arr . data (), static_bounds < N > ())
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < size_t N ,
2015-10-15 14:29:35 -07: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-03 19:17:11 -08:00
constexpr array_view ( const std :: array < std :: remove_const_t < value_type > , N > & arr ) : Base ( arr . data (), static_bounds < N > ())
{}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08: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 14:29:35 -07:00
> // remove literal 0 case
2015-11-03 19:17:11 -08:00
constexpr array_view ( pointer begin , Ptr end ) : Base ( begin , details :: newBoundsHelper < typename Base :: bounds_type > ( static_cast < pointer > ( end ) - begin ))
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// from containers. It must has .size() and .data() two function signatures
template < typename Cont , typename DataType = typename Cont :: value_type ,
typename Dummy = std :: enable_if_t <! details :: is_array_view < Cont >:: value
&& 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 >
>
constexpr array_view ( Cont & cont ) : Base ( static_cast < pointer > ( cont . data ()), details :: newBoundsHelper < typename Base :: bounds_type > ( cont . size ()))
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view ( const array_view & ) = default ;
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
// convertible
template < typename OtherValueType , std :: ptrdiff_t ... OtherDimensions ,
typename BaseType = basic_array_view < ValueType , static_bounds < FirstDimension , RestDimensions ... >> ,
typename OtherBaseType = basic_array_view < OtherValueType , static_bounds < OtherDimensions ... >> ,
typename Dummy = std :: enable_if_t < std :: is_convertible < OtherBaseType , BaseType >:: value >
>
constexpr array_view ( const array_view < OtherValueType , OtherDimensions ... > & av )
2015-10-15 14:29:35 -07:00
: Base ( static_cast < const typename array_view < OtherValueType , OtherDimensions ... >:: Base &> ( av ))
{}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// reshape
2015-11-03 12:44:09 -08: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 ) >>
constexpr array_view < ValueType , Dimensions2 :: value ... > as_array_view ( Dimensions2 ... dims )
2015-11-03 19:17:11 -08:00
{
using BoundsType = typename array_view < ValueType , ( Dimensions2 :: value )... >:: bounds_type ;
auto tobounds = details :: static_as_array_view_helper < BoundsType > ( dims ..., details :: Sep {});
details :: verifyBoundsReshape ( this -> bounds (), tobounds );
return { this -> data (), tobounds };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// to bytes array
template < bool Enabled = std :: is_standard_layout < std :: decay_t < ValueType >>:: value >
auto as_bytes () const noexcept -> array_view < const byte >
{
static_assert ( Enabled , "The value_type of array_view must be standarded layout" );
return { reinterpret_cast < const byte *> ( this -> data ()), this -> bytes () };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < bool Enabled = std :: is_standard_layout < std :: decay_t < ValueType >>:: value >
auto as_writeable_bytes () const noexcept -> array_view < byte >
{
static_assert ( Enabled , "The value_type of array_view must be standarded layout" );
return { reinterpret_cast < byte *> ( this -> data ()), this -> bytes () };
}
2015-08-20 18:09:14 -07:00
2015-10-15 14:29:35 -07:00
// from bytes array
2015-11-03 19:17:11 -08:00
template < typename U , bool IsByte = std :: is_same < value_type , const byte >:: value , typename = std :: enable_if_t < IsByte && sizeof ...( RestDimensions ) == 0 >>
constexpr auto as_array_view () const noexcept -> array_view < 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 ) >
{
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 )) };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < typename U , bool IsByte = std :: is_same < value_type , byte >:: value , typename = std :: enable_if_t < IsByte && sizeof ...( RestDimensions ) == 0 >>
constexpr auto as_array_view () const noexcept -> array_view < 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 ) >
{
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 )) };
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
// section on linear space
template < std :: ptrdiff_t Count >
constexpr array_view < ValueType , Count > first () const noexcept
{
static_assert ( bounds_type :: static_size == dynamic_range || Count <= bounds_type :: static_size , "Index is out of bound" );
fail_fast_assert ( bounds_type :: static_size != dynamic_range || Count <= this -> size ()); // ensures we only check condition when needed
return { this -> data (), Count };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view < ValueType , dynamic_range > first ( size_type count ) const noexcept
{
fail_fast_assert ( count <= this -> size ());
return { this -> data (), count };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < std :: ptrdiff_t Count >
constexpr array_view < ValueType , Count > last () const noexcept
{
static_assert ( bounds_type :: static_size == dynamic_range || Count <= bounds_type :: static_size , "Index is out of bound" );
fail_fast_assert ( bounds_type :: static_size != dynamic_range || Count <= this -> size ());
return { this -> data () + this -> size () - Count , Count };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view < ValueType , dynamic_range > last ( size_type count ) const noexcept
{
fail_fast_assert ( count <= this -> size ());
return { this -> data () + this -> size () - count , count };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
template < std :: ptrdiff_t Offset , std :: ptrdiff_t Count >
constexpr array_view < ValueType , Count > sub () const noexcept
{
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-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
constexpr array_view < ValueType , dynamic_range > sub ( size_type offset , size_type count = dynamic_range ) const noexcept
{
fail_fast_assert (( offset == 0 || offset <= this -> size ()) && ( count == dynamic_range || ( offset + count ) <= this -> size ()));
return { this -> data () + offset , count == dynamic_range ? this -> length () - offset : count };
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// size
constexpr size_type length () const noexcept
{
return this -> size ();
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
constexpr size_type used_length () const noexcept
{
return length ();
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
constexpr size_type bytes () const noexcept
{
return sizeof ( value_type ) * this -> size ();
}
2015-10-15 14:29:35 -07:00
2015-11-03 19:17:11 -08:00
constexpr size_type used_bytes () const noexcept
{
return bytes ();
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// section
constexpr strided_array_view < ValueType , rank > section ( index_type origin , index_type extents ) const
{
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 >>
constexpr array_view < ValueType , RestDimensions ... > operator []( size_type idx ) const
{
auto ret = Base :: operator []( idx );
return { ret . data (), ret . bounds () };
}
2015-08-27 18:13:49 -07:00
2015-11-03 19:17:11 -08:00
using Base :: operator == ;
using Base :: operator != ;
using Base :: operator < ;
using Base :: operator <= ;
using Base :: operator > ;
using Base :: operator >= ;
2015-08-20 18:09:14 -07:00
};
2015-10-15 14:29:35 -07:00
template < typename T , std :: ptrdiff_t ... Dimensions >
constexpr auto as_array_view ( T * const & ptr , dim < Dimensions > ... args ) -> array_view < std :: remove_all_extents_t < T > , Dimensions ... >
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { reinterpret_cast < std :: remove_all_extents_t < T >*> ( ptr ), details :: static_as_array_view_helper < static_bounds < Dimensions ... >> ( args ..., details :: Sep {})};
2015-08-20 18:09:14 -07:00
}
template < typename T >
2015-10-15 14:29:35 -07:00
constexpr auto as_array_view ( T * arr , std :: ptrdiff_t len ) -> typename details :: ArrayViewArrayTraits < T , dynamic_range >:: type
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { reinterpret_cast < std :: remove_all_extents_t < T >*> ( arr ), len };
2015-08-20 18:09:14 -07:00
}
template < typename T , size_t N >
2015-10-15 14:29:35 -07:00
constexpr auto as_array_view ( T ( & arr )[ N ]) -> typename details :: ArrayViewArrayTraits < T , N >:: type
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { arr };
2015-08-20 18:09:14 -07:00
}
template < typename T , size_t N >
2015-09-28 05:10:44 -07:00
constexpr array_view < const T , N > as_array_view ( const std :: array < T , N > & arr )
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { arr };
2015-08-20 18:09:14 -07:00
}
template < typename T , size_t N >
2015-09-28 05:10:44 -07:00
constexpr array_view < const T , N > as_array_view ( const std :: array < T , N > && ) = delete ;
2015-08-20 18:09:14 -07:00
template < typename T , size_t N >
2015-09-28 05:10:44 -07:00
constexpr array_view < T , N > as_array_view ( std :: array < T , N > & arr )
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { arr };
2015-08-20 18:09:14 -07:00
}
template < typename T >
2015-09-28 05:10:44 -07:00
constexpr array_view < T , dynamic_range > as_array_view ( T * begin , T * end )
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return { begin , end };
2015-08-20 18:09:14 -07:00
}
template < typename Cont >
2015-09-28 05:10:44 -07:00
constexpr auto as_array_view ( Cont & arr ) -> std :: enable_if_t <! details :: is_array_view < std :: decay_t < Cont >>:: value ,
2015-11-03 19:17:11 -08:00
array_view < std :: remove_reference_t < decltype ( arr . size (), * arr . data ()) > , dynamic_range >>
2015-08-20 18:09:14 -07:00
{
2015-10-23 19:49:17 -07:00
fail_fast_assert ( arr . size () < PTRDIFF_MAX );
2015-11-03 19:17:11 -08:00
return { arr . data (), static_cast < std :: ptrdiff_t > ( arr . size ())};
2015-08-20 18:09:14 -07:00
}
template < typename Cont >
2015-09-28 05:10:44 -07:00
constexpr auto as_array_view ( Cont && arr ) -> std :: enable_if_t <! details :: is_array_view < std :: decay_t < Cont >>:: value ,
2015-11-03 19:17:11 -08:00
array_view < std :: remove_reference_t < decltype ( arr . size (), * arr . data ()) > , dynamic_range >> = delete ;
2015-08-20 18:09:14 -07:00
2015-10-15 14:29:35 -07:00
template < typename ValueType , size_t Rank >
class strided_array_view : public basic_array_view < ValueType , strided_bounds < Rank >>
2015-08-20 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
using Base = basic_array_view < ValueType , strided_bounds < Rank >> ;
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
template < typename OtherValue , size_t OtherRank >
friend class strided_array_view ;
2015-10-15 14:29:35 -07:00
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08: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 >
strided_array_view ( value_type ( & values )[ N ], bounds_type bounds ) : Base ( values , std :: move ( bounds ))
{
fail_fast_assert ( this -> bounds (). total_size () <= N , "Bounds cross data boundaries" );
}
2015-08-20 18:09:14 -07:00
2015-11-03 19:17:11 -08:00
// from raw data
strided_array_view ( pointer ptr , size_type size , bounds_type bounds ) : Base ( ptr , std :: move ( bounds ))
{
fail_fast_assert ( this -> bounds (). total_size () <= size , "Bounds cross data boundaries" );
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
// from array view
template < std :: ptrdiff_t ... Dimensions , typename Dummy = std :: enable_if < sizeof ...( Dimensions ) == Rank >>
strided_array_view ( array_view < ValueType , Dimensions ... > av , bounds_type bounds ) : Base ( av . data (), std :: move ( bounds ))
{
fail_fast_assert ( this -> bounds (). total_size () <= av . bounds (). total_size (), "Bounds cross data boundaries" );
}
// convertible
template < typename OtherValueType ,
typename BaseType = basic_array_view < ValueType , strided_bounds < Rank >> ,
typename OtherBaseType = basic_array_view < OtherValueType , strided_bounds < Rank >> ,
typename Dummy = std :: enable_if_t < std :: is_convertible < OtherBaseType , BaseType >:: value >
>
2015-10-15 14:29:35 -07:00
constexpr strided_array_view ( const strided_array_view < OtherValueType , Rank > & av ) : Base ( static_cast < const typename strided_array_view < OtherValueType , Rank >:: Base &> ( av )) // static_cast is required
{}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
// convert from bytes
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
{
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 ));
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
size_type size = this -> bounds (). total_size () / d ;
return { ( OtherValueType * ) this -> data (), size , bounds_type { resize_extent ( this -> bounds (). index_bounds (), d ), resize_stride ( this -> bounds (). strides (), d )} };
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
strided_array_view section ( index_type origin , index_type extents ) const
{
size_type size = this -> bounds (). total_size () - this -> bounds (). linearize ( origin );
return { & this -> operator []( origin ), size , bounds_type { extents , details :: make_stride ( Base :: bounds ())}};
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
constexpr reference operator []( const index_type & idx ) const
{
return Base :: operator []( idx );
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
template < bool Enabled = ( rank > 1 ), typename Dummy = std :: enable_if_t < Enabled >>
constexpr strided_array_view < value_type , rank - 1 > operator []( size_type idx ) const
{
auto ret = Base :: operator []( idx );
return { ret . data (), ret . bounds (). total_size (), ret . bounds () };
}
2015-08-30 23:30:15 -07:00
private :
2015-11-03 19:17:11 -08: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-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
index_type ret = extent ;
ret [ rank - 1 ] /= d ;
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
return ret ;
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08: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-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
return strides ;
}
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08: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-30 23:30:15 -07:00
2015-11-03 19:17:11 -08: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-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
index_type ret = strides / d ;
ret [ rank - 1 ] = 1 ;
2015-08-30 23:30:15 -07:00
2015-11-03 19:17:11 -08:00
return ret ;
}
2015-08-20 18:09:14 -07:00
};
template < typename ArrayView >
class contiguous_array_view_iterator : public std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type >
{
2015-11-03 19:17:11 -08:00
using Base = std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type > ;
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
2015-10-15 14:29:35 -07:00
2015-08-20 18:09:14 -07:00
private :
2015-11-03 19:17:11 -08:00
template < typename ValueType , typename Bounds >
friend class basic_array_view ;
2015-10-15 14:29:35 -07:00
pointer m_pdata ;
2015-11-03 19:17:11 -08: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" );
}
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 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
reference operator * () const noexcept
{
validateThis ();
return * m_pdata ;
}
pointer operator -> () const noexcept
{
validateThis ();
return m_pdata ;
}
contiguous_array_view_iterator & operator ++ () noexcept
{
++ m_pdata ;
return * this ;
}
contiguous_array_view_iterator operator ++ ( int ) noexcept
{
auto ret = * this ;
++ ( * this );
return ret ;
}
contiguous_array_view_iterator & operator -- () noexcept
{
-- m_pdata ;
return * this ;
}
contiguous_array_view_iterator operator -- ( int ) noexcept
{
auto ret = * this ;
-- ( * this );
return ret ;
}
contiguous_array_view_iterator operator + ( difference_type n ) const noexcept
{
contiguous_array_view_iterator ret { * this };
return ret += n ;
}
contiguous_array_view_iterator & operator += ( difference_type n ) noexcept
{
m_pdata += n ;
return * this ;
}
contiguous_array_view_iterator operator - ( difference_type n ) const noexcept
{
contiguous_array_view_iterator ret { * this };
return ret -= n ;
}
contiguous_array_view_iterator & operator -= ( difference_type n ) noexcept
{
return * this += - n ;
}
difference_type operator - ( const contiguous_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata - rhs . m_pdata ;
}
reference operator []( difference_type n ) const noexcept
{
return * ( * this + n );
}
bool operator == ( const contiguous_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata == rhs . m_pdata ;
}
bool operator != ( const contiguous_array_view_iterator & rhs ) const noexcept
{
return ! ( * this == rhs );
}
bool operator < ( const contiguous_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_validator == rhs . m_validator );
return m_pdata < rhs . m_pdata ;
}
bool operator <= ( const contiguous_array_view_iterator & rhs ) const noexcept
{
return ! ( rhs < * this );
}
bool operator > ( const contiguous_array_view_iterator & rhs ) const noexcept
{
return rhs < * this ;
}
bool operator >= ( const contiguous_array_view_iterator & rhs ) const noexcept
{
return ! ( rhs > * this );
}
void swap ( contiguous_array_view_iterator & rhs ) noexcept
{
std :: swap ( m_pdata , rhs . m_pdata );
std :: swap ( m_validator , rhs . m_validator );
}
2015-08-20 18:09:14 -07:00
};
template < typename ArrayView >
2015-09-30 21:54:08 -07: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 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return rhs + n ;
2015-08-20 18:09:14 -07:00
}
template < typename ArrayView >
class general_array_view_iterator : public std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type >
{
2015-11-03 19:17:11 -08:00
using Base = std :: iterator < std :: random_access_iterator_tag , typename ArrayView :: value_type > ;
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
using typename Base :: reference ;
using typename Base :: pointer ;
using typename Base :: difference_type ;
using typename Base :: value_type ;
2015-08-20 18:09:14 -07:00
private :
2015-11-03 19:17:11 -08:00
template < typename ValueType , typename Bounds >
friend class basic_array_view ;
2015-10-15 14:29:35 -07:00
const ArrayView * m_container ;
2015-11-03 19:17:11 -08:00
typename ArrayView :: bounds_type :: iterator m_itr ;
general_array_view_iterator ( const ArrayView * container , bool isbegin ) :
m_container ( container ), m_itr ( isbegin ? m_container -> bounds (). begin () : m_container -> bounds (). end ())
{}
2015-08-20 18:09:14 -07:00
public :
2015-11-03 19:17:11 -08:00
reference operator * () noexcept
{
return ( * m_container )[ * m_itr ];
}
pointer operator -> () noexcept
{
return & ( * m_container )[ * m_itr ];
}
general_array_view_iterator & operator ++ () noexcept
{
++ m_itr ;
return * this ;
}
general_array_view_iterator operator ++ ( int ) noexcept
{
auto ret = * this ;
++ ( * this );
return ret ;
}
general_array_view_iterator & operator -- () noexcept
{
-- m_itr ;
return * this ;
}
general_array_view_iterator operator -- ( int ) noexcept
{
auto ret = * this ;
-- ( * this );
return ret ;
}
general_array_view_iterator operator + ( difference_type n ) const noexcept
{
general_array_view_iterator ret { * this };
return ret += n ;
}
general_array_view_iterator & operator += ( difference_type n ) noexcept
{
m_itr += n ;
return * this ;
}
general_array_view_iterator operator - ( difference_type n ) const noexcept
{
general_array_view_iterator ret { * this };
return ret -= n ;
}
general_array_view_iterator & operator -= ( difference_type n ) noexcept
{
return * this += - n ;
}
difference_type operator - ( const general_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr - rhs . m_itr ;
}
value_type operator []( difference_type n ) const noexcept
{
return ( * m_container )[ m_itr [ n ]];;
}
bool operator == ( const general_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr == rhs . m_itr ;
}
bool operator != ( const general_array_view_iterator & rhs ) const noexcept
{
return ! ( * this == rhs );
}
bool operator < ( const general_array_view_iterator & rhs ) const noexcept
{
fail_fast_assert ( m_container == rhs . m_container );
return m_itr < rhs . m_itr ;
}
bool operator <= ( const general_array_view_iterator & rhs ) const noexcept
{
return ! ( rhs < * this );
}
bool operator > ( const general_array_view_iterator & rhs ) const noexcept
{
return rhs < * this ;
}
bool operator >= ( const general_array_view_iterator & rhs ) const noexcept
{
return ! ( rhs > * this );
}
void swap ( general_array_view_iterator & rhs ) noexcept
{
std :: swap ( m_itr , rhs . m_itr );
std :: swap ( m_container , rhs . m_container );
}
2015-08-20 18:09:14 -07:00
};
template < typename ArrayView >
2015-09-30 21:54:08 -07: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 18:09:14 -07:00
{
2015-11-03 19:17:11 -08:00
return rhs + n ;
2015-08-20 18:09:14 -07:00
}
2015-09-29 16:41:37 -07:00
} // namespace gsl
2015-08-20 18:09:14 -07:00
2015-09-30 21:54:08 -07:00
#ifdef _MSC_VER
2015-09-28 05:10:44 -07:00
#undef constexpr
#pragma pop_macro("constexpr")
2015-09-30 21:54:08 -07:00
#if _MSC_VER <= 1800
2015-09-14 15:11:07 -07:00
#pragma warning(pop)
2015-09-30 21:54:08 -07:00
#ifndef GSL_THROWS_FOR_TESTING
#pragma undef noexcept
#endif // GSL_THROWS_FOR_TESTING
2015-11-03 18:56:55 -08:00
#undef GSL_MSVC_HAS_VARIADIC_CTOR_BUG
#pragma pop_macro("GSL_MSVC_HAS_VARIADIC_CTOR_BUG")
2015-09-14 15:11:07 -07:00
#endif // _MSC_VER <= 1800
2015-09-30 21:54:08 -07:00
#endif // _MSC_VER
#if defined(GSL_THROWS_FOR_TESTING)
#undef noexcept
#endif // GSL_THROWS_FOR_TESTING
2015-09-24 18:08:34 -07:00
#endif // GSL_ARRAY_VIEW_H