SpECTRE Documentation Coverage Report
Current view: top level - Utilities - GenerateInstantiations.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 2 1
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 <boost/parameter/name.hpp>
       7              : #include <boost/preprocessor/arithmetic/inc.hpp>
       8              : #include <boost/preprocessor/control/expr_iif.hpp>
       9              : #include <boost/preprocessor/control/iif.hpp>
      10              : #include <boost/preprocessor/control/while.hpp>
      11              : #include <boost/preprocessor/list/adt.hpp>
      12              : #include <boost/preprocessor/list/fold_left.hpp>
      13              : #include <boost/preprocessor/list/fold_right.hpp>
      14              : #include <boost/preprocessor/list/for_each_product.hpp>
      15              : #include <boost/preprocessor/list/size.hpp>
      16              : #include <boost/preprocessor/list/to_tuple.hpp>
      17              : #include <boost/preprocessor/list/transform.hpp>
      18              : #include <boost/preprocessor/logical/bitand.hpp>
      19              : #include <boost/preprocessor/logical/bool.hpp>
      20              : #include <boost/preprocessor/logical/compl.hpp>
      21              : #include <boost/preprocessor/repetition/for.hpp>
      22              : #include <boost/preprocessor/tuple/elem.hpp>
      23              : #include <boost/preprocessor/tuple/reverse.hpp>
      24              : #include <boost/preprocessor/tuple/size.hpp>
      25              : #include <boost/preprocessor/tuple/to_list.hpp>
      26              : #include <boost/preprocessor/variadic/elem.hpp>
      27              : #include <boost/preprocessor/variadic/to_list.hpp>
      28              : 
      29              : /// \cond
      30              : #define GENERATE_INSTANTIATIONS_DO_PRODUCT(INSTANTIATION_MACRO, LIST_OF_LISTS) \
      31              :   BOOST_PP_LIST_FOR_EACH_PRODUCT(INSTANTIATION_MACRO,                          \
      32              :                                  BOOST_PP_LIST_SIZE(LIST_OF_LISTS),            \
      33              :                                  BOOST_PP_LIST_TO_TUPLE(LIST_OF_LISTS))
      34              : 
      35              : #define GENERATE_INSTANTIATION_TUPLES_TO_LISTS(d, _, elem) \
      36              :   BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_SIZE(elem), elem)
      37              : /// \endcond
      38              : 
      39              : /*!
      40              :  * \ingroup UtilitiesGroup
      41              :  * \brief Macro useful for generating many explicit instantiations of function
      42              :  * or class templates
      43              :  *
      44              :  * It is often necessary to generate explicit instantiations of function or
      45              :  * class templates. Since the total number of explicit instantiations scales as
      46              :  * the product of the number of possible number of parameter values of each
      47              :  * template parameter, this quickly becomes tedious. This macro allows you to
      48              :  * easily generate hundreds of explicit instantiations.
      49              :  *
      50              :  * The first argument to the macro is a macro that takes two arguments and is
      51              :  * described below. The remaining arguments are macro-tuples, e.g. `(1, 2, 3)`.
      52              :  * The Cartesian product of the macro-tuples is then computed and each term is
      53              :  * passed as a tuple as the second argument to the `INSTANTIATION_MACRO`. The
      54              :  * first argument to the `INSTANTIATION_MACRO` is a Boost.Preprocessor internal
      55              :  * variable so just make it `_`. The `INSTANTIATION(_, data)` macro below serves
      56              :  * as an example. A concrete example is generating explicit instantiations of
      57              :  * the class `Index<Dim>` for `Dim = 0,1,2,3`, which you would do as follows:
      58              :  *
      59              :  * \code
      60              :  * #define GET_DIM(data) BOOST_PP_TUPLE_ELEM(0, data)
      61              :  *
      62              :  * #define INSTANTIATION(_, data)         \
      63              :  *   template class Index<GET_DIM(data)>;
      64              :  *
      65              :  * GENERATE_INSTANTIATIONS(INSTANTIATION, (0, 1, 2, 3))
      66              :  *
      67              :  * #undef GET_DIM
      68              :  * #undef INSTANTIATION
      69              :  * \endcode
      70              :  *
      71              :  * This will generate:
      72              :  *
      73              :  * \code
      74              :  * template class Index<0>;
      75              :  * template class Index<1>;
      76              :  * template class Index<2>;
      77              :  * template class Index<3>;
      78              :  * \endcode
      79              :  *
      80              :  * It is also possible to generate explicit instantiations for multiple classes
      81              :  * or functions in a single call to `GENERATE_INSTANTIATIONS`. For example, the
      82              :  * (in)equivalence operators can be generated using:
      83              :  *
      84              :  * \code
      85              :  * #define GET_DIM(data) BOOST_PP_TUPLE_ELEM(0, data)
      86              :  * #define GEN_OP(op, dim)                            \
      87              :  *   template bool operator op(const Index<dim>& lhs, \
      88              :  *                             const Index<dim>& rhs);
      89              :  * #define INSTANTIATION(_, data)         \
      90              :  *   template class Index<GET_DIM(data)>; \
      91              :  *   GEN_OP(==, GET_DIM(data))            \
      92              :  *   GEN_OP(!=, GET_DIM(data))
      93              :  *
      94              :  * GENERATE_INSTANTIATIONS(INSTANTIATION, (0, 1, 2, 3))
      95              :  *
      96              :  * #undef GET_DIM
      97              :  * #undef GEN_OP
      98              :  * #undef INSTANTIATION
      99              :  * \endcode
     100              :  *
     101              :  * which will result in the instantiations:
     102              :  *
     103              :  * \code
     104              :  * template class Index<0>;
     105              :  * template bool operator==(const Index<0>& lhs, const Index<0>& rhs);
     106              :  * template bool operator!=(const Index<0>& lhs, const Index<0>& rhs);
     107              :  * template class Index<1>;
     108              :  * template bool operator==(const Index<1>& lhs, const Index<1>& rhs);
     109              :  * template bool operator!=(const Index<1>& lhs, const Index<1>& rhs);
     110              :  * template class Index<2>;
     111              :  * template bool operator==(const Index<2>& lhs, const Index<2>& rhs);
     112              :  * template bool operator!=(const Index<2>& lhs, const Index<2>& rhs);
     113              :  * template class Index<3>;
     114              :  * template bool operator==(const Index<3>& lhs, const Index<3>& rhs);
     115              :  * template bool operator!=(const Index<3>& lhs, const Index<3>& rhs);
     116              :  * \endcode
     117              :  *
     118              :  * Now let's look at generating instantiations of member function templates of
     119              :  * class templates, which will be a common use case. In this example we generate
     120              :  * explicit instantiations of all the member function templates of the class
     121              :  * `ScalarWave::Solutions::PlaneWave`. In total, for `Dim = 1,2,3` and types
     122              :  * `double` and `DataVector` this is about 42 explicit instantiations, which
     123              :  * would be extremely annoying to write by hand. The macro code is surprisingly
     124              :  * simple:
     125              :  *
     126              :  * \code
     127              :  * #define DIM(data) BOOST_PP_TUPLE_ELEM(0, data)
     128              :  * #define DTYPE(data) BOOST_PP_TUPLE_ELEM(1, data)
     129              :  *
     130              :  * #define INSTANTIATE(_, data)                                              \
     131              :  *   template Scalar<DTYPE(data)>                                            \
     132              :  *   ScalarWave::Solutions::PlaneWave<DIM(data)>::psi(                       \
     133              :  *       const tnsr::I<DTYPE(data), DIM(data)>& x, double t) const; \
     134              :  *   template Scalar<DTYPE(data)>                                            \
     135              :  *   ScalarWave::Solutions::PlaneWave<DIM(data)>::dpsi_dt(                   \
     136              :  *       const tnsr::I<DTYPE(data), DIM(data)>& x, double t) const;
     137              :  *
     138              :  * GENERATE_INSTANTIATIONS(INSTANTIATE, (1, 2, 3), (double, DataVector))
     139              :  *
     140              :  * #undef DIM
     141              :  * #undef DTYPE
     142              :  * #undef INSTANTIATE
     143              :  * \endcode
     144              :  *
     145              :  * We don't show the result from preprocessor since for all of the member
     146              :  * functions of `PlaneWave` the total output is approximately 150 lines, but you
     147              :  * can hopefully see the benefits of generating explicit instantiations using
     148              :  * the `GENERATE_INSTANTIATIONS` way.
     149              :  *
     150              :  * One thing that can be difficult is debugging metaprograms (be they template
     151              :  * or macro-based). To this end we provide a make target `DebugPreprocessor`
     152              :  * which prints the output of running the preprocessor on the file
     153              :  * `src/Executables/DebugPreprocessor/DebugPreprocessor.cpp`.
     154              :  * Note that the output of the `GENERATE_INSTANTIATIONS` macro will be on a
     155              :  * single line, so it often proves useful to copy-paste the output into an
     156              :  * editor and run clang-format over the code so it's easier to reason about.
     157              :  */
     158            1 : #define GENERATE_INSTANTIATIONS(INSTANTIATION_MACRO, ...)                \
     159              :   GENERATE_INSTANTIATIONS_DO_PRODUCT(                                    \
     160              :       INSTANTIATION_MACRO,                                               \
     161              :       BOOST_PP_LIST_TRANSFORM(GENERATE_INSTANTIATION_TUPLES_TO_LISTS, _, \
     162              :                               BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)))
        

Generated by: LCOV version 2.0-1