SpECTRE Documentation Coverage Report
Current view: top level - Utilities - StdArrayHelpers.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 58.3 % 24 14
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines arithmetic operators for std::array and other helpful functions.
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <array>
      10              : #include <cassert>
      11              : #include <cmath>
      12              : #include <cstddef>
      13              : #include <type_traits>
      14              : #include <utility>
      15              : 
      16              : #include "Utilities/Gsl.hpp"
      17              : 
      18              : // Arithmetic operators for std::array<T, Dim>
      19              : 
      20              : template <size_t Dim, typename T, typename U>
      21            0 : inline constexpr std::array<T, Dim>& operator+=(std::array<T, Dim>& lhs,
      22              :                                                 const std::array<U, Dim>& rhs) {
      23              :   for (size_t i = 0; i < Dim; ++i) {
      24              :     gsl::at(lhs, i) += gsl::at(rhs, i);
      25              :   }
      26              :   return lhs;
      27              : }
      28              : 
      29              : template <size_t Dim, typename T, typename U>
      30            0 : inline constexpr auto operator+(const std::array<T, Dim>& lhs,
      31              :                                 const std::array<U, Dim>& rhs)
      32              :     -> std::array<decltype(lhs[0] + rhs[0]), Dim> {
      33              :   std::array<decltype(lhs[0] + rhs[0]), Dim> result{};
      34              :   for (size_t i = 0; i < Dim; ++i) {
      35              :     gsl::at(result, i) = gsl::at(lhs, i) + gsl::at(rhs, i);
      36              :   }
      37              :   return result;
      38              : }
      39              : 
      40              : template <size_t Dim, typename T, typename U>
      41            0 : inline constexpr std::array<T, Dim>& operator-=(std::array<T, Dim>& lhs,
      42              :                                                 const std::array<U, Dim>& rhs) {
      43              :   for (size_t i = 0; i < Dim; ++i) {
      44              :     gsl::at(lhs, i) -= gsl::at(rhs, i);
      45              :   }
      46              :   return lhs;
      47              : }
      48              : 
      49              : template <size_t Dim, typename T, typename U>
      50            0 : inline constexpr auto operator-(const std::array<T, Dim>& lhs,
      51              :                                 const std::array<U, Dim>& rhs)
      52              :     -> std::array<decltype(lhs[0] - rhs[0]), Dim> {
      53              :   std::array<decltype(lhs[0] - rhs[0]), Dim> result{};
      54              :   for (size_t i = 0; i < Dim; ++i) {
      55              :     gsl::at(result, i) = gsl::at(lhs, i) - gsl::at(rhs, i);
      56              :   }
      57              :   return result;
      58              : }
      59              : 
      60              : template <size_t Dim, typename T, typename U>
      61            0 : inline constexpr std::array<T, Dim>& operator*=(std::array<T, Dim>& lhs,
      62              :                                                 const U& scale) {
      63              :   for (size_t i = 0; i < Dim; ++i) {
      64              :     gsl::at(lhs, i) *= scale;
      65              :   }
      66              :   return lhs;
      67              : }
      68              : 
      69              : template <size_t Dim, typename T, typename U>
      70            0 : inline constexpr std::array<T, Dim> operator*(const std::array<T, Dim>& lhs,
      71              :                                               const U& scale) {
      72              :   std::array<T, Dim> result = lhs;
      73              :   result *= scale;
      74              :   return result;
      75              : }
      76              : 
      77              : template <size_t Dim, typename T, typename U>
      78            0 : inline constexpr std::array<T, Dim> operator*(const U& scale,
      79              :                                               const std::array<T, Dim>& rhs) {
      80              :   return rhs * scale;
      81              : }
      82              : 
      83              : template <size_t Dim, typename T, typename U>
      84            0 : inline constexpr std::array<T, Dim>& operator/=(std::array<T, Dim>& lhs,
      85              :                                                 const U& scale) {
      86              :   for (size_t i = 0; i < Dim; ++i) {
      87              :     gsl::at(lhs, i) /= scale;
      88              :   }
      89              :   return lhs;
      90              : }
      91              : 
      92              : template <size_t Dim, typename T, typename U>
      93            0 : inline constexpr std::array<T, Dim> operator/(const std::array<T, Dim>& lhs,
      94              :                                               const U& scale) {
      95              :   std::array<T, Dim> result = lhs;
      96              :   result /= scale;
      97              :   return result;
      98              : }
      99              : 
     100              : template <size_t Dim, typename T>
     101            0 : inline constexpr std::array<T, Dim> operator-(const std::array<T, Dim>& rhs) {
     102              :   std::array<T, Dim> result{};
     103              :   for (size_t i = 0; i < Dim; ++i) {
     104              :     gsl::at(result, i) = -gsl::at(rhs, i);
     105              :   }
     106              :   return result;
     107              : }
     108              : 
     109              : /// \ingroup UtilitiesGroup
     110              : /// \brief Construct an array from an existing array omitting one element
     111              : template <typename T, size_t Dim>
     112            1 : inline constexpr std::array<T, Dim - 1> all_but_specified_element_of(
     113              :     const std::array<T, Dim>& a, const size_t element_to_remove) {
     114              :   assert(element_to_remove < Dim);
     115              :   std::array<T, Dim - 1> result{};
     116              :   for (size_t i = 0; i < element_to_remove; ++i) {
     117              :     gsl::at(result, i) = gsl::at(a, i);
     118              :   }
     119              :   for (size_t i = element_to_remove + 1; i < Dim; ++i) {
     120              :     gsl::at(result, i - 1) = gsl::at(a, i);
     121              :   }
     122              :   return result;
     123              : }
     124              : 
     125              : /// \ingroup UtilitiesGroup
     126              : /// \brief Construct an array from an existing array adding one element
     127              : template <typename T, size_t Dim>
     128            1 : inline constexpr std::array<T, Dim + 1> insert_element(
     129              :     std::array<T, Dim> a, const size_t element_to_add, T value) {
     130              :   assert(element_to_add <= Dim);
     131              :   std::array<T, Dim + 1> result{};
     132              :   for (size_t i = 0; i < element_to_add; ++i) {
     133              :     gsl::at(result, i) = std::move(gsl::at(a, i));
     134              :   }
     135              :   gsl::at(result, element_to_add) = std::move(value);
     136              :   for (size_t i = element_to_add; i < Dim; ++i) {
     137              :     gsl::at(result, i + 1) = std::move(gsl::at(a, i));
     138              :   }
     139              :   return result;
     140              : }
     141              : 
     142              : /// \ingroup UtilitiesGroup
     143              : /// \brief Construct an array from an existing array prepending a value
     144              : template <typename T, size_t Dim>
     145            1 : inline constexpr std::array<T, Dim + 1> prepend(const std::array<T, Dim>& a,
     146              :                                                 T value) {
     147              :   std::array<T, Dim + 1> result{};
     148              :   gsl::at(result, 0) = std::move(value);
     149              :   for (size_t i = 0; i < Dim; ++i) {
     150              :     gsl::at(result, i + 1) = gsl::at(a, i);
     151              :   }
     152              :   return result;
     153              : }
     154              : 
     155              : /// \ingroup UtilitiesGroup
     156              : /// \brief Construct an array from the contents of two other arrays.
     157              : template <typename T, size_t Dim1, size_t Dim2>
     158            1 : constexpr std::array<T, Dim1 + Dim2> concatenate(std::array<T, Dim1> a,
     159              :                                                  std::array<T, Dim2> b) {
     160              :   std::array<T, Dim1 + Dim2> result{};
     161              :   for (size_t i = 0; i < Dim1; ++i) {
     162              :     gsl::at(result, i) = std::move(gsl::at(a, i));
     163              :   }
     164              :   for (size_t i = 0; i < Dim2; ++i) {
     165              :     gsl::at(result, i + Dim1) = std::move(gsl::at(b, i));
     166              :   }
     167              :   return result;
     168              : }
     169              : 
     170              : /// @{
     171              : /// \ingroup UtilitiesGroup
     172              : /// \brief Euclidean magnitude of the elements of the array.
     173              : ///
     174              : /// \details If T is a container the magnitude is computed separately for each
     175              : /// element of the container.
     176              : ///
     177              : /// \requires If T is a container, T must have following mathematical operators:
     178              : /// abs(), sqrt(), and element-wise addition and multiplication.  In addition,
     179              : /// each T in the array must have the same size.
     180              : template <typename T>
     181            1 : constexpr decltype(auto) magnitude(const std::array<T, 1>& a) {
     182              :   using std::abs;
     183              :   return abs(a[0]);
     184              : }
     185              : 
     186              : template <typename T>
     187            1 : constexpr decltype(auto) magnitude(const std::array<T, 2>& a) {
     188              :   return sqrt(a[0] * a[0] + a[1] * a[1]);
     189              : }
     190              : 
     191              : template <typename T>
     192            1 : constexpr decltype(auto) magnitude(const std::array<T, 3>& a) {
     193              :   return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
     194              : }
     195              : /// @}
     196              : /// @{
     197              : /// \ingroup UtilitiesGroup
     198              : /// \brief Dot product between two arrays
     199              : ///
     200              : /// \details This also works elementwise if T is a container and R is a float or
     201              : /// the other way round. The return type will always be the same as the return
     202              : /// type of the multiplication which may be a blaze expression template.
     203              : 
     204              : template <typename T, typename R>
     205            1 : constexpr decltype(auto) dot(const std::array<T, 1>& first,
     206              :                              const std::array<R, 1>& second) {
     207              :   return first[0] * second[0];
     208              : }
     209              : 
     210              : template <typename T, typename R>
     211            1 : constexpr decltype(auto) dot(const std::array<T, 2>& first,
     212              :                              const std::array<R, 2>& second) {
     213              :   return first[0] * second[0] + first[1] * second[1];
     214              : }
     215              : 
     216              : template <typename T, typename R>
     217            1 : constexpr decltype(auto) dot(const std::array<T, 3>& first,
     218              :                              const std::array<R, 3>& second) {
     219              :   return first[0] * second[0] + first[1] * second[1] + first[2] * second[2];
     220              : }
     221              : /// @}
     222              : 
     223              : namespace std_array_helpers_detail {
     224              : template <typename T, size_t Dim, typename F, size_t... Indices>
     225              : auto map_array_impl(const std::array<T, Dim>& array, const F& f,
     226              :                     const std::index_sequence<Indices...> /*meta*/) {
     227              :   return std::array<std::decay_t<decltype(f(std::declval<T>()))>, Dim>{
     228              :       {f(array[Indices])...}};
     229              : }
     230              : }  // namespace std_array_helpers_detail
     231              : 
     232              : /// \ingroup UtilitiesGroup
     233              : /// Applies a function to each element of an array, producing a new
     234              : /// array of the results.  The elements of the new array are
     235              : /// constructed in place, so they need not be default constructible.
     236              : template <typename T, size_t Dim, typename F>
     237            1 : auto map_array(const std::array<T, Dim>& array, const F& f) {
     238              :   return std_array_helpers_detail::map_array_impl(
     239              :       array, f, std::make_index_sequence<Dim>{});
     240              : }
     241              : 
     242              : /*!
     243              :  * \ingroup UtilitiesGroup
     244              :  * \brief Declares a binary function on an array, intended for binary
     245              :  * operators such as `+`
     246              :  *
     247              :  * \param RESULT_TYPE the `value_type` that is the result of the operation
     248              :  * (e.g. `A` for resulting `std::array<A,2>`)
     249              :  *
     250              :  * \param LTYPE the `value_type` of the first argument of the function (so the
     251              :  * left value if the function is an operator overload)
     252              :  *
     253              :  * \param RTYPE the `value_type` of the second argument of the function
     254              :  *
     255              :  * \param OP_FUNCTION_NAME the function which should be declared
     256              :  * (e.g. `operator+`)
     257              :  *
     258              :  * \param BINARY_OP the binary function which should be applied elementwise to
     259              :  * the pair of arrays. (e.g. `std::plus<>()`)
     260              :  */
     261              : // clang-tidy: complaints about uninitialized member, but the transform will set
     262              : // data
     263              : #define DEFINE_STD_ARRAY_BINOP(RESULT_TYPE, LTYPE, RTYPE, OP_FUNCTION_NAME,   \
     264            1 :                                BINARY_OP)                                     \
     265              :   template <size_t Dim>                                                       \
     266              :   std::array<RESULT_TYPE, Dim> OP_FUNCTION_NAME(                              \
     267              :       const std::array<LTYPE, Dim>& lhs, const std::array<RTYPE, Dim>& rhs) { \
     268              :     std::array<RESULT_TYPE, Dim> result; /*NOLINT*/                           \
     269              :     std::transform(lhs.begin(), lhs.end(), rhs.begin(), result.begin(),       \
     270              :                    BINARY_OP);                                                \
     271              :     return result;                                                            \
     272              :   }
     273              : 
     274              : /*!
     275              :  * \ingroup UtilitiesGroup
     276              :  * \brief Declares an in-place binary function on an array, intended for
     277              :  * operations such as `+=`
     278              :  *
     279              :  * \param LTYPE the `value_type` of the first argument of the function which is
     280              :  * also the result `value_tye` of the operation (so the left value if the
     281              :  * function is an operator overload)
     282              :  *
     283              :  * \param RTYPE the `value_type` of the second argument of the function
     284              :  *
     285              :  * \param OP_FUNCTION_NAME the function which should be declared
     286              :  * (e.g. `operator+=`)
     287              :  *
     288              :  * \param BINARY_OP the binary function which should be applied elementwise to
     289              :  * the pair of arrays. (e.g. `std::plus<>()`)
     290              :  */
     291              : #define DEFINE_STD_ARRAY_INPLACE_BINOP(LTYPE, RTYPE, OP_FUNCTION_NAME,  \
     292            1 :                                        BINARY_OP)                       \
     293              :   template <size_t Dim>                                                 \
     294              :   std::array<LTYPE, Dim>& OP_FUNCTION_NAME(                             \
     295              :       std::array<LTYPE, Dim>& lhs, const std::array<RTYPE, Dim>& rhs) { \
     296              :     std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(),    \
     297              :                    BINARY_OP);                                          \
     298              :     return lhs;                                                         \
     299              :   }
        

Generated by: LCOV version 2.0-1