1 /*! 2 @file 3 Defines `boost::hana::group`. 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_GROUP_HPP 11 #define BOOST_HANA_GROUP_HPP 12 13 #include <boost/hana/fwd/group.hpp> 14 15 #include <boost/hana/at.hpp> 16 #include <boost/hana/concept/sequence.hpp> 17 #include <boost/hana/config.hpp> 18 #include <boost/hana/core/dispatch.hpp> 19 #include <boost/hana/core/make.hpp> 20 #include <boost/hana/detail/algorithm.hpp> 21 #include <boost/hana/detail/array.hpp> 22 #include <boost/hana/detail/nested_by.hpp> // required by fwd decl 23 #include <boost/hana/equal.hpp> 24 #include <boost/hana/length.hpp> 25 26 #include <cstddef> 27 #include <utility> 28 29 30 BOOST_HANA_NAMESPACE_BEGIN 31 //! @cond 32 template <typename Xs> operator ()(Xs && xs) const33 constexpr auto group_t::operator()(Xs&& xs) const { 34 using S = typename hana::tag_of<Xs>::type; 35 using Group = BOOST_HANA_DISPATCH_IF(group_impl<S>, 36 hana::Sequence<S>::value 37 ); 38 39 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS 40 static_assert(hana::Sequence<S>::value, 41 "hana::group(xs) requires 'xs' to be a Sequence"); 42 #endif 43 44 return Group::apply(static_cast<Xs&&>(xs)); 45 } 46 47 template <typename Xs, typename Predicate> operator ()(Xs && xs,Predicate && pred) const48 constexpr auto group_t::operator()(Xs&& xs, Predicate&& pred) const { 49 using S = typename hana::tag_of<Xs>::type; 50 using Group = BOOST_HANA_DISPATCH_IF(group_impl<S>, 51 hana::Sequence<S>::value 52 ); 53 54 #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS 55 static_assert(hana::Sequence<S>::value, 56 "hana::group(xs, predicate) requires 'xs' to be a Sequence"); 57 #endif 58 59 return Group::apply(static_cast<Xs&&>(xs), 60 static_cast<Predicate&&>(pred)); 61 } 62 //! @endcond 63 64 namespace detail { 65 template <typename Xs, std::size_t ...i> get_subsequence_(Xs && xs,std::index_sequence<i...>)66 constexpr auto get_subsequence_(Xs&& xs, std::index_sequence<i...>) { 67 using S = typename hana::tag_of<Xs>::type; 68 return hana::make<S>(hana::at_c<i>(static_cast<Xs&&>(xs))...); 69 } 70 71 template <std::size_t offset, typename Indices> 72 struct offset_by; 73 74 template <std::size_t offset, std::size_t ...i> 75 struct offset_by<offset, std::index_sequence<i...>> { 76 using type = std::index_sequence<(offset + i)...>; 77 }; 78 79 template <bool ...b> 80 struct group_indices { 81 static constexpr bool bs[sizeof...(b)] = {b...}; 82 static constexpr std::size_t n_groups = 83 detail::count(bs, bs + sizeof(bs), false) + 1; 84 compute_infodetail::group_indices85 static constexpr auto compute_info() { 86 detail::array<std::size_t, n_groups> sizes{}, offsets{}; 87 for (std::size_t g = 0, i = 0, offset = 0; g < n_groups; ++g) { 88 offsets[g] = offset; 89 90 sizes[g] = 1; 91 while (i < sizeof...(b) && bs[i++]) 92 ++sizes[g]; 93 94 offset += sizes[g]; 95 } 96 return std::make_pair(offsets, sizes); 97 } 98 99 static constexpr auto info = compute_info(); 100 static constexpr auto group_offsets = info.first; 101 static constexpr auto group_sizes = info.second; 102 103 template <typename S, typename Xs, std::size_t ...i> finishdetail::group_indices104 static constexpr auto finish(Xs&& xs, std::index_sequence<i...>) { 105 return hana::make<S>( 106 detail::get_subsequence_( 107 static_cast<Xs&&>(xs), 108 typename offset_by< 109 group_offsets[i], 110 std::make_index_sequence<group_sizes[i]> 111 >::type{} 112 )... 113 ); 114 } 115 }; 116 } // end namespace detail 117 118 template <typename S, bool condition> 119 struct group_impl<S, when<condition>> : default_ { 120 template <typename Xs, typename Pred, std::size_t ...i> 121 static constexpr auto group_helpergroup_impl122 group_helper(Xs&& xs, Pred&& pred, std::index_sequence<0, i...>) { 123 using info = detail::group_indices<static_cast<bool>(decltype( 124 pred(hana::at_c<i - 1>(static_cast<Xs&&>(xs)), 125 hana::at_c<i>(static_cast<Xs&&>(xs))) 126 )::value)...>; 127 return info::template finish<S>(static_cast<Xs&&>(xs), 128 std::make_index_sequence<info::n_groups>{} 129 ); 130 } 131 132 template <typename Xs, typename Pred> 133 static constexpr auto group_helpergroup_impl134 group_helper(Xs&& xs, Pred&&, std::index_sequence<0>) { 135 return hana::make<S>(static_cast<Xs&&>(xs)); 136 } 137 138 template <typename Xs, typename Pred> 139 static constexpr auto group_helpergroup_impl140 group_helper(Xs&&, Pred&&, std::index_sequence<>) { 141 return hana::make<S>(); 142 } 143 144 template <typename Xs, typename Pred> applygroup_impl145 static constexpr auto apply(Xs&& xs, Pred&& pred) { 146 constexpr std::size_t len = decltype(hana::length(xs))::value; 147 return group_helper(static_cast<Xs&&>(xs), 148 static_cast<Pred&&>(pred), 149 std::make_index_sequence<len>{}); 150 } 151 152 template <typename Xs> applygroup_impl153 static constexpr auto apply(Xs&& xs) 154 { return group_impl::apply(static_cast<Xs&&>(xs), hana::equal); } 155 }; 156 BOOST_HANA_NAMESPACE_END 157 158 #endif // !BOOST_HANA_GROUP_HPP 159