1 /*! 2 @file 3 Defines `boost::hana::slice` and `boost::hana::slice_c`. 4 5 @copyright Louis Dionne 2013-2017 6 Distributed under the Boost Software License, Version 1.0. 7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 */ 9 10 #ifndef BOOST_HANA_SLICE_HPP 11 #define BOOST_HANA_SLICE_HPP 12 13 #include <boost/hana/fwd/slice.hpp> 14 15 #include <boost/hana/at.hpp> 16 #include <boost/hana/concept/foldable.hpp> 17 #include <boost/hana/concept/sequence.hpp> 18 #include <boost/hana/config.hpp> 19 #include <boost/hana/core/dispatch.hpp> 20 #include <boost/hana/core/make.hpp> 21 #include <boost/hana/range.hpp> 22 #include <boost/hana/unpack.hpp> 23 24 #include <cstddef> 25 #include <utility> 26 27 28 BOOST_HANA_NAMESPACE_BEGIN 29 //! @cond 30 template <typename Xs, typename Indices> operator ()(Xs && xs,Indices && indices) const31 constexpr auto slice_t::operator()(Xs&& xs, Indices&& indices) const { 32 using S = typename hana::tag_of<Xs>::type; 33 using Slice = BOOST_HANA_DISPATCH_IF(slice_impl<S>, 34 hana::Sequence<S>::value && 35 hana::Foldable<Indices>::value 36 ); 37 38 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS 39 static_assert(hana::Sequence<S>::value, 40 "hana::slice(xs, indices) requires 'xs' to be a Sequence"); 41 42 static_assert(hana::Foldable<Indices>::value, 43 "hana::slice(xs, indices) requires 'indices' to be Foldable"); 44 #endif 45 46 return Slice::apply(static_cast<Xs&&>(xs), static_cast<Indices&&>(indices)); 47 } 48 //! @endcond 49 50 namespace detail { 51 template <typename Xs> 52 struct take_arbitrary { 53 Xs& xs; 54 using S = typename hana::tag_of<Xs>::type; 55 56 template <typename ...N> operator ()detail::take_arbitrary57 constexpr auto operator()(N const& ...) const { 58 return hana::make<S>(hana::at_c<N::value>(xs)...); 59 } 60 }; 61 } 62 63 template <typename S, bool condition> 64 struct slice_impl<S, when<condition>> : default_ { 65 template <std::size_t from, typename Xs, std::size_t ...i> from_offsetslice_impl66 static constexpr auto from_offset(Xs&& xs, std::index_sequence<i...>) { 67 return hana::make<S>(hana::at_c<from + i>(static_cast<Xs&&>(xs))...); 68 } 69 70 template <typename Xs, typename T, T from, T to> applyslice_impl71 static constexpr auto apply(Xs&& xs, hana::range<T, from, to> const&) { 72 return slice_impl::from_offset<from>( 73 static_cast<Xs&&>(xs), std::make_index_sequence<to - from>{} 74 ); 75 } 76 77 //! @todo 78 //! Since we have the right to specify the same index more than once, 79 //! we can't move from the elements of the source sequence even if it 80 //! is a temporary object: we could end up double-moving. Perhaps it 81 //! would be possible to determine the indices from which we can move 82 //! without incurring a too large compile-time penalty? 83 template <typename Xs, typename Indices> applyslice_impl84 static constexpr auto apply(Xs const& xs, Indices const& indices) { 85 return hana::unpack(indices, detail::take_arbitrary<Xs const>{xs}); 86 } 87 }; 88 89 template <std::size_t from, std::size_t to> 90 struct slice_c_t { 91 template <typename Xs> operator ()slice_c_t92 constexpr auto operator()(Xs&& xs) const { 93 return hana::slice(static_cast<Xs&&>(xs), 94 hana::range_c<std::size_t, from, to>); 95 } 96 }; 97 BOOST_HANA_NAMESPACE_END 98 99 #endif // !BOOST_HANA_SLICE_HPP 100