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