/*! @file Defines `boost::hana::cartesian_product`. Copyright Louis Dionne 2013-2022 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_CARTESIAN_PRODUCT_HPP #define BOOST_HANA_CARTESIAN_PRODUCT_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace hana { //! @cond template constexpr auto cartesian_product_t::operator()(Xs&& xs) const { using S = typename hana::tag_of::type; using CartesianProduct = BOOST_HANA_DISPATCH_IF( cartesian_product_impl, hana::Sequence::value ); #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Sequence::value, "hana::cartesian_product(xs) requires 'xs' to be a Sequence"); #endif return CartesianProduct::apply(static_cast(xs)); } //! @endcond namespace detail { template struct cartesian_product_indices { static constexpr std::size_t total_length() { std::size_t lengths[sizeof...(Lengths)] = {Lengths...}; std::size_t r = 1; for (std::size_t len: lengths) r *= len; return r; } static constexpr std::size_t length = total_length(); static constexpr auto indices_of(std::size_t i) { constexpr std::size_t lengths[sizeof...(Lengths)] = {Lengths...}; constexpr std::size_t n = sizeof...(Lengths); detail::array result{}; for (std::size_t j = n; j--;) { result[j] = i % lengths[j]; i /= lengths[j]; } return result; } template static constexpr auto product_element(std::index_sequence, Xs&& ...xs) { constexpr auto indices = indices_of(n); return hana::make(hana::at_c(xs)...); } template static constexpr auto create_product(std::index_sequence, Xs&& ...xs) { return hana::make(product_element( std::make_index_sequence{}, xs... )...); } }; } // Credits: implementation adapted from http://github.com/alexk7/hel. template struct cartesian_product_impl> : default_ { template static constexpr auto apply(Xs&& xs) { return hana::unpack(static_cast(xs), cartesian_product_impl{}); } template constexpr auto operator()(Xs&& ...xs) const { using indices = detail::cartesian_product_indices< decltype(hana::length(xs))::value... >; return indices::template create_product( std::make_index_sequence{}, static_cast(xs)...); } constexpr auto operator()() const { return hana::make(); } }; }} // end namespace boost::hana #endif // !BOOST_HANA_CARTESIAN_PRODUCT_HPP