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