SpECTRE Documentation Coverage Report
Current view: top level - Utilities - CartesianProduct.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 75.0 % 4 3
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            0 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : #pragma once
       5              : 
       6              : #include <array>
       7              : #include <iterator>
       8              : #include <tuple>
       9              : #include <utility>
      10              : #include <vector>
      11              : 
      12              : // This implementation is from:
      13              : // https://stackoverflow.com/questions/16686942/how-to-iterate-over-two-stl-like-containers-cartesian-product
      14              : 
      15              : namespace detail {
      16              : 
      17              : // the lambda is fully bound with one element from each of the ranges
      18              : template <class Op>
      19              : void insert_tuples(Op op) {
      20              :   // evaluating the lambda will insert the currently bound tuple
      21              :   op();
      22              : }
      23              : 
      24              : // "peel off" the first range from the remaining tuple of ranges
      25              : template <class Op, class InputIterator1, class... InputIterator2>
      26              : void insert_tuples(Op op, std::pair<InputIterator1, InputIterator1> head,
      27              :                    std::pair<InputIterator2, InputIterator2>... tail) {
      28              :   // "peel off" the elements from the first of the remaining ranges
      29              :   // NOTE: the recursion will effectively generate the multiple nested for-loops
      30              :   for (auto it = head.first; it != head.second; ++it) {
      31              :     // bind the first free variable in the lambda, and
      32              :     // keep one free variable for each of the remaining ranges
      33              :     detail::insert_tuples(
      34              :         [&op, &it](InputIterator2... elems) { op(it, elems...); }, tail...);
      35              :   }
      36              : }
      37              : 
      38              : }  // namespace detail
      39              : 
      40              : /*!
      41              :  * \ingroup UtilitiesGroup
      42              :  * \brief Fill the `result` iterator with the Cartesian product of a sequence of
      43              :  * iterators
      44              :  *
      45              :  * The `result` will hold all possible combinations of the input iterators.
      46              :  * The last dimension varies fastest.
      47              :  */
      48              : template <class OutputIterator, class... InputIterator>
      49            1 : void cartesian_product(OutputIterator result,
      50              :                        std::pair<InputIterator, InputIterator>... dimensions) {
      51              :   detail::insert_tuples(
      52              :       [&result](InputIterator... elems) {
      53              :         *result++ = std::make_tuple(*elems...);
      54              :       },
      55              :       dimensions...);
      56              : }
      57              : 
      58              : /*!
      59              :  * \ingroup UtilitiesGroup
      60              :  * \brief The Cartesian product of a sequence of arrays
      61              :  *
      62              :  * Returns a `std::array` with all possible combinations of the input arrays.
      63              :  * The last dimension varies fastest.
      64              :  *
      65              :  * \example
      66              :  * Here's an example using this function to replace a nested for loop:
      67              :  * \snippet Test_Wedge3D.cpp cartesian_product_loop
      68              :  */
      69              : template <typename... Ts, size_t... Lens>
      70            1 : std::array<std::tuple<Ts...>, (... * Lens)> cartesian_product(
      71              :     const std::array<Ts, Lens>&... dimensions) {
      72              :   std::array<std::tuple<Ts...>, (... * Lens)> result{};
      73              :   cartesian_product(result.begin(),
      74              :                     std::make_pair(dimensions.begin(), dimensions.end())...);
      75              :   return result;
      76              : }
      77              : 
      78              : /*!
      79              :  * \ingroup UtilitiesGroup
      80              :  * \brief The Cartesian product of several containers
      81              :  *
      82              :  * Returns a `std::vector` with all possible combinations of the values of the
      83              :  * input containers. The value of the last container varies fastest.
      84              :  */
      85              : template <typename... Containers>
      86            1 : std::vector<std::tuple<typename Containers::value_type...>> cartesian_product(
      87              :     const Containers&... containers) {
      88              :   std::vector<std::tuple<typename Containers::value_type...>> result{};
      89              :   cartesian_product(
      90              :       std::back_inserter(result),
      91              :       std::make_pair(std::begin(containers), std::end(containers))...);
      92              :   return result;
      93              : }
        

Generated by: LCOV version 2.0-1