// // 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 #include #include #include #include #include #include #include #include #include #include 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, 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, tag::scalar >, mpl::greater< AddressingIndex, rank > > >::type > { typedef mpl::range_c< int, 1, rank::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::value >::invoke( t ); } }; } // namespace detail namespace result_of { template< typename T, typename Tag = tag::addressing_index<1> > struct stride { BOOST_STATIC_ASSERT( (is_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, mpl::int_<2> >, typename result_of::stride< const T, tag::addressing_index<1> >::type >::type stride( const T& t ) { return detail::stride_impl >::invoke( t ); } #define GENERATE_STRIDE_INDEX( z, which, unused ) \ GENERATE_FUNCTIONS( stride, which, tag::addressing_index ) 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::type ) GENERATE_FUNCTIONS( stride, _minor, typename addressing_index_minor::type ) } // namespace bindings } // namespace numeric } // namespace boost #endif