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