SpECTRE Documentation Coverage Report
Current view: top level - DataStructures - MathWrapper.hpp Hit Total Coverage
Commit: ecb8a275e1aebab77dcce48a5e098ed4e486ab4b Lines: 19 45 42.2 %
Date: 2026-08-22 01:05:40
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 1.14