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
|