Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : ///\file 5 : /// Defines make_with_value 6 : 7 : #pragma once 8 : 9 : #include <array> 10 : #include <complex> 11 : #include <functional> 12 : #include <type_traits> 13 : #include <vector> 14 : 15 : #include "Utilities/Algorithm.hpp" 16 : #include "Utilities/ErrorHandling/Assert.hpp" 17 : #include "Utilities/ForceInline.hpp" 18 : #include "Utilities/MakeArray.hpp" 19 : 20 : /// \ingroup DataStructuresGroup 21 : /// Implementations of make_with_value. 22 : namespace MakeWithValueImpls { 23 : /// Defines a method for determining the number of points represented 24 : /// by an object. This allows the object to appear as the input to 25 : /// make_with_value. 26 : /// 27 : /// The MakeWithValueImpls::number_of_points convenience wrapper is 28 : /// provided to simplify calling this. 29 : template <typename T, typename = std::nullptr_t> 30 1 : struct NumberOfPoints { 31 : /// The default implementation will produce a compile-time error. 32 1 : [[noreturn]] static SPECTRE_ALWAYS_INLINE size_t apply(const T& /*input*/) { 33 : static_assert(typename tmpl::has_type<T, std::false_type>::type{}, 34 : "Do not know how to obtain a size from this type. Either " 35 : "implement NumberOfPoints or specialize MakeWithValueImpl " 36 : "for the type you are trying to create."); 37 : } 38 : }; 39 : 40 : /// The number of points represented by an object. 41 : template <typename T> 42 1 : size_t number_of_points(const T& input) { 43 : return NumberOfPoints<T>::apply(input); 44 : } 45 : 46 : /// Defines a method for producing an object representing a given 47 : /// number of points. 48 : /// 49 : /// Do not call these functions directly. Use make_with_value 50 : /// instead, which can take a size as its first argument. 51 : template <typename R, typename = std::nullptr_t> 52 1 : struct MakeWithSize { 53 : /// The default implementation will produce a compile-time error. 54 : /// In specializations, the \p value parameter need not be a template. 55 : template <typename T> 56 1 : [[noreturn]] static SPECTRE_ALWAYS_INLINE R apply(const size_t /*size*/, 57 : const T& /*value*/) { 58 : static_assert(typename tmpl::has_type<R, std::false_type>::type{}, 59 : "Do not know how to create a sized object of this type. " 60 : "Either implement MakeWithSize or specialize " 61 : "MakeWithValueImpl for the type you are trying to create."); 62 : } 63 : }; 64 : 65 : template <typename R, typename T, typename = std::nullptr_t> 66 0 : struct MakeWithValueImpl { 67 : /// The default implementation uses \ref number_of_points and MakeWithSize. 68 : template <typename ValueType> 69 1 : static SPECTRE_ALWAYS_INLINE R apply(const T& input, const ValueType value) { 70 : return MakeWithSize<R>::apply(number_of_points(input), value); 71 : } 72 : }; 73 : } // namespace MakeWithValueImpls 74 : 75 : /// \ingroup DataStructuresGroup 76 : /// \brief Given an object of type `T`, create an object of type `R` whose 77 : /// elements are initialized to `value`. 78 : /// 79 : /// \details This function is useful in function templates in order to 80 : /// initialize the return type of a function template with `value` for functions 81 : /// that can be called either at a single grid-point or to fill a data structure 82 : /// at the same set of grid-points as the `input` 83 : 84 : /// \tparam ValueType The type of `value`. For most containers, this will be 85 : /// `double`. 86 : /// 87 : /// \see MakeWithValueImpls, set_number_of_grid_points 88 : template <typename R, typename T, typename ValueType> 89 1 : SPECTRE_ALWAYS_INLINE std::remove_const_t<R> make_with_value( 90 : const T& input, const ValueType& value) { 91 : return MakeWithValueImpls::MakeWithValueImpl<std::remove_const_t<R>, 92 : T>::apply(input, value); 93 : } 94 : 95 : namespace MakeWithValueImpls { 96 : template <> 97 0 : struct NumberOfPoints<size_t> { 98 0 : static SPECTRE_ALWAYS_INLINE size_t apply(const size_t& input) { 99 : return input; 100 : } 101 : }; 102 : 103 : /// \brief Returns a double initialized to `value` (`input` is ignored) 104 : template <typename T> 105 1 : struct MakeWithValueImpl<double, T> { 106 0 : static SPECTRE_ALWAYS_INLINE double apply(const T& /* input */, 107 : const double value) { 108 : return value; 109 : } 110 : }; 111 : 112 : template <typename T> 113 : struct MakeWithValueImpl<std::complex<double>, T> { 114 : static SPECTRE_ALWAYS_INLINE std::complex<double> apply( 115 : const T& /* input */, const std::complex<double> value) { 116 : return value; 117 : } 118 : }; 119 : 120 : /// \brief Makes a `std::array`; each element of the `std::array` 121 : /// must be `make_with_value`-creatable from a `InputType`. 122 : template <size_t Size, typename T, typename InputType> 123 : struct MakeWithValueImpl<std::array<T, Size>, InputType> { 124 : template <typename ValueType> 125 : static SPECTRE_ALWAYS_INLINE std::array<T, Size> apply( 126 : const InputType& input, const ValueType value) { 127 : return make_array<Size>(make_with_value<T>(input, value)); 128 : } 129 : }; 130 : 131 : template <size_t Size, typename T> 132 : struct NumberOfPoints<std::array<T, Size>> { 133 : static SPECTRE_ALWAYS_INLINE size_t apply(const std::array<T, Size>& input) { 134 : static_assert(Size > 0); 135 : // size_t is interpreted as the number of points in other 136 : // contexts, but that doesn't make sense here. 137 : static_assert(not std::is_same_v<T, size_t>, 138 : "Cannot get size from non-vector."); 139 : const size_t points = number_of_points(input[0]); 140 : ASSERT( 141 : alg::all_of(input, 142 : [&](const T& t) { return number_of_points(t) == points; }), 143 : "Inconsistent number of points in array entries."); 144 : return points; 145 : } 146 : }; 147 : 148 : template <typename T> 149 : struct NumberOfPoints<std::vector<T>> { 150 : static SPECTRE_ALWAYS_INLINE size_t apply(const std::vector<T>& input) { 151 : // size_t is interpreted as the number of points in other 152 : // contexts, but that doesn't make sense here. 153 : static_assert(not std::is_same_v<T, size_t>, 154 : "Cannot get number_of_points from non-vector."); 155 : ASSERT(not input.empty(), 156 : "Cannot get number of points from empty std::vector."); 157 : const size_t points = number_of_points(input[0]); 158 : ASSERT( 159 : alg::all_of(input, 160 : [&](const T& t) { return number_of_points(t) == points; }), 161 : "Inconsistent number of points in vector entries."); 162 : return points; 163 : } 164 : }; 165 : 166 : template <typename T> 167 : struct NumberOfPoints<std::reference_wrapper<T>> { 168 : static SPECTRE_ALWAYS_INLINE size_t apply( 169 : const std::reference_wrapper<T>& input) { 170 : return number_of_points(input.get()); 171 : } 172 : }; 173 : 174 : } // namespace MakeWithValueImpls