Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details
3 :
4 : #pragma once
5 :
6 : #include "DataStructures/ComplexDataVector.hpp"
7 : #include "Utilities/ForceInline.hpp"
8 : #include "Utilities/Requires.hpp"
9 : #include "Utilities/SetNumberOfGridPoints.hpp"
10 : #include "Utilities/TypeTraits.hpp"
11 :
12 : /// @{
13 : /*!
14 : * \ingroup DataStructuresGroup
15 : * \brief Make a spin-weighted type `T` with spin-weight `Spin`. Mathematical
16 : * operators are restricted to addition, subtraction, multiplication and
17 : * division, with spin-weights checked for validity.
18 : *
19 : * \details For a spin-weighted object, we limit operations to those valid for a
20 : * pair of spin-weighted quantities - i.e. addition only makes sense when the
21 : * two summands possess the same spin weight, and multiplication (or division)
22 : * result in a summed (or subtracted) spin weight.
23 : */
24 : template <typename T, int Spin, bool is_vector = is_derived_of_vector_impl_v<T>>
25 1 : struct SpinWeighted;
26 :
27 : template <typename T, int Spin>
28 0 : struct SpinWeighted<T, Spin, false> {
29 0 : using value_type = T;
30 0 : constexpr static int spin = Spin;
31 :
32 0 : SpinWeighted() = default;
33 0 : SpinWeighted(const SpinWeighted&) = default;
34 0 : SpinWeighted(SpinWeighted&&) = default;
35 0 : SpinWeighted& operator=(const SpinWeighted&) = default;
36 0 : SpinWeighted& operator=(SpinWeighted&&) = default;
37 0 : ~SpinWeighted() = default;
38 :
39 : // clang-tidy asks that these be marked explicit, but we actually do not want
40 : // them explicit for use in the math operations below.
41 : template <typename Rhs>
42 0 : SpinWeighted(const SpinWeighted<Rhs, Spin>& rhs) // NOLINT
43 : : data_{rhs.data()} {}
44 :
45 : template <typename Rhs>
46 0 : SpinWeighted(SpinWeighted<Rhs, Spin>&& rhs) // NOLINT
47 : : data_{std::move(rhs.data())} {}
48 :
49 0 : SpinWeighted(const T& rhs) : data_{rhs} {} // NOLINT
50 0 : SpinWeighted(T&& rhs) : data_{std::move(rhs)} {} // NOLINT
51 0 : explicit SpinWeighted(const size_t size) : data_{size} {}
52 : template <typename U>
53 0 : SpinWeighted(const size_t size, const U& val) : data_{size, val} {}
54 :
55 : template <typename Rhs>
56 0 : SpinWeighted& operator=(const SpinWeighted<Rhs, Spin>& rhs) {
57 : data_ = rhs.data();
58 : return *this;
59 : }
60 :
61 : template <typename Rhs>
62 0 : SpinWeighted& operator=(SpinWeighted<Rhs, Spin>&& rhs) {
63 : data_ = std::move(rhs.data());
64 : return *this;
65 : }
66 :
67 0 : SpinWeighted& operator=(const T& rhs) {
68 : data_ = rhs;
69 : return *this;
70 : }
71 0 : SpinWeighted& operator=(T&& rhs) {
72 : data_ = std::move(rhs);
73 : return *this;
74 : }
75 :
76 : template <typename Rhs>
77 0 : auto& operator+=(const SpinWeighted<Rhs, Spin>& rhs) {
78 : data_ += rhs.data();
79 : return *this;
80 : }
81 :
82 0 : auto& operator+=(const T& rhs) {
83 : data_ += rhs;
84 : return *this;
85 : }
86 :
87 : template <typename Rhs>
88 0 : auto& operator-=(const SpinWeighted<Rhs, Spin>& rhs) {
89 : data_ -= rhs.data();
90 : return *this;
91 : }
92 :
93 0 : auto& operator-=(const T& rhs) {
94 : data_ -= rhs;
95 : return *this;
96 : }
97 :
98 0 : T& data() { return data_; }
99 0 : const T& data() const { return data_; }
100 :
101 0 : size_t size() const { return data_.size(); }
102 :
103 : /// Serialization for Charm++
104 : // NOLINTNEXTLINE(google-runtime-references)
105 1 : void pup(PUP::er& p);
106 :
107 : private:
108 0 : T data_;
109 : };
110 :
111 : template <typename T, int Spin>
112 0 : struct SpinWeighted<T, Spin, true> {
113 0 : using value_type = T;
114 0 : constexpr static int spin = Spin;
115 :
116 0 : void set_data_ref(const gsl::not_null<T*> rhs) { data_.set_data_ref(rhs); }
117 :
118 : // needed for invoking the check in `Variables.hpp` that ensures that
119 : // default-constructed `Variables` are never used.
120 0 : void set_data_ref(const std::nullptr_t null, const size_t size) {
121 : data_.set_data_ref(null, size);
122 : }
123 :
124 0 : void set_data_ref(const gsl::not_null<SpinWeighted<T, spin>*> rhs) {
125 : data_.set_data_ref(make_not_null(&(rhs->data_)));
126 : }
127 :
128 : template <typename ValueType>
129 0 : void set_data_ref(ValueType* const start, const size_t set_size) {
130 : data_.set_data_ref(start, set_size);
131 : }
132 :
133 0 : void destructive_resize(const size_t new_size) {
134 : data_.destructive_resize(new_size);
135 : }
136 :
137 0 : SpinWeighted() = default;
138 0 : SpinWeighted(const SpinWeighted&) = default;
139 0 : SpinWeighted(SpinWeighted&&) = default;
140 0 : SpinWeighted& operator=(const SpinWeighted&) = default;
141 0 : SpinWeighted& operator=(SpinWeighted&&) = default;
142 0 : ~SpinWeighted() = default;
143 :
144 : // clang-tidy asks that these be marked explicit, but we actually do not want
145 : // them explicit for use in the math operations below.
146 : template <typename Rhs>
147 0 : SpinWeighted(const SpinWeighted<Rhs, Spin>& rhs) // NOLINT
148 : : data_{rhs.data()} {}
149 :
150 : template <typename Rhs>
151 0 : SpinWeighted(SpinWeighted<Rhs, Spin>&& rhs) // NOLINT
152 : : data_{std::move(rhs.data())} {}
153 :
154 0 : SpinWeighted(const T& rhs) : data_{rhs} {} // NOLINT
155 0 : SpinWeighted(T&& rhs) : data_{std::move(rhs)} {} // NOLINT
156 0 : explicit SpinWeighted(const size_t size) : data_{size} {}
157 : template <typename U>
158 0 : SpinWeighted(const size_t size, const U& val) : data_{size, val} {}
159 :
160 : template <typename Rhs>
161 0 : SpinWeighted& operator=(const SpinWeighted<Rhs, Spin>& rhs) {
162 : data_ = rhs.data();
163 : return *this;
164 : }
165 :
166 : template <typename Rhs>
167 0 : SpinWeighted& operator=(SpinWeighted<Rhs, Spin>&& rhs) {
168 : data_ = std::move(rhs.data());
169 : return *this;
170 : }
171 :
172 0 : SpinWeighted& operator=(const T& rhs) {
173 : data_ = rhs;
174 : return *this;
175 : }
176 0 : SpinWeighted& operator=(T&& rhs) {
177 : data_ = std::move(rhs);
178 : return *this;
179 : }
180 :
181 : template <typename Rhs>
182 0 : auto& operator+=(const SpinWeighted<Rhs, Spin>& rhs) {
183 : data_ += rhs.data();
184 : return *this;
185 : }
186 :
187 0 : auto& operator+=(const T& rhs) {
188 : data_ += rhs;
189 : return *this;
190 : }
191 :
192 : template <typename Rhs>
193 0 : auto& operator-=(const SpinWeighted<Rhs, Spin>& rhs) {
194 : data_ -= rhs.data();
195 : return *this;
196 : }
197 :
198 0 : auto& operator-=(const T& rhs) {
199 : data_ -= rhs;
200 : return *this;
201 : }
202 :
203 0 : T& data() { return data_; }
204 0 : const T& data() const { return data_; }
205 :
206 0 : size_t size() const { return data_.size(); }
207 :
208 : /// Serialization for Charm++
209 : // NOLINTNEXTLINE(google-runtime-references)
210 1 : void pup(PUP::er& p);
211 :
212 : private:
213 0 : T data_;
214 : };
215 : /// @}
216 :
217 : template <typename T, int Spin>
218 : void SpinWeighted<T, Spin, true>::pup(PUP::er& p) {
219 : p | data_;
220 : }
221 :
222 : template <typename T, int Spin>
223 : void SpinWeighted<T, Spin, false>::pup(PUP::er& p) {
224 : p | data_;
225 : }
226 :
227 : /// @{
228 : /// \ingroup TypeTraitsGroup
229 : /// \ingroup DataStructuresGroup
230 : /// This is a `std::true_type` if the provided type is a `SpinWeighted` of any
231 : /// type and spin, otherwise is a `std::false_type`.
232 : template <typename T>
233 1 : struct is_any_spin_weighted : std::false_type {};
234 :
235 : template <typename T, int S>
236 0 : struct is_any_spin_weighted<SpinWeighted<T, S>> : std::true_type {};
237 : /// @}
238 :
239 : template <typename T>
240 0 : constexpr bool is_any_spin_weighted_v = is_any_spin_weighted<T>::value;
241 :
242 : /// @{
243 : /// \ingroup TypeTraitsGroup
244 : /// \ingroup DataStructuresGroup
245 : /// This is a `std::true_type` if the provided type `T` is a `SpinWeighted` of
246 : /// `InternalType` and any spin, otherwise is a `std::false_type`.
247 : template <typename InternalType, typename T>
248 1 : struct is_spin_weighted_of : std::false_type {};
249 :
250 : template <typename InternalType, int S>
251 0 : struct is_spin_weighted_of<InternalType, SpinWeighted<InternalType, S>>
252 : : std::true_type {};
253 : /// @}
254 :
255 : template <typename InternalType, typename T>
256 0 : constexpr bool is_spin_weighted_of_v =
257 : is_spin_weighted_of<InternalType, T>::value;
258 :
259 : /// @{
260 : /// \ingroup TypeTraitsGroup
261 : /// \ingroup DataStructuresGroup
262 : /// This is a `std::true_type` if the provided type `T1` is a `SpinWeighted` and
263 : /// `T2` is a `SpinWeighted`, and both have the same internal type, but any
264 : /// combination of spin weights.
265 : template <typename T1, typename T2>
266 1 : struct is_spin_weighted_of_same_type : std::false_type {};
267 :
268 : template <typename T, int Spin1, int Spin2>
269 0 : struct is_spin_weighted_of_same_type<SpinWeighted<T, Spin1>,
270 : SpinWeighted<T, Spin2>> : std::true_type {
271 : };
272 : /// @}
273 :
274 : template <typename T1, typename T2>
275 0 : constexpr bool is_spin_weighted_of_same_type_v =
276 : is_spin_weighted_of_same_type<T1, T2>::value;
277 :
278 : /// @{
279 : /// \brief Add two spin-weighted quantities if the types are compatible and
280 : /// spins are the same. Un-weighted quantities are assumed to be spin 0.
281 : // These overloads are designed to allow SpinWeighted to wrap Blaze expression
282 : // templates to ensure efficient math operations, necessitating the
283 : // `decltype(declval<T>() ...` syntax
284 : template <typename T1, typename T2, int Spin>
285 : SPECTRE_ALWAYS_INLINE
286 : SpinWeighted<decltype(std::declval<T1>() + std::declval<T2>()), Spin>
287 1 : operator+(const SpinWeighted<T1, Spin>& lhs,
288 : const SpinWeighted<T2, Spin>& rhs) {
289 : return {lhs.data() + rhs.data()};
290 : }
291 : template <typename T>
292 : SPECTRE_ALWAYS_INLINE
293 : SpinWeighted<decltype(std::declval<T>() + std::declval<T>()), 0>
294 1 : operator+(const SpinWeighted<T, 0>& lhs, const T& rhs) {
295 : return {lhs.data() + rhs};
296 : }
297 : template <typename T>
298 : SPECTRE_ALWAYS_INLINE SpinWeighted<
299 : decltype(std::declval<T>() + std::declval<get_vector_element_type_t<T>>()),
300 : 0>
301 1 : operator+(const SpinWeighted<T, 0>& lhs,
302 : const get_vector_element_type_t<T>& rhs) {
303 : return {lhs.data() + rhs};
304 : }
305 : template <typename T>
306 : SPECTRE_ALWAYS_INLINE
307 : SpinWeighted<decltype(std::declval<T>() + std::declval<T>()), 0>
308 1 : operator+(const T& lhs, const SpinWeighted<T, 0>& rhs) {
309 : return {lhs + rhs.data()};
310 : }
311 : template <typename T>
312 : SPECTRE_ALWAYS_INLINE SpinWeighted<
313 : decltype(std::declval<get_vector_element_type_t<T>>() + std::declval<T>()),
314 : 0>
315 1 : operator+(const get_vector_element_type_t<T>& lhs,
316 : const SpinWeighted<T, 0>& rhs) {
317 : return {lhs + rhs.data()};
318 : }
319 : /// @}
320 :
321 : /// @{
322 : /// \brief Subtract two spin-weighted quantities if the types are compatible and
323 : /// spins are the same. Un-weighted quantities are assumed to be spin 0.
324 : // These overloads are designed to allow SpinWeighted to wrap Blaze expression
325 : // templates to ensure efficient math operations, necessitating the
326 : // `decltype(declval<T>() ...` syntax
327 : template <typename T1, typename T2, int Spin>
328 : SPECTRE_ALWAYS_INLINE
329 : SpinWeighted<decltype(std::declval<T1>() - std::declval<T2>()), Spin>
330 1 : operator-(const SpinWeighted<T1, Spin>& lhs,
331 : const SpinWeighted<T2, Spin>& rhs) {
332 : return {lhs.data() - rhs.data()};
333 : }
334 : template <typename T>
335 : SPECTRE_ALWAYS_INLINE
336 : SpinWeighted<decltype(std::declval<T>() - std::declval<T>()), 0>
337 1 : operator-(const SpinWeighted<T, 0>& lhs, const T& rhs) {
338 : return {lhs.data() - rhs};
339 : }
340 : template <typename T>
341 : SPECTRE_ALWAYS_INLINE SpinWeighted<
342 : decltype(std::declval<T>() - std::declval<get_vector_element_type_t<T>>()),
343 : 0>
344 1 : operator-(const SpinWeighted<T, 0>& lhs,
345 : const get_vector_element_type_t<T>& rhs) {
346 : return {lhs.data() - rhs};
347 : }
348 : template <typename T>
349 : SPECTRE_ALWAYS_INLINE
350 : SpinWeighted<decltype(std::declval<T>() - std::declval<T>()), 0>
351 1 : operator-(const T& lhs, const SpinWeighted<T, 0>& rhs) {
352 : return {lhs - rhs.data()};
353 : }
354 : template <typename T>
355 : SPECTRE_ALWAYS_INLINE SpinWeighted<
356 : decltype(std::declval<get_vector_element_type_t<T>>() - std::declval<T>()),
357 : 0>
358 1 : operator-(const get_vector_element_type_t<T>& lhs,
359 : const SpinWeighted<T, 0>& rhs) {
360 : return {lhs - rhs.data()};
361 : }
362 : /// @}
363 :
364 : /// Negation operator preserves spin
365 : template <typename T, int Spin>
366 : SPECTRE_ALWAYS_INLINE SpinWeighted<decltype(-std::declval<T>()), Spin>
367 1 : operator-(const SpinWeighted<T, Spin>& operand) {
368 : return {-operand.data()};
369 : }
370 :
371 : /// Unary `+` operator preserves spin
372 : template <typename T, int Spin>
373 : SPECTRE_ALWAYS_INLINE SpinWeighted<decltype(+std::declval<T>()), Spin>
374 1 : operator+(const SpinWeighted<T, Spin>& operand) {
375 : return {+operand.data()};
376 : }
377 :
378 : /// @{
379 : /// \brief Multiply two spin-weighted quantities if the types are compatible and
380 : /// add the spins. Un-weighted quantities are assumed to be spin 0.
381 : // These overloads are designed to allow SpinWeighted to wrap Blaze expression
382 : // templates to ensure efficient math operations, necessitating the
383 : // `decltype(declval<T>() ...` syntax
384 : template <typename T1, typename T2, int Spin1, int Spin2>
385 : SPECTRE_ALWAYS_INLINE SpinWeighted<
386 : decltype(std::declval<T1>() * std::declval<T2>()), Spin1 + Spin2>
387 1 : operator*(const SpinWeighted<T1, Spin1>& lhs,
388 : const SpinWeighted<T2, Spin2>& rhs) {
389 : return {lhs.data() * rhs.data()};
390 : }
391 : template <typename T, int Spin>
392 : SPECTRE_ALWAYS_INLINE
393 : SpinWeighted<decltype(std::declval<T>() * std::declval<T>()), Spin>
394 1 : operator*(const SpinWeighted<T, Spin>& lhs, const T& rhs) {
395 : return {lhs.data() * rhs};
396 : }
397 : template <typename T, int Spin>
398 : SPECTRE_ALWAYS_INLINE SpinWeighted<
399 : decltype(std::declval<T>() * std::declval<get_vector_element_type_t<T>>()),
400 : Spin>
401 1 : operator*(const SpinWeighted<T, Spin>& lhs,
402 : const get_vector_element_type_t<T>& rhs) {
403 : return {lhs.data() * rhs};
404 : }
405 : template <typename T, int Spin>
406 : SPECTRE_ALWAYS_INLINE
407 : SpinWeighted<decltype(std::declval<T>() * std::declval<T>()), Spin>
408 1 : operator*(const T& lhs, const SpinWeighted<T, Spin>& rhs) {
409 : return {lhs * rhs.data()};
410 : }
411 : template <typename T, int Spin>
412 : SPECTRE_ALWAYS_INLINE SpinWeighted<
413 : decltype(std::declval<get_vector_element_type_t<T>>() * std::declval<T>()),
414 : Spin>
415 1 : operator*(const get_vector_element_type_t<T>& lhs,
416 : const SpinWeighted<T, Spin>& rhs) {
417 : return {lhs * rhs.data()};
418 : }
419 : /// @}
420 :
421 : /// @{
422 : /// \brief Divide two spin-weighted quantities if the types are compatible and
423 : /// subtract the spins. Un-weighted quantities are assumed to be spin 0.
424 : // These overloads are designed to allow SpinWeighted to wrap Blaze expression
425 : // templates to ensure efficient math operations, necessitating the
426 : // `decltype(declval<T>() ...` syntax
427 : template <typename T1, typename T2, int Spin1, int Spin2>
428 : SPECTRE_ALWAYS_INLINE SpinWeighted<
429 : decltype(std::declval<T1>() / std::declval<T2>()), Spin1 - Spin2>
430 1 : operator/(const SpinWeighted<T1, Spin1>& lhs,
431 : const SpinWeighted<T2, Spin2>& rhs) {
432 : return {lhs.data() / rhs.data()};
433 : }
434 : template <typename T, int Spin>
435 : SPECTRE_ALWAYS_INLINE
436 : SpinWeighted<decltype(std::declval<T>() / std::declval<T>()), Spin>
437 1 : operator/(const SpinWeighted<T, Spin>& lhs, const T& rhs) {
438 : return {lhs.data() / rhs};
439 : }
440 : template <typename T, int Spin>
441 : SPECTRE_ALWAYS_INLINE SpinWeighted<
442 : decltype(std::declval<T>() / std::declval<get_vector_element_type_t<T>>()),
443 : Spin>
444 1 : operator/(const SpinWeighted<T, Spin>& lhs,
445 : const get_vector_element_type_t<T>& rhs) {
446 : return {lhs.data() / rhs};
447 : }
448 : template <typename T, int Spin>
449 : SPECTRE_ALWAYS_INLINE
450 : SpinWeighted<decltype(std::declval<T>() / std::declval<T>()), -Spin>
451 1 : operator/(const T& lhs, const SpinWeighted<T, Spin>& rhs) {
452 : return {lhs / rhs.data()};
453 : }
454 : template <typename T, int Spin>
455 : SPECTRE_ALWAYS_INLINE SpinWeighted<
456 : decltype(std::declval<get_vector_element_type_t<T>>() / std::declval<T>()),
457 : -Spin>
458 1 : operator/(const get_vector_element_type_t<T>& lhs,
459 : const SpinWeighted<T, Spin>& rhs) {
460 : return {lhs / rhs.data()};
461 : }
462 : /// @}
463 :
464 : /// conjugate the spin-weighted quantity, inverting the spin
465 : template <typename T, int Spin>
466 : SPECTRE_ALWAYS_INLINE SpinWeighted<decltype(conj(std::declval<T>())), -Spin>
467 1 : conj(const SpinWeighted<T, Spin>& value) {
468 : return {conj(value.data())};
469 : }
470 :
471 : /// Take the exponential of the spin-weighted quantity; only valid for
472 : /// spin-weight = 0
473 : template <typename T>
474 1 : SPECTRE_ALWAYS_INLINE SpinWeighted<decltype(exp(std::declval<T>())), 0> exp(
475 : const SpinWeighted<T, 0>& value) {
476 : return {exp(value.data())};
477 : }
478 :
479 : /// Take the square-root of the spin-weighted quantity; only valid for
480 : /// spin-weight = 0
481 : template <typename T, int Spin>
482 1 : SPECTRE_ALWAYS_INLINE SpinWeighted<decltype(sqrt(std::declval<T>())), 0> sqrt(
483 : const SpinWeighted<T, Spin>& value) {
484 : return {sqrt(value.data())};
485 : }
486 :
487 : /// @{
488 : /// \brief Test equivalence of spin-weighted quantities if the types are
489 : /// compatible and spins are the same. Un-weighted quantities are assumed to
490 : /// be spin 0.
491 : template <typename T1, typename T2, int Spin>
492 1 : SPECTRE_ALWAYS_INLINE bool operator==(const SpinWeighted<T1, Spin>& lhs,
493 : const SpinWeighted<T2, Spin>& rhs) {
494 : return lhs.data() == rhs.data();
495 : }
496 : template <typename T>
497 1 : SPECTRE_ALWAYS_INLINE bool operator==(const SpinWeighted<T, 0>& lhs,
498 : const T& rhs) {
499 : return lhs.data() == rhs;
500 : }
501 : template <typename T>
502 1 : SPECTRE_ALWAYS_INLINE bool operator==(const T& lhs,
503 : const SpinWeighted<T, 0>& rhs) {
504 : return lhs == rhs.data();
505 : }
506 : /// @}
507 :
508 : /// @{
509 : /// \brief Test inequivalence of spin-weighted quantities if the types are
510 : /// compatible and spins are the same. Un-weighted quantities are assumed to be
511 : /// spin 0.
512 : template <typename T1, typename T2, int Spin>
513 1 : SPECTRE_ALWAYS_INLINE bool operator!=(const SpinWeighted<T1, Spin>& lhs,
514 : const SpinWeighted<T2, Spin>& rhs) {
515 : return not(lhs == rhs);
516 : }
517 : template <typename T>
518 1 : SPECTRE_ALWAYS_INLINE bool operator!=(const SpinWeighted<T, 0>& lhs,
519 : const T& rhs) {
520 : return not(lhs == rhs);
521 : }
522 : template <typename T>
523 1 : SPECTRE_ALWAYS_INLINE bool operator!=(const T& lhs,
524 : const SpinWeighted<T, 0>& rhs) {
525 : return not(lhs == rhs);
526 : }
527 : /// @}
528 :
529 : /// \ingroup DataStructuresGroup
530 : /// Make the input `view` a `const` view of the const data `spin_weighted`, at
531 : /// offset `offset` and length `extent`.
532 : ///
533 : /// \warning This DOES modify the (const) input `view`. The reason `view` is
534 : /// taken by const pointer is to try to insist that the object to be a `const`
535 : /// view is actually const. Of course, there are ways of subverting this
536 : /// intended functionality and editing the data pointed into by `view` after
537 : /// this function is called; doing so is highly discouraged and results in
538 : /// undefined behavior.
539 : template <typename SpinWeightedType,
540 : Requires<is_any_spin_weighted_v<SpinWeightedType> and
541 : is_derived_of_vector_impl_v<
542 : typename SpinWeightedType::value_type>> = nullptr>
543 1 : void make_const_view(const gsl::not_null<const SpinWeightedType*> view,
544 : const SpinWeightedType& spin_weighted, const size_t offset,
545 : const size_t extent) {
546 : const_cast<SpinWeightedType*>(view.get()) // NOLINT
547 : ->set_data_ref(const_cast< // NOLINT
548 : typename SpinWeightedType::value_type::value_type*>(
549 : spin_weighted.data().data()) + // NOLINT
550 : offset,
551 : extent);
552 : }
553 :
554 : /// Stream operator simply forwards
555 : template <typename T, int Spin>
556 1 : std::ostream& operator<<(std::ostream& os, const SpinWeighted<T, Spin>& d) {
557 : return os << d.data();
558 : }
559 :
560 : namespace MakeWithValueImpls {
561 : template <int Spin, typename SpinWeightedType>
562 0 : struct NumberOfPoints<SpinWeighted<SpinWeightedType, Spin>> {
563 : static SPECTRE_ALWAYS_INLINE size_t
564 0 : apply(const SpinWeighted<SpinWeightedType, Spin>& input) {
565 : return number_of_points(input.data());
566 : }
567 : };
568 :
569 : template <int Spin, typename SpinWeightedType>
570 0 : struct MakeWithSize<SpinWeighted<SpinWeightedType, Spin>> {
571 : template <typename ValueType>
572 0 : static SPECTRE_ALWAYS_INLINE SpinWeighted<SpinWeightedType, Spin> apply(
573 : const size_t size, const ValueType value) {
574 : return SpinWeighted<SpinWeightedType, Spin>{
575 : make_with_value<SpinWeightedType>(size, value)};
576 : }
577 : };
578 : } // namespace MakeWithValueImpls
579 :
580 : template <int Spin, typename SpinWeightedType>
581 0 : struct SetNumberOfGridPointsImpls::SetNumberOfGridPointsImpl<
582 : SpinWeighted<SpinWeightedType, Spin>> {
583 0 : static constexpr bool is_trivial =
584 : SetNumberOfGridPointsImpl<SpinWeightedType>::is_trivial;
585 0 : static SPECTRE_ALWAYS_INLINE void apply(
586 : const gsl::not_null<SpinWeighted<SpinWeightedType, Spin>*> result,
587 : const size_t size) {
588 : set_number_of_grid_points(make_not_null(&result->data()), size);
589 : }
590 : };
|