VectorImpl.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <algorithm>
7 #include <array>
8 #include <complex>
9 #include <cstddef>
10 #include <cstdlib>
11 #include <functional> // for std::reference_wrapper
12 #include <initializer_list>
13 #include <memory>
14 #include <ostream>
15 #include <pup.h>
16 #include <type_traits>
17 
18 #include "ErrorHandling/Assert.hpp"
20 #include "Utilities/MakeWithValue.hpp" // IWYU pragma: keep
21 #include "Utilities/PointerVector.hpp" // IWYU pragma: keep
22 #include "Utilities/PrintHelpers.hpp"
23 #include "Utilities/Requires.hpp"
25 
26 // IWYU doesn't like that we want PointerVector.hpp to expose Blaze and also
27 // have VectorImpl.hpp to expose PointerVector.hpp without including Blaze
28 // directly in VectorImpl.hpp
29 //
30 // IWYU pragma: no_include <blaze/math/dense/DenseVector.h>
31 // IWYU pragma: no_include <blaze/math/expressions/DVecDVecAddExpr.h>
32 // IWYU pragma: no_include <blaze/math/expressions/DVecDVecDivExpr.h>
33 // IWYU pragma: no_include <blaze/math/expressions/DVecDVecMultExpr.h>
34 // IWYU pragma: no_include <blaze/math/expressions/DVecDVecSubExpr.h>
35 // IWYU pragma: no_include <blaze/math/expressions/DVecMapExpr.h>
36 // IWYU pragma: no_include <blaze/math/expressions/DVecScalarDivExpr.h>
37 // IWYU pragma: no_include <blaze/math/expressions/DVecScalarMultExpr.h>
38 // IWYU pragma: no_include <blaze/math/expressions/DenseVector.h>
39 // IWYU pragma: no_include <blaze/math/expressions/Vector.h>
40 // IWYU pragma: no_include <blaze/math/typetraits/IsVector.h>
41 // IWYU pragma: no_include <blaze/math/expressions/Forward.h>
42 // IWYU pragma: no_include <blaze/math/AlignmentFlag.h>
43 // IWYU pragma: no_include <blaze/math/PaddingFlag.h>
44 // IWYU pragma: no_include <blaze/math/traits/AddTrait.h>
45 // IWYU pragma: no_include <blaze/math/traits/DivTrait.h>
46 // IWYU pragma: no_include <blaze/math/traits/MultTrait.h>
47 // IWYU pragma: no_include <blaze/math/traits/SubTrait.h>
48 // IWYU pragma: no_include <blaze/system/TransposeFlag.h>
49 #if ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
50 // IWYU pragma: no_include <blaze/math/traits/UnaryMapTrait.h>
51 // IWYU pragma: no_include <blaze/math/traits/BinaryMapTrait.h>
52 #else
53 // IWYU pragma: no_include <blaze/math/traits/MapTrait.h>
54 #endif // ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
55 // IWYU pragma: no_include <blaze/math/typetraits/TransposeFlag.h>
56 
57 // IWYU pragma: no_forward_declare blaze::DenseVector
58 #if ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
59 // IWYU pragma: no_forward_declare blaze::UnaryMapTrait
60 // IWYU pragma: no_forward_declare blaze::BinaryMapTrait
61 #else
62 // IWYU pragma: no_forward_declare blaze::MapTrait
63 #endif // ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
64 // IWYU pragma: no_forward_declare blaze::IsVector
65 // IWYU pragma: no_forward_declare blaze::TransposeFlag
66 
67 /*!
68  * \ingroup DataStructuresGroup
69  * \brief Base class template for various DataVector and related types
70  *
71  * \details The `VectorImpl` class is the generic parent class for vectors
72  * representing collections of related function values, such as `DataVector`s
73  * for contiguous data over a computational domain.
74  *
75  * The `VectorImpl` does not itself define any particular mathematical
76  * operations on the contained values. The `VectorImpl` template class and the
77  * macros defined in `VectorImpl.hpp` assist in the construction of various
78  * derived classes supporting a chosen set of mathematical operations.
79  *
80  * In addition, the equivalence operator `==` is inherited from the underlying
81  * `PointerVector` type, and returns true if and only if the size and contents
82  * of the two compared vectors are equivalent.
83  *
84  * Template parameters:
85  * - `T` is the underlying stored type, e.g. `double`, `std::complex<double>`,
86  * `float`, etc.
87  * - `VectorType` is the type that should be associated with the VectorImpl
88  * during mathematical computations. In most cases, inherited types should
89  * have themselves as the second template argument, e.g.
90  * ```
91  * class DataVector : VectorImpl<double, DataVector> {
92  * ```
93  * The second template parameter communicates arithmetic type restrictions to
94  * the underlying Blaze framework. For example, if `VectorType` is
95  * `DataVector`, then the underlying architecture will prevent addition with a
96  * vector type whose `ResultType` (which is aliased to its `VectorType`) is
97  * `ModalVector`. Since `DataVector`s and `ModalVector`s represent data in
98  * different spaces, we wish to forbid several operations between them. This
99  * vector-type-tracking through an expression prevents accidental mixing of
100  * vector types in math expressions.
101  *
102  * \note
103  * - If created with size 0, then `data()` will return `nullptr`
104  * - If either `SPECTRE_DEBUG` or `SPECTRE_NAN_INIT` are defined, then the
105  * `VectorImpl` is default initialized to `signaling_NaN()`. Otherwise, the
106  * vector is filled with uninitialized memory for performance.
107  */
108 template <typename T, typename VectorType>
110  : public PointerVector<T, blaze::unaligned, blaze::unpadded,
111  blaze::defaultTransposeFlag, VectorType> {
112  public:
113  using value_type = T;
114  using size_type = size_t;
116  using BaseType = PointerVector<T, blaze::unaligned, blaze::unpadded,
117  blaze::defaultTransposeFlag, VectorType>;
118  static constexpr bool transpose_flag = blaze::defaultTransposeFlag;
119 
120  using ElementType = T;
123  using iterator = typename BaseType::Iterator;
124  using const_iterator = typename BaseType::ConstIterator;
125 
126  using BaseType::operator[];
127  using BaseType::begin;
128  using BaseType::cbegin;
129  using BaseType::cend;
130  using BaseType::data;
131  using BaseType::end;
132  using BaseType::size;
133 
134  // @{
135  /// Upcast to `BaseType`
136  /// \attention
137  /// upcast should only be used when implementing a derived vector type, not in
138  /// calling code
139  const BaseType& operator~() const noexcept {
140  return static_cast<const BaseType&>(*this);
141  }
142  BaseType& operator~() noexcept { return static_cast<BaseType&>(*this); }
143  // @}
144 
145  /// Create with the given size. In debug mode, the vector is initialized to
146  /// 'NaN' by default. If not initialized to 'NaN', the memory is allocated but
147  /// not initialized.
148  ///
149  /// - `set_size` number of values
150  explicit VectorImpl(size_t set_size) noexcept
151  : owned_data_(set_size > 0 ? static_cast<value_type*>(
152  malloc(set_size * sizeof(value_type)))
153  : nullptr,
154  &free) {
155 #if defined(SPECTRE_DEBUG) || defined(SPECTRE_NAN_INIT)
156  std::fill(owned_data_.get(), owned_data_.get() + set_size,
158 #endif // SPECTRE_DEBUG
159  reset_pointer_vector(set_size);
160  }
161 
162  /// Create with the given size and value.
163  ///
164  /// - `set_size` number of values
165  /// - `value` the value to initialize each element
166  VectorImpl(size_t set_size, T value) noexcept
167  : owned_data_(set_size > 0 ? static_cast<value_type*>(
168  malloc(set_size * sizeof(value_type)))
169  : nullptr,
170  &free) {
171  std::fill(owned_data_.get(), owned_data_.get() + set_size, value);
172  reset_pointer_vector(set_size);
173  }
174 
175  /// Create a non-owning VectorImpl that points to `start`
176  VectorImpl(T* start, size_t set_size) noexcept
177  : BaseType(start, set_size), owning_(false) {}
178 
179  /// Create from an initializer list of `T`.
180  template <class U, Requires<cpp17::is_same_v<U, T>> = nullptr>
182  : owned_data_(list.size() > 0 ? static_cast<value_type*>(malloc(
183  list.size() * sizeof(value_type)))
184  : nullptr,
185  &free) {
186  // Note: can't use memcpy with an initializer list.
187  std::copy(list.begin(), list.end(), owned_data_.get());
188  reset_pointer_vector(list.size());
189  }
190 
191  /// Empty VectorImpl
192  VectorImpl() = default;
193  /// \cond HIDDEN_SYMBOLS
194  ~VectorImpl() = default;
195 
196  VectorImpl(const VectorImpl<T, VectorType>& rhs) noexcept;
197  VectorImpl& operator=(const VectorImpl<T, VectorType>& rhs) noexcept;
198  VectorImpl(VectorImpl<T, VectorType>&& rhs) noexcept;
199  VectorImpl& operator=(VectorImpl<T, VectorType>&& rhs) noexcept;
200 
201  // This is a converting constructor. clang-tidy complains that it's not
202  // explicit, but we want it to allow conversion.
203  // clang-tidy: mark as explicit (we want conversion to VectorImpl type)
204  template <
205  typename VT, bool VF,
207  VectorImpl(const blaze::DenseVector<VT, VF>& expression) noexcept; // NOLINT
208 
209  template <typename VT, bool VF>
210  VectorImpl& operator=(const blaze::DenseVector<VT, VF>& expression) noexcept;
211  /// \endcond
212 
213  VectorImpl& operator=(const T& rhs) noexcept;
214 
215  // @{
216  /// Set the VectorImpl to be a reference to another VectorImpl object
218  set_data_ref(rhs->data(), rhs->size());
219  }
220 
221  void set_data_ref(T* const start, const size_t set_size) noexcept {
222  owned_data_.reset();
223  (~*this).reset(start, set_size);
224  owning_ = false;
225  }
226  // @}
227 
228  /// Returns true if the class owns the data
229  bool is_owning() const noexcept { return owning_; }
230 
231  /// Serialization for Charm++
232  // clang-tidy: google-runtime-references
233  void pup(PUP::er& p) noexcept; // NOLINT
234 
235  protected:
236  std::unique_ptr<value_type[], decltype(&free)> owned_data_{nullptr, &free};
237  bool owning_{true};
238 
239  SPECTRE_ALWAYS_INLINE void reset_pointer_vector(
240  const size_t set_size) noexcept {
241  this->reset(owned_data_.get(), set_size);
242  }
243 };
244 
245 template <typename T, typename VectorType>
247  const VectorImpl<T, VectorType>& rhs) noexcept
248  : BaseType{rhs},
249  owned_data_(rhs.size() > 0 ? static_cast<value_type*>(
250  malloc(rhs.size() * sizeof(value_type)))
251  : nullptr,
252  &free) {
253  reset_pointer_vector(rhs.size());
254  std::memcpy(data(), rhs.data(), size() * sizeof(value_type));
255 }
256 
257 template <typename T, typename VectorType>
259  const VectorImpl<T, VectorType>& rhs) noexcept {
260  if (this != &rhs) {
261  if (owning_) {
262  if (size() != rhs.size()) {
263  owned_data_.reset(rhs.size() > 0 ? static_cast<value_type*>(malloc(
264  rhs.size() * sizeof(value_type)))
265  : nullptr);
266  }
267  reset_pointer_vector(rhs.size());
268  } else {
269  ASSERT(rhs.size() == size(), "Must copy into same size, not "
270  << rhs.size() << " into " << size());
271  }
272  std::memcpy(data(), rhs.data(), size() * sizeof(value_type));
273  }
274  return *this;
275 }
276 
277 template <typename T, typename VectorType>
279  VectorImpl<T, VectorType>&& rhs) noexcept {
280  owned_data_ = std::move(rhs.owned_data_);
281  ~*this = ~rhs; // PointerVector is trivially copyable
282  owning_ = rhs.owning_;
283  rhs.owning_ = true;
284  rhs.reset();
285 }
286 
287 template <typename T, typename VectorType>
289  VectorImpl<T, VectorType>&& rhs) noexcept {
290  if (this != &rhs) {
291  if (owning_) {
292  owned_data_ = std::move(rhs.owned_data_);
293  ~*this = ~rhs; /* PointerVector is trivially copyable */
294  owning_ = rhs.owning_;
295  } else {
296  ASSERT(rhs.size() == size(), "Must copy into same size, not "
297  << rhs.size() << " into " << size());
298  std::memcpy(data(), rhs.data(), size() * sizeof(value_type));
299  }
300  rhs.owning_ = true;
301  rhs.reset();
302  }
303  return *this;
304 }
305 
306 /// \cond HIDDEN_SYMBOLS
307 // This is a converting constructor. clang-tidy complains that it's not
308 // explicit, but we want it to allow conversion.
309 // clang-tidy: mark as explicit (we want conversion to VectorImpl)
310 template <typename T, typename VectorType>
311 template <typename VT, bool VF,
314  const blaze::DenseVector<VT, VF>& expression) // NOLINT
315  noexcept
316  : owned_data_(static_cast<value_type*>(
317  malloc((~expression).size() * sizeof(value_type))),
318  &free) {
319  static_assert(cpp17::is_same_v<typename VT::ResultType, VectorType>,
320  "You are attempting to assign the result of an expression "
321  "that is not consistent with the VectorImpl type you are "
322  "assigning to.");
323  reset_pointer_vector((~expression).size());
324  ~*this = expression;
325 }
326 
327 template <typename T, typename VectorType>
328 template <typename VT, bool VF>
330  const blaze::DenseVector<VT, VF>& expression) noexcept {
331  static_assert(cpp17::is_same_v<typename VT::ResultType, VectorType>,
332  "You are attempting to assign the result of an expression "
333  "that is not consistent with the VectorImpl type you are "
334  "assigning to.");
335  if (owning_ and (~expression).size() != size()) {
336  owned_data_.reset(static_cast<value_type*>(
337  malloc((~expression).size() * sizeof(value_type))));
338  reset_pointer_vector((~expression).size());
339  } else if (not owning_) {
340  ASSERT((~expression).size() == size(), "Must copy into same size, not "
341  << (~expression).size()
342  << " into " << size());
343  }
344  ~*this = expression;
345  return *this;
346 }
347 /// \endcond
348 
349 // The case of assigning a type apart from the same VectorImpl or a
350 // `blaze::DenseVector` forwards the assignment to the `PointerVector` base
351 // type. In the case of a single compatible value, this fills the vector with
352 // that value.
353 template <typename T, typename VectorType>
355  const T& rhs) noexcept {
356  ~*this = rhs;
357  return *this;
358 }
359 
360 template <typename T, typename VectorType>
361 void VectorImpl<T, VectorType>::pup(PUP::er& p) noexcept { // NOLINT
362  auto my_size = size();
363  p | my_size;
364  if (my_size > 0) {
365  if (p.isUnpacking()) {
366  owning_ = true;
367  owned_data_.reset(my_size > 0 ? static_cast<value_type*>(
368  malloc(my_size * sizeof(value_type)))
369  : nullptr);
370  reset_pointer_vector(my_size);
371  }
372  PUParray(p, data(), size());
373  }
374 }
375 
376 /// Output operator for VectorImpl
377 template <typename T, typename VectorType>
378 std::ostream& operator<<(std::ostream& os,
379  const VectorImpl<T, VectorType>& d) noexcept {
380  sequence_print_helper(os, d.begin(), d.end());
381  return os;
382 }
383 
384 /*!
385  * \ingroup DataStructuresGroup
386  * \brief Instructs Blaze to provide the appropriate vector result type after
387  * math operations. This is accomplished by specializing Blaze's type traits
388  * that are used for handling return type deduction and specifying the `using
389  * Type =` nested type alias in the traits.
390  *
391  * \param VECTOR_TYPE The vector type, which matches the type of the operation
392  * result (e.g. `DataVector`)
393  *
394  * \param BLAZE_MATH_TRAIT The blaze trait/expression for which you want to
395  * specify the return type (e.g. `AddTrait`).
396  */
397 #define BLAZE_TRAIT_SPECIALIZE_BINARY_TRAIT(VECTOR_TYPE, BLAZE_MATH_TRAIT) \
398  template <> \
399  struct BLAZE_MATH_TRAIT<VECTOR_TYPE, VECTOR_TYPE> { \
400  using Type = VECTOR_TYPE; \
401  }; \
402  template <> \
403  struct BLAZE_MATH_TRAIT<VECTOR_TYPE, VECTOR_TYPE::value_type> { \
404  using Type = VECTOR_TYPE; \
405  }; \
406  template <> \
407  struct BLAZE_MATH_TRAIT<VECTOR_TYPE::value_type, VECTOR_TYPE> { \
408  using Type = VECTOR_TYPE; \
409  }
410 
411 /*!
412  * \ingroup DataStructuresGroup
413  * \brief Instructs Blaze to provide the appropriate vector result type of an
414  * operator between `VECTOR_TYPE` and `COMPATIBLE`, where the operation is
415  * represented by `BLAZE_MATH_TRAIT`
416  *
417  * \param VECTOR_TYPE The vector type, which matches the type of the operation
418  * result (e.g. `ComplexDataVector`)
419  *
420  * \param COMPATIBLE the type for which you want math operations to work with
421  * `VECTOR_TYPE` smoothly (e.g. `DataVector`)
422  *
423  * \param BLAZE_MATH_TRAIT The blaze trait for which you want declare the Type
424  * field (e.g. `AddTrait`)
425  */
426 #define BLAZE_TRAIT_SPECIALIZE_COMPATIBLE_BINARY_TRAIT( \
427  VECTOR_TYPE, COMPATIBLE, BLAZE_MATH_TRAIT) \
428  template <> \
429  struct BLAZE_MATH_TRAIT<VECTOR_TYPE, COMPATIBLE> { \
430  using Type = VECTOR_TYPE; \
431  }; \
432  template <> \
433  struct BLAZE_MATH_TRAIT<COMPATIBLE, VECTOR_TYPE> { \
434  using Type = VECTOR_TYPE; \
435  }
436 
437 /*!
438  * \ingroup DataStructuresGroup
439  * \brief Instructs Blaze to provide the appropriate vector result type of
440  * arithmetic operations for `VECTOR_TYPE`. This is accomplished by specializing
441  * Blaze's type traits that are used for handling return type deduction.
442  *
443  * \details Type definitions here are suitable for contiguous data
444  * (e.g. `DataVector`), but this macro might need to be tweaked for other types
445  * of data, for instance Fourier coefficients.
446  *
447  * \param VECTOR_TYPE The vector type, which for the arithmetic operations is
448  * the type of the operation result (e.g. `DataVector`)
449  */
450 #define VECTOR_BLAZE_TRAIT_SPECIALIZE_ARITHMETIC_TRAITS(VECTOR_TYPE) \
451  template <> \
452  struct IsVector<VECTOR_TYPE> : std::true_type {}; \
453  template <> \
454  struct TransposeFlag<VECTOR_TYPE> \
455  : BoolConstant<VECTOR_TYPE::transpose_flag> {}; \
456  BLAZE_TRAIT_SPECIALIZE_BINARY_TRAIT(VECTOR_TYPE, AddTrait); \
457  BLAZE_TRAIT_SPECIALIZE_BINARY_TRAIT(VECTOR_TYPE, SubTrait); \
458  BLAZE_TRAIT_SPECIALIZE_BINARY_TRAIT(VECTOR_TYPE, MultTrait); \
459  BLAZE_TRAIT_SPECIALIZE_BINARY_TRAIT(VECTOR_TYPE, DivTrait)
460 
461 /*!
462  * \ingroup DataStructuresGroup
463  * \brief Instructs Blaze to provide the appropriate vector result type of `Map`
464  * operations (unary and binary) acting on `VECTOR_TYPE`. This is accomplished
465  * by specializing Blaze's type traits that are used for handling return type
466  * deduction.
467  *
468  * \details Type declarations here are suitable for contiguous data (e.g.
469  * `DataVector`), but this macro might need to be tweaked for other types of
470  * data, for instance Fourier coefficients.
471  *
472  * \param VECTOR_TYPE The vector type, which for the `Map` operations is
473  * the type of the operation result (e.g. `DataVector`)
474  */
475 #if ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
476 #define VECTOR_BLAZE_TRAIT_SPECIALIZE_ALL_MAP_TRAITS(VECTOR_TYPE) \
477  template <typename Operator> \
478  struct UnaryMapTrait<VECTOR_TYPE, Operator> { \
479  using Type = VECTOR_TYPE; \
480  }; \
481  template <typename Operator> \
482  struct BinaryMapTrait<VECTOR_TYPE, VECTOR_TYPE, Operator> { \
483  using Type = VECTOR_TYPE; \
484  }
485 #else
486 #define VECTOR_BLAZE_TRAIT_SPECIALIZE_ALL_MAP_TRAITS(VECTOR_TYPE) \
487  template <typename Operator> \
488  struct MapTrait<VECTOR_TYPE, Operator> { \
489  using Type = VECTOR_TYPE; \
490  }; \
491  template <typename Operator> \
492  struct MapTrait<VECTOR_TYPE, VECTOR_TYPE, Operator> { \
493  using Type = VECTOR_TYPE; \
494  }
495 #endif // ((BLAZE_MAJOR_VERSION == 3) && (BLAZE_MINOR_VERSION <= 3))
496 
497 /*!
498  * \ingroup DataStructuresGroup
499  * \brief Defines the set of binary operations often supported for
500  * `std::array<VECTOR_TYPE, size>`, for arbitrary `size`.
501  *
502  * \param VECTOR_TYPE The vector type (e.g. `DataVector`)
503  */
504 #define MAKE_STD_ARRAY_VECTOR_BINOPS(VECTOR_TYPE) \
505  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE::value_type, \
506  VECTOR_TYPE, operator+, std::plus<>()) \
507  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE, \
508  VECTOR_TYPE::value_type, operator+, std::plus<>()) \
509  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE, VECTOR_TYPE, operator+, \
510  std::plus<>()) \
511  \
512  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE::value_type, \
513  VECTOR_TYPE, operator-, std::minus<>()) \
514  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE, \
515  VECTOR_TYPE::value_type, operator-, std::minus<>()) \
516  DEFINE_STD_ARRAY_BINOP(VECTOR_TYPE, VECTOR_TYPE, VECTOR_TYPE, operator-, \
517  std::minus<>()) \
518  \
519  DEFINE_STD_ARRAY_INPLACE_BINOP(VECTOR_TYPE, VECTOR_TYPE, operator-=, \
520  std::minus<>()) \
521  DEFINE_STD_ARRAY_INPLACE_BINOP( \
522  VECTOR_TYPE, VECTOR_TYPE::value_type, operator-=, std::minus<>()) \
523  DEFINE_STD_ARRAY_INPLACE_BINOP(VECTOR_TYPE, VECTOR_TYPE, operator+=, \
524  std::plus<>()) \
525  DEFINE_STD_ARRAY_INPLACE_BINOP( \
526  VECTOR_TYPE, VECTOR_TYPE::value_type, operator+=, std::plus<>())
527 
528 /*!
529  * \ingroup DataStructuresGroup
530  * \brief Defines `MAKE_MATH_ASSIGN_EXPRESSION_POINTERVECTOR` with all
531  * assignment arithmetic operations
532  *
533  * \param VECTOR_TYPE The vector type (e.g. `DataVector`)
534  */
535 #define MAKE_MATH_ASSIGN_EXPRESSION_ARITHMETIC(VECTOR_TYPE) \
536  MAKE_MATH_ASSIGN_EXPRESSION_POINTERVECTOR(+=, VECTOR_TYPE) \
537  MAKE_MATH_ASSIGN_EXPRESSION_POINTERVECTOR(-=, VECTOR_TYPE) \
538  MAKE_MATH_ASSIGN_EXPRESSION_POINTERVECTOR(*=, VECTOR_TYPE) \
539  MAKE_MATH_ASSIGN_EXPRESSION_POINTERVECTOR(/=, VECTOR_TYPE)
540 
541 /*!
542  * \ingroup DataStructuresGroup
543  * \brief Defines the `MakeWithValueImpl` `apply` specialization
544  *
545  * \details The `MakeWithValueImpl<VECTOR_TYPE, VECTOR_TYPE>` member
546  * `apply(VECTOR_TYPE, VECTOR_TYPE::value_type)` specialization defined by this
547  * macro produces an object with the same size as the `input` argument,
548  * initialized with the `value` argument in every entry.
549  *
550  * \param VECTOR_TYPE The vector type (e.g. `DataVector`)
551  */
552 #define MAKE_WITH_VALUE_IMPL_DEFINITION_FOR(VECTOR_TYPE) \
553  namespace MakeWithValueImpls { \
554  template <> \
555  struct MakeWithValueImpl<VECTOR_TYPE, VECTOR_TYPE> { \
556  static SPECTRE_ALWAYS_INLINE VECTOR_TYPE \
557  apply(const VECTOR_TYPE& input, \
558  const VECTOR_TYPE::value_type value) noexcept { \
559  return VECTOR_TYPE(input.size(), value); \
560  } \
561  }; \
562  template <> \
563  struct MakeWithValueImpl<VECTOR_TYPE, size_t> { \
564  static SPECTRE_ALWAYS_INLINE VECTOR_TYPE \
565  apply(const size_t& size, const VECTOR_TYPE::value_type value) noexcept { \
566  return VECTOR_TYPE(size, value); \
567  } \
568  }; \
569  } // namespace MakeWithValueImpls
570 
571 // {@
572 /*!
573  * \ingroup DataStructuresGroup
574  * \ingroup TypeTraitsGroup
575  * \brief Helper struct to determine the element type of a VectorImpl or
576  * container of VectorImpl
577  *
578  * \details Extracts the element type of a `VectorImpl`, a std::array of
579  * `VectorImpl`, or a reference or pointer to a `VectorImpl`. In any of these
580  * cases, the `type` member is defined as the `ElementType` of the `VectorImpl`
581  * in question. If, instead, `get_vector_element_type` is passed an arithmetic
582  * or complex arithemetic type, the `type` member is defined as the passed type.
583  *
584  * \snippet DataStructures/Test_VectorImpl.cpp get_vector_element_type_example
585  */
586 // cast to bool needed to avoid the compiler mistaking the type to be determined
587 // by T
588 template <typename T,
589  bool = static_cast<bool>(tt::is_complex_of_fundamental_v<T> or
590  cpp17::is_fundamental_v<T>)>
592 template <typename T>
594  using type = T;
595 };
596 template <typename T>
598  using type = typename get_vector_element_type<T>::type;
599 };
600 template <typename T>
602  using type = typename get_vector_element_type<
603  typename T::ResultType::ElementType>::type;
604 };
605 template <typename T>
606 struct get_vector_element_type<T*, false> {
607  using type = typename get_vector_element_type<T>::type;
608 };
609 template <typename T>
610 struct get_vector_element_type<T&, false> {
611  using type = typename get_vector_element_type<T>::type;
612 };
613 template <typename T, size_t S>
614 struct get_vector_element_type<std::array<T, S>, false> {
615  using type = typename get_vector_element_type<T>::type;
616 };
617 // @}
618 
619 template <typename T>
620 using get_vector_element_type_t = typename get_vector_element_type<T>::type;
621 
622 namespace detail {
623 template <typename... VectorImplTemplateArgs>
624 std::true_type is_derived_of_vector_impl_impl(
626 
627 std::false_type is_derived_of_vector_impl_impl(...);
628 } // namespace detail
629 
630 /// \ingroup TypeTraitsGroup
631 /// This is `std::true_type` if the provided type possesses an implicit
632 /// conversion to any `VectorImpl`, which is the primary feature of SpECTRE
633 /// vectors generally. Otherwise, it is `std::false_type`.
634 template <typename T>
636  decltype(detail::is_derived_of_vector_impl_impl(std::declval<T*>()));
637 
638 template <typename T>
639 constexpr bool is_derived_of_vector_impl_v =
void set_data_ref(gsl::not_null< VectorType *> rhs) noexcept
Set the VectorImpl to be a reference to another VectorImpl object.
Definition: VectorImpl.hpp:217
VectorImpl(std::initializer_list< U > list) noexcept
Create from an initializer list of T.
Definition: VectorImpl.hpp:181
T signaling_NaN(T... args)
void pup(PUP::er &p) noexcept
Serialization for Charm++.
Definition: VectorImpl.hpp:361
Base class template for various DataVector and related types.
Definition: VectorImpl.hpp:109
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
Defines class PointerVector.
const BaseType & operator~() const noexcept
Upcast to BaseType
Definition: VectorImpl.hpp:139
Defines the type alias Requires.
VectorImpl(size_t set_size) noexcept
Create with the given size. In debug mode, the vector is initialized to &#39;NaN&#39; by default. If not initialized to &#39;NaN&#39;, the memory is allocated but not initialized.
Definition: VectorImpl.hpp:150
VectorImpl(T *start, size_t set_size) noexcept
Create a non-owning VectorImpl that points to start
Definition: VectorImpl.hpp:176
Definition: Determinant.hpp:11
Definition: VectorImpl.hpp:593
Definition: VectorImpl.hpp:601
decltype(detail::is_derived_of_vector_impl_impl(std::declval< T * >())) is_derived_of_vector_impl
This is std::true_type if the provided type possesses an implicit conversion to any VectorImpl...
Definition: VectorImpl.hpp:636
VectorImpl()=default
Empty VectorImpl.
VectorImpl(size_t set_size, T value) noexcept
Create with the given size and value.
Definition: VectorImpl.hpp:166
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
Definition: VectorImpl.hpp:597
bool is_owning() const noexcept
Returns true if the class owns the data.
Definition: VectorImpl.hpp:229
void sequence_print_helper(std::ostream &out, ForwardIt &&begin, ForwardIt &&end, Func f) noexcept
Applies the function f(out, it) to each item from begin to end, separated by commas and surrounded by...
Definition: PrintHelpers.hpp:18
Defines macro to always inline a function.
A raw pointer endowed with expression template support via the Blaze library.
Definition: PointerVector.hpp:496
Helper struct to determine the element type of a VectorImpl or container of VectorImpl.
Definition: VectorImpl.hpp:591
Defines macro ASSERT.
void set_data_ref(T *const start, const size_t set_size) noexcept
Set the VectorImpl to be a reference to another VectorImpl object.
Definition: VectorImpl.hpp:221
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
BaseType & operator~() noexcept
Upcast to BaseType
Definition: VectorImpl.hpp:142
Defines arithmetic operators for std::array and other helpful functions.
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
Defines make_with_value.