You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
5.7 KiB
210 lines
5.7 KiB
// |
|
// Copyright (c) 2009 Rutger ter Borg |
|
// |
|
// Distributed under the Boost Software License, Version 1.0. |
|
// (See accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
|
|
#ifndef BOOST_NUMERIC_BINDINGS_STRIDE_HPP |
|
#define BOOST_NUMERIC_BINDINGS_STRIDE_HPP |
|
|
|
#include <boost/numeric/bindings/size.hpp> |
|
#include <boost/mpl/min.hpp> |
|
#include <boost/mpl/and.hpp> |
|
#include <boost/mpl/less_equal.hpp> |
|
#include <boost/mpl/equal_to.hpp> |
|
#include <boost/mpl/range_c.hpp> |
|
#include <boost/mpl/times.hpp> |
|
#include <boost/mpl/greater.hpp> |
|
#include <boost/mpl/plus.hpp> |
|
#include <boost/type_traits/is_same.hpp> |
|
#include <boost/static_assert.hpp> |
|
|
|
namespace boost { |
|
namespace numeric { |
|
namespace bindings { |
|
namespace detail { |
|
|
|
template< typename T, typename AddressingIndex, typename Enable = void > |
|
struct stride_impl { |
|
|
|
typedef tag::stride_type< AddressingIndex::value > key_type; |
|
typedef typename result_of_get< T, key_type >::type result_type; |
|
|
|
static result_type invoke( const T& t ) { |
|
return get< key_type >( t ); |
|
} |
|
|
|
}; |
|
|
|
// |
|
// Strides for ranks outside the scope of the object are fixed at |
|
// the dot product of its existing sizes and strides. |
|
// |
|
// Object rank result of strideN(), with N > rank |
|
// scalar 0 1 |
|
// vector 1 size1 * stride1 |
|
// matrix 2 size1 * stride1 + size2 * stride2 |
|
// tensor N sum_i( size_i, stride_i ) (dot( size, stride)) |
|
// |
|
// Iff size_i and stride_i are integral constants, results will be known at |
|
// compile time. Otherwise, the result_type will be std::ptrdiff_t. |
|
// |
|
template< typename T, typename AddressingIndex > |
|
struct stride_impl< T, AddressingIndex, |
|
typename boost::enable_if< |
|
mpl::equal_to< rank<T>, tag::scalar > |
|
>::type > { |
|
|
|
typedef typename mpl::int_<1> result_type; |
|
|
|
static result_type invoke( const T& t ) { |
|
return result_type(); |
|
} |
|
|
|
}; |
|
|
|
|
|
template< typename T, typename State, typename AddressingIndex > |
|
struct fold_stride_size { |
|
|
|
typedef tag::addressing_index< AddressingIndex::value > index_type; |
|
typedef typename result_of::size< T, index_type >::type size_type; |
|
typedef typename stride_impl< T, index_type >::result_type stride_type; |
|
|
|
typedef typename mpl::if_< |
|
mpl::or_< |
|
is_same< State, std::ptrdiff_t >, |
|
is_same< size_type, std::ptrdiff_t >, |
|
is_same< stride_type, std::ptrdiff_t > |
|
>, |
|
std::ptrdiff_t, |
|
mpl::plus< |
|
State, |
|
mpl::times< |
|
size_type, |
|
stride_type |
|
> |
|
> |
|
>::type type; |
|
|
|
}; |
|
|
|
// |
|
// If Result isn't a ptrdiff_t, just invoke the integral constant |
|
// and return that. Otherwise, runtime stuff is involved, so we'll |
|
// have to evaluate sum_i( size_i, stride_i ). |
|
// |
|
template< typename T, typename Result, int AddressingIndex > |
|
struct apply_fold { |
|
static Result invoke( const T& t ) { |
|
return Result(); |
|
} |
|
}; |
|
|
|
template< typename T, int AddressingIndex > |
|
struct apply_fold< T, std::ptrdiff_t, AddressingIndex > { |
|
|
|
static std::ptrdiff_t invoke( const T& t ) { |
|
return size( t, tag::addressing_index< AddressingIndex >() ) * |
|
stride_impl< T, tag::addressing_index< AddressingIndex > >::invoke( t ) + |
|
apply_fold< T, std::ptrdiff_t, AddressingIndex-1 >::invoke( t ); |
|
} |
|
|
|
}; |
|
|
|
template< typename T > |
|
struct apply_fold< T, std::ptrdiff_t, 0 > { |
|
|
|
static std::ptrdiff_t invoke( const T& ) { |
|
return 0; |
|
} |
|
|
|
}; |
|
|
|
|
|
// Could be made generic for dimensions > 2, |
|
// but not enough time right now |
|
|
|
|
|
template< typename T, typename AddressingIndex > |
|
struct stride_impl< T, AddressingIndex, |
|
typename boost::enable_if< |
|
mpl::and_< |
|
mpl::greater< rank<T>, tag::scalar >, |
|
mpl::greater< AddressingIndex, rank<T> > |
|
> |
|
>::type > { |
|
|
|
typedef mpl::range_c< int, 1, rank<T>::value+1 > index_range; |
|
typedef typename mpl::fold< |
|
index_range, |
|
mpl::int_< 0 >, |
|
fold_stride_size< |
|
T, |
|
mpl::_1, |
|
mpl::_2 |
|
> |
|
>::type result_type; |
|
|
|
static result_type invoke( const T& t ) { |
|
return apply_fold< T, result_type, rank<T>::value >::invoke( t ); |
|
} |
|
|
|
|
|
}; |
|
|
|
} // namespace detail |
|
|
|
namespace result_of { |
|
|
|
template< typename T, typename Tag = tag::addressing_index<1> > |
|
struct stride { |
|
BOOST_STATIC_ASSERT( (is_tag<Tag>::value) ); |
|
typedef typename detail::stride_impl< T, Tag >::result_type type; |
|
}; |
|
|
|
} // namespace result_of |
|
|
|
|
|
// |
|
// Overloads for free template functions stride( x, tag ), |
|
// |
|
template< typename T, typename Tag > |
|
inline typename result_of::stride< const T, Tag >::type |
|
stride( const T& t, Tag ) { |
|
return detail::stride_impl< const T, Tag >::invoke( t ); |
|
} |
|
|
|
// Overloads for free template functions stride( x ) |
|
// Valid for types with rank <= 1 (scalars, vectors) |
|
// In theory, we could provide overloads for matrices here, too, |
|
// if their minimal_rank is at most 1. |
|
|
|
template< typename T > |
|
inline typename |
|
boost::enable_if< |
|
mpl::less< rank<T>, mpl::int_<2> >, |
|
typename result_of::stride< const T, tag::addressing_index<1> >::type |
|
>::type |
|
stride( const T& t ) { |
|
return detail::stride_impl<const T, tag::addressing_index<1> >::invoke( t ); |
|
} |
|
|
|
|
|
#define GENERATE_STRIDE_INDEX( z, which, unused ) \ |
|
GENERATE_FUNCTIONS( stride, which, tag::addressing_index<which> ) |
|
|
|
BOOST_PP_REPEAT_FROM_TO(1,3,GENERATE_STRIDE_INDEX,~) |
|
|
|
GENERATE_FUNCTIONS( stride, _row, tag::addressing_index<1> ) |
|
GENERATE_FUNCTIONS( stride, _column, tag::addressing_index<2> ) |
|
GENERATE_FUNCTIONS( stride, _major, typename addressing_index_major<T>::type ) |
|
GENERATE_FUNCTIONS( stride, _minor, typename addressing_index_minor<T>::type ) |
|
|
|
} // namespace bindings |
|
} // namespace numeric |
|
} // namespace boost |
|
|
|
#endif
|
|
|