SpECTRE Documentation Coverage Report
Current view: top level - DataStructures - MathWrapper.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 42.2 % 45 19
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 <complex>
       8              : #include <cstddef>
       9              : #include <type_traits>
      10              : #include <utility>
      11              : 
      12              : #include "DataStructures/ComplexDataVector.hpp"
      13              : #include "DataStructures/DataVector.hpp"
      14              : #include "Utilities/Gsl.hpp"
      15              : #include "Utilities/TMPL.hpp"
      16              : 
      17              : /// \ingroup DataStructuresGroup
      18              : /// A comma-separated list of valid template arguments to MathWrapper.
      19              : /// Useful for explicit instantiations.
      20              : ///
      21              : /// \snippet Helpers/DataStructures/MathWrapperDetail.cpp MATH_WRAPPER_TYPES_instantiate
      22            1 : #define MATH_WRAPPER_TYPES \
      23              :   double, std::complex<double>, DataVector, ComplexDataVector
      24              : 
      25              : /// \ingroup DataStructuresGroup
      26              : /// Type-erased data for performing math on.
      27              : ///
      28              : /// This class can only be instantiated with possibly const-qualified
      29              : /// types from \ref MATH_WRAPPER_TYPES, which can be assumed to
      30              : /// support the mathematical operations of a linear-algebra vector.
      31              : /// Instances of this class with those template arguments can be
      32              : /// created using overloads of `make_math_wrapper` (passing a `const
      33              : /// T&` for const versions and a `gsl::not_null<T*>` for mutable
      34              : /// versions).  Other data structures (such as `Variables`) can add
      35              : /// additional overloads implemented on top of these basic ones.
      36              : ///
      37              : /// \snippet Test_MathWrapper.cpp MathWrapper
      38              : template <typename T>
      39            1 : class MathWrapper {
      40              :  private:
      41            0 :   using MutableT = std::remove_const_t<T>;
      42              : 
      43              :   static_assert(
      44              :       tmpl::list_contains_v<tmpl::list<MATH_WRAPPER_TYPES>, MutableT>);
      45              : 
      46              :   template <typename U = T,
      47              :             bool IsVector =
      48              :                 not(std::is_same_v<std::decay_t<T>, double> or
      49              :                     std::is_same_v<std::decay_t<T>, std::complex<double>>),
      50              :             bool IsConst = std::is_const_v<T>>
      51            0 :   struct Impl {
      52            0 :     using scalar_type = std::remove_const_t<U>;
      53            0 :     T& data;
      54            0 :     Impl(const gsl::not_null<T*> data_in) : data(*data_in) {}
      55              :   };
      56              : 
      57              :   template <typename U>
      58            0 :   struct Impl<U, true, false> {
      59            0 :     using scalar_type = typename U::value_type;
      60              :     // NOLINTNEXTLINE(spectre-mutable)
      61            0 :     mutable T data;
      62            0 :     Impl(const gsl::not_null<T*> data_in) : data(std::move(*data_in)) {}
      63              :   };
      64              : 
      65              :   template <typename U>
      66            0 :   struct Impl<U, true, true> {
      67            0 :     using scalar_type = typename U::value_type;
      68            0 :     const T data;
      69              :     // Need to invoke the move-from-mutable constructor on DataVector, etc.
      70            0 :     Impl(const gsl::not_null<MutableT*> data_in) : data(std::move(*data_in)) {}
      71              :   };
      72              : 
      73            0 :   explicit MathWrapper(const gsl::not_null<MutableT*> data) : data_(data) {}
      74              : 
      75            0 :   friend MathWrapper<T> make_math_wrapper(
      76              :       tmpl::conditional_t<std::is_const_v<T>, T&, gsl::not_null<T*>>);
      77              : 
      78              :  public:
      79              :   /// The class's template parameter.
      80            1 :   using value_type = T;
      81              :   /// Scalar type for linear-algebra operations.  Either double or
      82              :   /// std::complex<double>.
      83            1 :   using scalar_type = typename Impl<>::scalar_type;
      84              : 
      85            0 :   T& operator*() const { return data_.data; }
      86            0 :   T* operator->() const { return &data_.data; }
      87              : 
      88            0 :   MathWrapper(MathWrapper&&) = default;
      89              : 
      90            0 :   MathWrapper() = delete;
      91            0 :   MathWrapper(const MathWrapper&) = delete;
      92            0 :   MathWrapper& operator=(const MathWrapper&) = delete;
      93            0 :   MathWrapper& operator=(MathWrapper&&) = delete;
      94              : 
      95              :   /// Convert MathWrapper wrapping a mutable value to one wrapping a
      96              :   /// const one.
      97              :   ///
      98              :   /// These methods will fail to compile if called on a MathWrapper
      99              :   /// wrapping a const value.  The `to_const` method is useful because
     100              :   /// C++ fails to resolve the implicit conversion in many cases.
     101              :   /// @{
     102            1 :   operator MathWrapper<const T>() const;
     103              : 
     104            1 :   MathWrapper<const T> to_const() const {
     105              :     return static_cast<MathWrapper<const T>>(*this);
     106              :   }
     107              :   /// @}
     108              : 
     109              :  private:
     110            0 :   Impl<> data_;
     111              : };
     112              : 
     113              : /// \ingroup DataStructuresGroup
     114              : /// A fundamental overload of the MathWrapper construction functions.
     115              : ///
     116              : /// Additional overloads can be implemented in terms of the
     117              : /// fundamental overloads.
     118              : /// @{
     119            1 : inline MathWrapper<double> make_math_wrapper(
     120              :     const gsl::not_null<double*> data) {
     121              :   return MathWrapper<double>(data);
     122              : }
     123              : 
     124            1 : inline MathWrapper<const double> make_math_wrapper(const double& data) {
     125              :   return MathWrapper<const double>(const_cast<double*>(&data));
     126              : }
     127              : 
     128            1 : inline MathWrapper<std::complex<double>> make_math_wrapper(
     129              :     const gsl::not_null<std::complex<double>*> data) {
     130              :   return MathWrapper<std::complex<double>>(data);
     131              : }
     132              : 
     133            1 : inline MathWrapper<const std::complex<double>> make_math_wrapper(
     134              :     const std::complex<double>& data) {
     135              :   return MathWrapper<const std::complex<double>>(
     136              :       const_cast<std::complex<double>*>(&data));
     137              : }
     138              : 
     139            1 : inline MathWrapper<DataVector> make_math_wrapper(
     140              :     const gsl::not_null<DataVector*> data) {
     141              :   if (UNLIKELY(data->size() == 0)) {
     142              :     DataVector empty{};
     143              :     return MathWrapper<DataVector>(&empty);
     144              :   }
     145              :   DataVector referencing(data->data(), data->size());
     146              :   return MathWrapper<DataVector>(&referencing);
     147              : }
     148              : 
     149            1 : inline MathWrapper<const DataVector> make_math_wrapper(const DataVector& data) {
     150              :   if (UNLIKELY(data.size() == 0)) {
     151              :     DataVector empty{};
     152              :     return MathWrapper<const DataVector>(&empty);
     153              :   }
     154              :   DataVector referencing(const_cast<double*>(data.data()), data.size());
     155              :   return MathWrapper<const DataVector>(&referencing);
     156              : }
     157              : 
     158            1 : inline MathWrapper<ComplexDataVector> make_math_wrapper(
     159              :     const gsl::not_null<ComplexDataVector*> data) {
     160              :   if (UNLIKELY(data->size() == 0)) {
     161              :     ComplexDataVector empty{};
     162              :     return MathWrapper<ComplexDataVector>(&empty);
     163              :   }
     164              :   ComplexDataVector referencing(data->data(), data->size());
     165              :   return MathWrapper<ComplexDataVector>(&referencing);
     166              : }
     167              : 
     168            1 : inline MathWrapper<const ComplexDataVector> make_math_wrapper(
     169              :     const ComplexDataVector& data) {
     170              :   if (UNLIKELY(data.size() == 0)) {
     171              :     ComplexDataVector empty{};
     172              :     return MathWrapper<const ComplexDataVector>(&empty);
     173              :   }
     174              :   ComplexDataVector referencing(const_cast<std::complex<double>*>(data.data()),
     175              :                                 data.size());
     176              :   return MathWrapper<const ComplexDataVector>(&referencing);
     177              : }
     178              : /// @}
     179              : 
     180              : template <typename T>
     181              : MathWrapper<T>::operator MathWrapper<const T>() const {
     182              :   return make_math_wrapper(data_.data);
     183              : }
     184              : 
     185              : template <typename T, size_t N>
     186            0 : auto make_math_wrapper(const gsl::not_null<std::array<T, N>*> array) {
     187              :   DataVector referencing(array->data(), array->size());
     188              :   return make_math_wrapper(&referencing);
     189              : }
     190              : 
     191              : template <typename T, size_t N>
     192            0 : auto make_math_wrapper(const std::array<T, N>& array) {
     193              :   const DataVector referencing(const_cast<double*>(array.data()), array.size());
     194              :   return make_math_wrapper(referencing);
     195              : }
     196              : 
     197              : /// \ingroup DataStructuresGroup
     198              : /// The `value_type` for a MathWrapper wrapping `T`.
     199              : template <typename T>
     200            1 : using math_wrapper_type = typename decltype(make_math_wrapper(
     201              :     std::declval<tmpl::conditional_t<std::is_const_v<T>, const T&,
     202              :                                      gsl::not_null<T*>>>()))::value_type;
     203              : 
     204              : /// \ingroup DataStructuresGroup
     205              : /// A fundamental overload for owning type-erasure.  Returns its argument
     206              : /// unchanged.
     207              : ///
     208              : /// Additional overloads should always return the `math_wrapper_type`
     209              : /// of their argument, and should be implemented to avoid allocations
     210              : /// and copying whenever possible.
     211              : /// @{
     212            1 : inline double into_math_wrapper_type(double&& data) { return data; }
     213              : 
     214            1 : inline std::complex<double> into_math_wrapper_type(
     215              :     std::complex<double>&& data) {
     216              :   return data;
     217              : }
     218              : 
     219            1 : inline DataVector into_math_wrapper_type(DataVector&& data) {
     220              :   return std::move(data);
     221              : }
     222              : 
     223            1 : inline ComplexDataVector into_math_wrapper_type(ComplexDataVector&& data) {
     224              :   return std::move(data);
     225              : }
     226              : /// @}
        

Generated by: LCOV version 2.0-1