SpECTRE Documentation Coverage Report
Current view: top level - DataStructures - MathWrapper.hpp Hit Total Coverage
Commit: 1e29a35ad8559408f21493dc5db8a49a237bb2f0 Lines: 19 44 43.2 %
Date: 2026-03-31 22:27:51
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             : 
      87           0 :   MathWrapper(MathWrapper&&) = default;
      88             : 
      89           0 :   MathWrapper() = delete;
      90           0 :   MathWrapper(const MathWrapper&) = delete;
      91           0 :   MathWrapper& operator=(const MathWrapper&) = delete;
      92           0 :   MathWrapper& operator=(MathWrapper&&) = delete;
      93             : 
      94             :   /// Convert MathWrapper wrapping a mutable value to one wrapping a
      95             :   /// const one.
      96             :   ///
      97             :   /// These methods will fail to compile if called on a MathWrapper
      98             :   /// wrapping a const value.  The `to_const` method is useful because
      99             :   /// C++ fails to resolve the implicit conversion in many cases.
     100             :   /// @{
     101           1 :   operator MathWrapper<const T>() const;
     102             : 
     103           1 :   MathWrapper<const T> to_const() const {
     104             :     return static_cast<MathWrapper<const T>>(*this);
     105             :   }
     106             :   /// @}
     107             : 
     108             :  private:
     109           0 :   Impl<> data_;
     110             : };
     111             : 
     112             : /// \ingroup DataStructuresGroup
     113             : /// A fundamental overload of the MathWrapper construction functions.
     114             : ///
     115             : /// Additional overloads can be implemented in terms of the
     116             : /// fundamental overloads.
     117             : /// @{
     118           1 : inline MathWrapper<double> make_math_wrapper(
     119             :     const gsl::not_null<double*> data) {
     120             :   return MathWrapper<double>(data);
     121             : }
     122             : 
     123           1 : inline MathWrapper<const double> make_math_wrapper(const double& data) {
     124             :   return MathWrapper<const double>(const_cast<double*>(&data));
     125             : }
     126             : 
     127           1 : inline MathWrapper<std::complex<double>> make_math_wrapper(
     128             :     const gsl::not_null<std::complex<double>*> data) {
     129             :   return MathWrapper<std::complex<double>>(data);
     130             : }
     131             : 
     132           1 : inline MathWrapper<const std::complex<double>> make_math_wrapper(
     133             :     const std::complex<double>& data) {
     134             :   return MathWrapper<const std::complex<double>>(
     135             :       const_cast<std::complex<double>*>(&data));
     136             : }
     137             : 
     138           1 : inline MathWrapper<DataVector> make_math_wrapper(
     139             :     const gsl::not_null<DataVector*> data) {
     140             :   DataVector referencing(data->data(), data->size());
     141             :   return MathWrapper<DataVector>(&referencing);
     142             : }
     143             : 
     144           1 : inline MathWrapper<const DataVector> make_math_wrapper(const DataVector& data) {
     145             :   DataVector referencing(const_cast<double*>(data.data()), data.size());
     146             :   return MathWrapper<const DataVector>(&referencing);
     147             : }
     148             : 
     149           1 : inline MathWrapper<ComplexDataVector> make_math_wrapper(
     150             :     const gsl::not_null<ComplexDataVector*> data) {
     151             :   ComplexDataVector referencing(data->data(), data->size());
     152             :   return MathWrapper<ComplexDataVector>(&referencing);
     153             : }
     154             : 
     155           1 : inline MathWrapper<const ComplexDataVector> make_math_wrapper(
     156             :     const ComplexDataVector& data) {
     157             :   ComplexDataVector referencing(const_cast<std::complex<double>*>(data.data()),
     158             :                                 data.size());
     159             :   return MathWrapper<const ComplexDataVector>(&referencing);
     160             : }
     161             : /// @}
     162             : 
     163             : template <typename T>
     164             : MathWrapper<T>::operator MathWrapper<const T>() const {
     165             :   return make_math_wrapper(data_.data);
     166             : }
     167             : 
     168             : template <typename T, size_t N>
     169           0 : auto make_math_wrapper(const gsl::not_null<std::array<T, N>*> array) {
     170             :   DataVector referencing(array->data(), array->size());
     171             :   return make_math_wrapper(&referencing);
     172             : }
     173             : 
     174             : template <typename T, size_t N>
     175           0 : auto make_math_wrapper(const std::array<T, N>& array) {
     176             :   const DataVector referencing(const_cast<double*>(array.data()), array.size());
     177             :   return make_math_wrapper(referencing);
     178             : }
     179             : 
     180             : /// \ingroup DataStructuresGroup
     181             : /// The `value_type` for a MathWrapper wrapping `T`.
     182             : template <typename T>
     183           1 : using math_wrapper_type = typename decltype(make_math_wrapper(
     184             :     std::declval<tmpl::conditional_t<std::is_const_v<T>, const T&,
     185             :                                      gsl::not_null<T*>>>()))::value_type;
     186             : 
     187             : /// \ingroup DataStructuresGroup
     188             : /// A fundamental overload for owning type-erasure.  Returns its argument
     189             : /// unchanged.
     190             : ///
     191             : /// Additional overloads should always return the `math_wrapper_type`
     192             : /// of their argument, and should be implemented to avoid allocations
     193             : /// and copying whenever possible.
     194             : /// @{
     195           1 : inline double into_math_wrapper_type(double&& data) { return data; }
     196             : 
     197           1 : inline std::complex<double> into_math_wrapper_type(
     198             :     std::complex<double>&& data) {
     199             :   return data;
     200             : }
     201             : 
     202           1 : inline DataVector into_math_wrapper_type(DataVector&& data) {
     203             :   return std::move(data);
     204             : }
     205             : 
     206           1 : inline ComplexDataVector into_math_wrapper_type(ComplexDataVector&& data) {
     207             :   return std::move(data);
     208             : }
     209             : /// @}

Generated by: LCOV version 1.14