123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /*!
- @file
- Defines `boost::hana::cartesian_product`.
- @copyright Louis Dionne 2013-2017
- 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 <boost/hana/fwd/cartesian_product.hpp>
- #include <boost/hana/at.hpp>
- #include <boost/hana/concept/sequence.hpp>
- #include <boost/hana/config.hpp>
- #include <boost/hana/core/dispatch.hpp>
- #include <boost/hana/core/make.hpp>
- #include <boost/hana/detail/array.hpp>
- #include <boost/hana/integral_constant.hpp>
- #include <boost/hana/length.hpp>
- #include <boost/hana/unpack.hpp>
- #include <cstddef>
- #include <utility>
- BOOST_HANA_NAMESPACE_BEGIN
- //! @cond
- template <typename Xs>
- constexpr auto cartesian_product_t::operator()(Xs&& xs) const {
- using S = typename hana::tag_of<Xs>::type;
- using CartesianProduct = BOOST_HANA_DISPATCH_IF(
- cartesian_product_impl<S>,
- hana::Sequence<S>::value
- );
- #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
- static_assert(hana::Sequence<S>::value,
- "hana::cartesian_product(xs) requires 'xs' to be a Sequence");
- #endif
- return CartesianProduct::apply(static_cast<Xs&&>(xs));
- }
- //! @endcond
- namespace detail {
- template <std::size_t ...Lengths>
- 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<std::size_t, n> result{};
- for (std::size_t j = n; j--;) {
- result[j] = i % lengths[j];
- i /= lengths[j];
- }
- return result;
- }
- template <typename S, std::size_t n, std::size_t ...k, typename ...Xs>
- static constexpr auto
- product_element(std::index_sequence<k...>, Xs&& ...xs) {
- constexpr auto indices = indices_of(n);
- return hana::make<S>(hana::at_c<indices[k]>(xs)...);
- }
- template <typename S, std::size_t ...n, typename ...Xs>
- static constexpr auto
- create_product(std::index_sequence<n...>, Xs&& ...xs) {
- return hana::make<S>(product_element<S, n>(
- std::make_index_sequence<sizeof...(Xs)>{}, xs...
- )...);
- }
- };
- }
- // Credits: implementation adapted from http://github.com/alexk7/hel.
- template <typename S, bool condition>
- struct cartesian_product_impl<S, when<condition>> : default_ {
- template <typename Xs>
- static constexpr auto apply(Xs&& xs) {
- return hana::unpack(static_cast<Xs&&>(xs), cartesian_product_impl{});
- }
- template <typename ...Xs>
- constexpr auto operator()(Xs&& ...xs) const {
- using indices = detail::cartesian_product_indices<
- decltype(hana::length(xs))::value...
- >;
- return indices::template create_product<S>(
- std::make_index_sequence<indices::length>{},
- static_cast<Xs&&>(xs)...);
- }
- constexpr auto operator()() const {
- return hana::make<S>();
- }
- };
- BOOST_HANA_NAMESPACE_END
- #endif // !BOOST_HANA_CARTESIAN_PRODUCT_HPP
|