Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <functional>
8 : #include <initializer_list>
9 : #include <ostream>
10 : #include <stack>
11 : #include <string>
12 : #include <utility>
13 :
14 : #include "Utilities/ErrorHandling/Assert.hpp"
15 : #include "Utilities/Gsl.hpp"
16 : #include "Utilities/MakeWithValue.hpp"
17 : #include "Utilities/Overloader.hpp"
18 : #include "Utilities/PrettyType.hpp"
19 : #include "Utilities/PrintHelpers.hpp"
20 : #include "Utilities/SetNumberOfGridPoints.hpp"
21 : #include "Utilities/TMPL.hpp"
22 :
23 : /// \cond
24 : namespace PUP {
25 : class er;
26 : } // namespace PUP
27 : /// \endcond
28 :
29 : /*!
30 : * \brief Contains utilities for working with tuples
31 : */
32 1 : namespace tuples {
33 :
34 : namespace tuples_detail {
35 :
36 : template <class T>
37 : inline constexpr T&& forward(typename std::remove_reference<T>::type& t) {
38 : return static_cast<T&&>(t);
39 : }
40 :
41 : template <class T>
42 : inline constexpr T&& forward(typename std::remove_reference<T>::type&& t) {
43 : static_assert(!std::is_lvalue_reference<T>::value,
44 : "cannot forward an rvalue as an lvalue");
45 : return static_cast<T&&>(t);
46 : }
47 :
48 : template <class T, T...>
49 : struct value_list {};
50 :
51 : template <class...>
52 : struct typelist {};
53 :
54 : template <bool... Bs>
55 : using all = typename std::is_same<
56 : value_list<bool, Bs...>,
57 : value_list<bool, (static_cast<void>(Bs), true)...>>::type;
58 :
59 : struct no_such_type {
60 : no_such_type() = delete;
61 : no_such_type(no_such_type const& /*unused*/) = delete;
62 : no_such_type(no_such_type&& /*unused*/) = delete;
63 : ~no_such_type() = delete;
64 : no_such_type& operator=(no_such_type const& /*unused*/) = delete;
65 : no_such_type operator=(no_such_type&& /*unused*/) = delete;
66 : };
67 :
68 : namespace detail {
69 : using std::swap;
70 :
71 : template <class T, class S,
72 : bool = not std::is_void<T>::value and not std::is_void<S>::value>
73 : struct is_swappable_with {
74 : template <class L, class R>
75 : static auto test_swap(int)
76 : -> decltype(swap(std::declval<L&>(), std::declval<R&>()));
77 : template <class L, class R>
78 : static tuples::tuples_detail::no_such_type test_swap(...);
79 :
80 : static const bool value =
81 : not std::is_same<decltype(test_swap<T, S>(0)),
82 : tuples::tuples_detail::no_such_type>::value and
83 : not std::is_same<decltype(test_swap<S, T>(0)),
84 : tuples::tuples_detail::no_such_type>::value;
85 : };
86 :
87 : template <class T, class S>
88 : struct is_swappable_with<T, S, false> : std::false_type {};
89 : } // namespace detail
90 :
91 : template <class T, class S>
92 : using is_swappable_with = detail::is_swappable_with<T, S>;
93 :
94 : template <typename... Ts>
95 : constexpr char expand_pack(Ts&&... /*unused*/) {
96 : return '0';
97 : }
98 : } // namespace tuples_detail
99 :
100 : namespace tuples_detail {
101 : template <class Tag, bool Ebo = std::is_empty<typename Tag::type>::value &&
102 : !__is_final(typename Tag::type)>
103 : class TaggedTupleLeaf;
104 :
105 : template <class T, bool B>
106 : void swap(TaggedTupleLeaf<T, B>& lhs, TaggedTupleLeaf<T, B>& rhs) {
107 : using std::swap;
108 : swap(lhs.get_data(), rhs.get_data());
109 : }
110 :
111 : template <class Tag>
112 : class TaggedTupleLeaf<Tag, false> {
113 : using value_type = typename Tag::type;
114 : value_type value_;
115 :
116 : template <class T>
117 : static constexpr bool can_bind_reference() {
118 : using rem_ref_value_type = typename std::remove_reference<value_type>::type;
119 : using rem_ref_T = typename std::remove_reference<T>::type;
120 : using is_lvalue_type = std::integral_constant<
121 : bool,
122 : std::is_lvalue_reference<T>::value or
123 : std::is_same<std::reference_wrapper<rem_ref_value_type>,
124 : rem_ref_T>::value or
125 : std::is_same<std::reference_wrapper<typename std::remove_const<
126 : rem_ref_value_type>::type>,
127 : rem_ref_T>::value>;
128 : return not std::is_reference<value_type>::value or
129 : (std::is_lvalue_reference<value_type>::value and
130 : is_lvalue_type::value) or
131 : (std::is_rvalue_reference<value_type>::value and
132 : not std::is_lvalue_reference<T>::value);
133 : }
134 :
135 : public:
136 : // Tested in constexpr context in Unit.TaggedTuple.Ebo
137 : constexpr TaggedTupleLeaf() : value_() {
138 : static_assert(
139 : !std::is_reference<value_type>::value,
140 : "Cannot default construct a reference element in a TaggedTuple");
141 : }
142 :
143 : // clang-tidy: forwarding references can be bad
144 : template <
145 : class T,
146 : typename std::enable_if<
147 : !std::is_same<typename std::decay<T>::type, TaggedTupleLeaf>::value &&
148 : std::is_constructible<value_type, T>::value>::type* = nullptr>
149 : constexpr explicit TaggedTupleLeaf(T&& t)
150 : : value_(tuples_detail::forward<T>(t)) {
151 : static_assert(can_bind_reference<T>(),
152 : "Cannot construct an lvalue reference with an rvalue");
153 : }
154 :
155 : constexpr TaggedTupleLeaf(TaggedTupleLeaf const& /*rhs*/) = default;
156 : constexpr TaggedTupleLeaf(TaggedTupleLeaf&& /*rhs*/) = default;
157 : constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf const& /*rhs*/) =
158 : default;
159 : constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf&& /*rhs*/) = default;
160 :
161 : ~TaggedTupleLeaf() = default;
162 :
163 : // Note: name get_data instead of get to enable structured binding support.
164 : constexpr value_type& get_data() { return value_; }
165 : constexpr const value_type& get_data() const { return value_; }
166 :
167 : bool swap(TaggedTupleLeaf& t) {
168 : using std::swap;
169 : swap(*this, t);
170 : return false;
171 : }
172 :
173 : // clang-tidy: runtime-references
174 : void pup(PUP::er& p) { p | value_; } // NOLINT
175 : };
176 :
177 : template <class Tag>
178 : class TaggedTupleLeaf<Tag, true> : private Tag::type {
179 : using value_type = typename Tag::type;
180 :
181 : public:
182 : constexpr TaggedTupleLeaf() : value_type{} {}
183 :
184 : template <
185 : class T,
186 : typename std::enable_if<
187 : !std::is_same<typename std::decay<T>::type, TaggedTupleLeaf>::value &&
188 : std::is_constructible<value_type, T&&>::value>::type* = nullptr>
189 : constexpr explicit TaggedTupleLeaf(T&& t)
190 : : value_type(tuples_detail::forward<T>(t)) {}
191 :
192 : constexpr TaggedTupleLeaf(TaggedTupleLeaf const& /*rhs*/) = default;
193 : constexpr TaggedTupleLeaf(TaggedTupleLeaf&& /*rhs*/) = default;
194 : constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf const& /*rhs*/) =
195 : default;
196 : constexpr TaggedTupleLeaf& operator=(TaggedTupleLeaf&& /*rhs*/) = default;
197 :
198 : ~TaggedTupleLeaf() = default;
199 :
200 : // Note: name get_data instead of get to enable structured binding support.
201 : constexpr value_type& get_data() { return static_cast<value_type&>(*this); }
202 :
203 : constexpr const value_type& get_data() const {
204 : return static_cast<const value_type&>(*this);
205 : }
206 :
207 : bool swap(TaggedTupleLeaf& t) {
208 : using std::swap;
209 : swap(*this, t);
210 : return false;
211 : }
212 :
213 : // NOLINTNEXTLINE(google-runtime-references)
214 : void pup(PUP::er& p) { p | static_cast<typename Tag::type&>(*this); }
215 : };
216 :
217 : struct disable_constructors {
218 : static constexpr bool enable_default() { return false; }
219 : static constexpr bool enable_explicit() { return false; }
220 : static constexpr bool enable_implicit() { return false; }
221 : };
222 : } // namespace tuples_detail
223 :
224 : /*!
225 : * \ingroup UtilitiesGroup
226 : * \brief An associative container that is indexed by structs
227 : *
228 : * A data structure that is indexed by Tags. A Tag is a struct that contains
229 : * a type alias named `type`, which is the type of the object stored with
230 : * index Tag.
231 : *
232 : * \tparam Tags the tags of the objects to be placed in the tuple
233 : */
234 : template <class... Tags>
235 : class TaggedTuple;
236 :
237 : template <class Tag, class... Tags>
238 : constexpr const typename Tag::type& get(const TaggedTuple<Tags...>& t);
239 : template <class Tag, class... Tags>
240 : constexpr typename Tag::type& get(TaggedTuple<Tags...>& t);
241 : template <class Tag, class... Tags>
242 : constexpr const typename Tag::type&& get(const TaggedTuple<Tags...>&& t);
243 : template <class Tag, class... Tags>
244 : constexpr typename Tag::type&& get(TaggedTuple<Tags...>&& t);
245 :
246 : /*!
247 : * \brief Returns the type of the Tag
248 : */
249 : template <class Tag>
250 1 : using tag_type = typename Tag::type;
251 :
252 : // clang-tidy: class does not define copy or move assignment (it does)
253 : template <class... Tags>
254 1 : class TaggedTuple : private tuples_detail::TaggedTupleLeaf<Tags>... { // NOLINT
255 : template <class... Args>
256 0 : struct pack_is_TaggedTuple : std::false_type {};
257 : template <class... Args>
258 0 : struct pack_is_TaggedTuple<TaggedTuple<Args...>> : std::true_type {};
259 :
260 : template <bool EnableConstructor, class Dummy = void>
261 0 : struct args_constructor : tuples_detail::disable_constructors {};
262 :
263 : template <class Dummy>
264 0 : struct args_constructor<true, Dummy> {
265 0 : static constexpr bool enable_default() {
266 : return tuples_detail::all<
267 : std::is_default_constructible<tag_type<Tags>>::value...>::value;
268 : }
269 :
270 : template <class... Ts>
271 0 : static constexpr bool enable_explicit() {
272 : return tuples_detail::all<std::is_constructible<
273 : tuples_detail::TaggedTupleLeaf<Tags>, Ts>::value...>::value and
274 : not tuples_detail::all<
275 : std::is_convertible<Ts, tag_type<Tags>>::value...>::value;
276 : }
277 : template <class... Ts>
278 0 : static constexpr bool enable_implicit() {
279 : return tuples_detail::all<std::is_constructible<
280 : tuples_detail::TaggedTupleLeaf<Tags>, Ts>::value...>::value and
281 : tuples_detail::all<
282 : std::is_convertible<Ts, tag_type<Tags>>::value...>::value;
283 : }
284 : };
285 :
286 : // C++17 Draft 23.5.3.2 Assignment - helper aliases
287 0 : using is_copy_assignable =
288 : tuples_detail::all<std::is_copy_assignable<tag_type<Tags>>::value...>;
289 0 : using is_nothrow_copy_assignable = tuples_detail::all<
290 : std::is_nothrow_copy_assignable<tag_type<Tags>>::value...>;
291 0 : using is_move_assignable =
292 : tuples_detail::all<std::is_move_assignable<tag_type<Tags>>::value...>;
293 0 : using is_nothrow_move_assignable = tuples_detail::all<
294 : std::is_nothrow_move_assignable<tag_type<Tags>>::value...>;
295 :
296 : // clang-tidy: redundant declaration
297 : template <class Tag, class... LTags>
298 0 : friend constexpr const typename Tag::type& get( // NOLINT
299 : const TaggedTuple<LTags...>& t);
300 : template <class Tag, class... LTags>
301 0 : friend constexpr typename Tag::type& get( // NOLINT
302 : TaggedTuple<LTags...>& t);
303 : template <class Tag, class... LTags>
304 0 : friend constexpr const typename Tag::type&& get( // NOLINT
305 : const TaggedTuple<LTags...>&& t);
306 : template <class Tag, class... LTags>
307 0 : friend constexpr typename Tag::type&& get( // NOLINT
308 : TaggedTuple<LTags...>&& t);
309 :
310 : public:
311 0 : using tags_list = tmpl::list<Tags...>;
312 :
313 0 : static constexpr size_t size() { return sizeof...(Tags); }
314 :
315 : // clang-tidy: runtime-references
316 : // NOLINTNEXTLINE(google-runtime-references)
317 0 : void pup(PUP::er& p) {
318 : static_cast<void>(std::initializer_list<char>{
319 : (tuples_detail::TaggedTupleLeaf<Tags>::pup(p), '0')...});
320 : }
321 :
322 : // C++17 Draft 23.5.3.1 Construction
323 : template <bool Dummy = true, typename std::enable_if<args_constructor<
324 : Dummy>::enable_default()>::type* = nullptr>
325 0 : constexpr TaggedTuple() {}
326 :
327 0 : TaggedTuple(TaggedTuple const& /*rhs*/) = default;
328 0 : TaggedTuple(TaggedTuple&& /*rhs*/) = default;
329 :
330 : /*!
331 : * \brief Construct a TaggedTuple with Args
332 : * \requires `std::is_convertible_v<Us, typename Tags::type>...` is `true`
333 : *
334 : * \example
335 : * \snippet Test_TaggedTuple.cpp construction_example
336 : */
337 : template <class... Us,
338 : typename std::enable_if<
339 : args_constructor<not pack_is_TaggedTuple<Us...>::value and
340 : sizeof...(Us) == sizeof...(Tags)>::
341 : template enable_explicit<Us...>()>::type* = nullptr>
342 1 : constexpr explicit TaggedTuple(Us&&... us)
343 : : tuples_detail::TaggedTupleLeaf<Tags>(
344 : tuples_detail::forward<Us>(us))... {}
345 :
346 : /*!
347 : * \brief Construct a TaggedTuple with Args
348 : * \requires `std::is_convertible_v<Us, typename Tags::type>...` is `true`
349 : *
350 : * \example
351 : * \snippet Test_TaggedTuple.cpp construction_example
352 : */
353 : template <class... Us,
354 : typename std::enable_if<
355 : args_constructor<not pack_is_TaggedTuple<Us...>::value and
356 : sizeof...(Us) == sizeof...(Tags)>::
357 : template enable_implicit<Us...>()>::type* = nullptr>
358 : // clang-tidy: mark explicit
359 1 : constexpr TaggedTuple(Us&&... us)
360 : : tuples_detail::TaggedTupleLeaf<Tags>(
361 : tuples_detail::forward<Us>(us))... {}
362 :
363 : template <
364 : class... UTags,
365 : typename std::enable_if<
366 : sizeof...(Tags) == sizeof...(UTags) and
367 : tuples_detail::all<std::is_constructible<
368 : tag_type<Tags>, const tag_type<UTags>&>::value...>::value and
369 : not tuples_detail::all<std::is_same<Tags, UTags>::value...>::value>::
370 : type* = nullptr>
371 0 : constexpr explicit TaggedTuple(TaggedTuple<UTags...> const& t)
372 : : tuples_detail::TaggedTupleLeaf<Tags>(get<UTags>(t))... {}
373 :
374 : template <class... UTags,
375 : typename std::enable_if<
376 : sizeof...(Tags) == sizeof...(UTags) and
377 : tuples_detail::all<std::is_constructible<
378 : tag_type<Tags>, tag_type<UTags>&&>::value...>::value and
379 : not tuples_detail::all<std::is_same<Tags, UTags>::value...>::
380 : value>::type* = nullptr>
381 0 : constexpr explicit TaggedTuple(TaggedTuple<UTags...>&& t)
382 : : tuples_detail::TaggedTupleLeaf<Tags>(std::move(get<UTags>(t)))... {}
383 :
384 0 : ~TaggedTuple() = default;
385 :
386 : // C++17 Draft 23.5.3.2 Assignment
387 0 : TaggedTuple& operator=(
388 : tmpl::conditional_t<is_copy_assignable::value, TaggedTuple,
389 : tuples_detail::no_such_type> const& t) {
390 : static_cast<void>(
391 : tuples_detail::expand_pack((get<Tags>(*this) = get<Tags>(t))...));
392 : return *this;
393 : }
394 :
395 0 : TaggedTuple& operator=(
396 : tmpl::conditional_t<is_move_assignable::value, TaggedTuple,
397 : tuples_detail::no_such_type>&& t) {
398 : static_cast<void>(tuples_detail::expand_pack(
399 : (get<Tags>(*this) =
400 : tuples_detail::forward<tag_type<Tags>>(get<Tags>(t)))...));
401 : return *this;
402 : }
403 :
404 : template <class... UTags,
405 : typename std::enable_if<
406 : sizeof...(Tags) == sizeof...(UTags) and
407 : tuples_detail::all<std::is_assignable<
408 : tag_type<Tags>&,
409 : tag_type<UTags> const&>::value...>::value>::type* = nullptr>
410 0 : TaggedTuple& operator=(TaggedTuple<UTags...> const& t) {
411 : static_cast<void>(
412 : tuples_detail::expand_pack((get<Tags>(*this) = get<UTags>(t))...));
413 : return *this;
414 : }
415 :
416 : template <
417 : class... UTags,
418 : typename std::enable_if<
419 : sizeof...(Tags) == sizeof...(UTags) and
420 : tuples_detail::all<std::is_assignable<
421 : tag_type<Tags>&, tag_type<UTags>&&>::value...>::value>::type* =
422 : nullptr>
423 0 : TaggedTuple& operator=(TaggedTuple<UTags...>&& t) {
424 : static_cast<void>(tuples_detail::expand_pack(
425 : (get<Tags>(*this) =
426 : tuples_detail::forward<tag_type<UTags>>(get<UTags>(t)))...));
427 : return *this;
428 : }
429 :
430 : // C++17 Draft 23.5.3.3 swap
431 0 : void swap(TaggedTuple& t) {
432 : tuples_detail::expand_pack(tuples_detail::TaggedTupleLeaf<Tags>::swap(
433 : static_cast<tuples_detail::TaggedTupleLeaf<Tags>&>(t))...);
434 : }
435 : };
436 :
437 : template <>
438 0 : class TaggedTuple<> {
439 : public:
440 0 : using tags_list = tmpl::list<>;
441 0 : static constexpr size_t size() { return 0; }
442 0 : TaggedTuple() = default;
443 0 : void swap(TaggedTuple& /*unused*/) {}
444 : // clang-tidy: runtime-references
445 0 : void pup(PUP::er& /*p*/) {} // NOLINT
446 : };
447 :
448 : // C++17 Draft 23.5.3.6 Tuple helper classes
449 : template <class T>
450 0 : struct tuple_size;
451 :
452 : template <class... Tags>
453 0 : struct tuple_size<TaggedTuple<Tags...>>
454 : : std::integral_constant<size_t, sizeof...(Tags)> {};
455 : template <class... Tags>
456 0 : struct tuple_size<const TaggedTuple<Tags...>>
457 : : tuple_size<TaggedTuple<Tags...>> {};
458 : template <class... Tags>
459 0 : struct tuple_size<volatile TaggedTuple<Tags...>>
460 : : tuple_size<TaggedTuple<Tags...>> {};
461 : template <class... Tags>
462 0 : struct tuple_size<const volatile TaggedTuple<Tags...>>
463 : : tuple_size<TaggedTuple<Tags...>> {};
464 :
465 : // C++17 Draft 23.5.3.7 Element access
466 : /// @{
467 : /*!
468 : * \ingroup UtilitiesGroup
469 : * \brief Retrieve the element of `Tag` in the TaggedTuple
470 : */
471 : template <class Tag, class... Tags>
472 1 : inline constexpr const typename Tag::type& get(const TaggedTuple<Tags...>& t) {
473 : static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
474 : TaggedTuple<Tags...>>::value,
475 : "Could not retrieve Tag from TaggedTuple. See the first "
476 : "template parameter of the instantiation for what Tag is being "
477 : "retrieved and the remaining template parameters for what Tags "
478 : "are available.");
479 : return static_cast<const tuples_detail::TaggedTupleLeaf<Tag>&>(t).get_data();
480 : }
481 : template <class Tag, class... Tags>
482 1 : inline constexpr typename Tag::type& get(TaggedTuple<Tags...>& t) {
483 : static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
484 : TaggedTuple<Tags...>>::value,
485 : "Could not retrieve Tag from TaggedTuple. See the first "
486 : "template parameter of the instantiation for what Tag is being "
487 : "retrieved and the remaining template parameters for what Tags "
488 : "are available.");
489 : return static_cast<tuples_detail::TaggedTupleLeaf<Tag>&>(t).get_data();
490 : }
491 : template <class Tag, class... Tags>
492 1 : inline constexpr const typename Tag::type&& get(
493 : const TaggedTuple<Tags...>&& t) {
494 : static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
495 : TaggedTuple<Tags...>>::value,
496 : "Could not retrieve Tag from TaggedTuple. See the first "
497 : "template parameter of the instantiation for what Tag is being "
498 : "retrieved and the remaining template parameters for what Tags "
499 : "are available.");
500 : return static_cast<const typename Tag::type&&>(
501 : static_cast<const tuples_detail::TaggedTupleLeaf<Tag>&&>(t).get_data());
502 : }
503 : template <class Tag, class... Tags>
504 1 : inline constexpr typename Tag::type&& get(TaggedTuple<Tags...>&& t) {
505 : static_assert(std::is_base_of<tuples_detail::TaggedTupleLeaf<Tag>,
506 : TaggedTuple<Tags...>>::value,
507 : "Could not retrieve Tag from TaggedTuple. See the first "
508 : "template parameter of the instantiation for what Tag is being "
509 : "retrieved and the remaining template parameters for what Tags "
510 : "are available.");
511 : return static_cast<typename Tag::type&&>(
512 : static_cast<tuples_detail::TaggedTupleLeaf<Tag>&&>(t).get_data());
513 : }
514 : /// @}
515 :
516 : template <size_t I, class... Tags>
517 0 : inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type&& get(
518 : TaggedTuple<Tags...>&& t) {
519 : return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
520 : }
521 :
522 : template <size_t I, class... Tags>
523 0 : inline constexpr const typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
524 : const TaggedTuple<Tags...>& t) {
525 : return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
526 : }
527 :
528 : template <size_t I, class... Tags>
529 0 : inline constexpr typename tmpl::at_c<tmpl::list<Tags...>, I>::type& get(
530 : TaggedTuple<Tags...>& t) {
531 : return get<tmpl::at_c<tmpl::list<Tags...>, I>>(t);
532 : }
533 :
534 : // C++17 Draft 23.5.3.8 Relational operators
535 : namespace tuples_detail {
536 : struct equal {
537 : template <class T, class U>
538 : static constexpr void apply(T const& lhs, U const& rhs, bool* result) {
539 : *result = *result and lhs == rhs;
540 : }
541 : };
542 :
543 : template <class... LTags, class... RTags>
544 : constexpr bool tuple_equal_impl(TaggedTuple<LTags...> const& lhs,
545 : TaggedTuple<RTags...> const& rhs) {
546 : bool equal = true;
547 : // This short circuits in the sense that the operator== is only evaluated if
548 : // the result thus far is true
549 : static_cast<void>(std::initializer_list<char>{
550 : (equal::apply(get<LTags>(lhs), get<RTags>(rhs), &equal), '0')...});
551 : return equal;
552 : }
553 : } // namespace tuples_detail
554 :
555 : template <class... LTags, class... RTags,
556 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
557 : nullptr>
558 0 : constexpr bool operator==(TaggedTuple<LTags...> const& lhs,
559 : TaggedTuple<RTags...> const& rhs) {
560 : return tuples_detail::tuple_equal_impl(lhs, rhs);
561 : }
562 :
563 : template <class... LTags, class... RTags,
564 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
565 : nullptr>
566 0 : constexpr bool operator!=(TaggedTuple<LTags...> const& lhs,
567 : TaggedTuple<RTags...> const& rhs) {
568 : return not(lhs == rhs);
569 : }
570 :
571 : namespace tuples_detail {
572 : struct less {
573 : template <class T, class U>
574 : static constexpr void apply(T const& lhs, U const& rhs,
575 : bool* last_rhs_less_lhs, bool* result) {
576 : if (*result or *last_rhs_less_lhs) {
577 : return;
578 : }
579 : *result = lhs < rhs;
580 : if (*result) {
581 : return;
582 : }
583 : *last_rhs_less_lhs = rhs < lhs;
584 : }
585 : };
586 :
587 : template <class... LTags, class... RTags>
588 : constexpr bool tuple_less_impl(TaggedTuple<LTags...> const& lhs,
589 : TaggedTuple<RTags...> const& rhs) {
590 : bool result = false;
591 : bool last_rhs_less_lhs = false;
592 : static_cast<void>(
593 : std::initializer_list<char>{(less::apply(get<LTags>(lhs), get<RTags>(rhs),
594 : &last_rhs_less_lhs, &result),
595 : '0')...});
596 : return result;
597 : }
598 : } // namespace tuples_detail
599 :
600 : template <class... LTags, class... RTags,
601 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
602 : nullptr>
603 0 : constexpr bool operator<(TaggedTuple<LTags...> const& lhs,
604 : TaggedTuple<RTags...> const& rhs) {
605 : return tuples_detail::tuple_less_impl(lhs, rhs);
606 : }
607 :
608 : template <class... LTags, class... RTags,
609 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
610 : nullptr>
611 0 : constexpr bool operator>(TaggedTuple<LTags...> const& lhs,
612 : TaggedTuple<RTags...> const& rhs) {
613 : return rhs < lhs;
614 : }
615 :
616 : template <class... LTags, class... RTags,
617 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
618 : nullptr>
619 0 : constexpr bool operator<=(TaggedTuple<LTags...> const& lhs,
620 : TaggedTuple<RTags...> const& rhs) {
621 : return not(rhs < lhs);
622 : }
623 :
624 : template <class... LTags, class... RTags,
625 : typename std::enable_if<sizeof...(LTags) == sizeof...(RTags)>::type* =
626 : nullptr>
627 0 : constexpr bool operator>=(TaggedTuple<LTags...> const& lhs,
628 : TaggedTuple<RTags...> const& rhs) {
629 : return not(lhs < rhs);
630 : }
631 :
632 : // C++17 Draft 23.5.3.3 swap
633 : template <
634 : class... Tags,
635 : typename std::enable_if<tuples_detail::all<tuples_detail::is_swappable_with<
636 : tuples_detail::TaggedTupleLeaf<Tags>,
637 : tuples_detail::TaggedTupleLeaf<Tags>>::value...>::value>::type* =
638 : nullptr>
639 0 : void swap(TaggedTuple<Tags...>& lhs, TaggedTuple<Tags...>& rhs) {
640 : lhs.swap(rhs);
641 : }
642 :
643 : namespace TaggedTuple_detail {
644 : template <typename T>
645 : struct tagged_tuple_typelist_impl;
646 :
647 : template <template <typename...> class List, typename... Tags>
648 : struct tagged_tuple_typelist_impl<List<Tags...>> {
649 : using type = TaggedTuple<Tags...>;
650 : };
651 : } // namespace TaggedTuple_detail
652 :
653 : /// \ingroup UtilitiesGroup
654 : template <typename T>
655 0 : using tagged_tuple_from_typelist =
656 : typename TaggedTuple_detail::tagged_tuple_typelist_impl<T>::type;
657 :
658 : namespace TaggedTuple_detail {
659 : template <typename... InputTags, typename... OutputTags>
660 : TaggedTuple<OutputTags...> reorder_impl(TaggedTuple<InputTags...>&& input,
661 : tmpl::list<OutputTags...> /*meta*/) {
662 : static_assert(
663 : std::is_same_v<tmpl::list_difference<tmpl::list<OutputTags...>,
664 : tmpl::list<InputTags...>>,
665 : tmpl::list<>> and
666 : std::is_same_v<tmpl::list_difference<tmpl::list<InputTags...>,
667 : tmpl::list<OutputTags...>>,
668 : tmpl::list<>>,
669 : "The input and output TaggedTuples must be the same except "
670 : "for ordering.");
671 : return TaggedTuple<OutputTags...>(std::move(get<OutputTags>(input))...);
672 : }
673 : } // namespace TaggedTuple_detail
674 :
675 : /// Given an input TaggedTuple, produce an output TaggedTuple
676 : /// with the tags in a different order. All tags must be the same
677 : /// except for ordering.
678 : /// \example
679 : /// \snippet Test_TaggedTuple.cpp reorder_example
680 : template <typename ReturnedTaggedTuple, typename... Tags>
681 1 : ReturnedTaggedTuple reorder(TaggedTuple<Tags...> input) {
682 : return TaggedTuple_detail::reorder_impl(
683 : std::move(input), typename ReturnedTaggedTuple::tags_list{});
684 : }
685 :
686 : /// Stream operator for TaggedTuple
687 : using ::operator<<;
688 : template <class... Tags>
689 0 : std::ostream& operator<<(std::ostream& os, const TaggedTuple<Tags...>& t) {
690 : os << "TaggedTuple:\n";
691 : const auto print_item = [&os, &t](auto tag_v) {
692 : using tag = tmpl::type_from<decltype(tag_v)>;
693 : using type = typename tag::type;
694 : os << "----------\n";
695 : os << "Name: " << pretty_type::get_name<tag>() << "\n";
696 : os << "Type: " << pretty_type::get_name<type>() << "\n";
697 : os << "Value: ";
698 : print_value(os, get<tag>(t));
699 : os << "\n";
700 : };
701 : tmpl::for_each<tmpl::list<Tags...>>(print_item);
702 : return os;
703 : }
704 :
705 : namespace TaggedTuple_detail {
706 :
707 : template <typename F, typename... Tags, typename... ApplyTags>
708 : constexpr decltype(auto) apply_impl(F&& f, const TaggedTuple<Tags...>& t,
709 : tmpl::list<ApplyTags...> /* meta */) {
710 : return std::forward<F>(f)(get<ApplyTags>(t)...);
711 : }
712 :
713 : } // namespace TaggedTuple_detail
714 :
715 : /// @{
716 : /*!
717 : * \ingroup UtilitiesGroup
718 : * \brief Invoke `f` with the `ApplyTags` taken from `t` expanded in a parameter
719 : * pack
720 : *
721 : * `ApplyTags` defaults to the full list of tags in `t`.
722 : *
723 : * Here is an example how to use the function:
724 : *
725 : * \snippet Test_TaggedTuple.cpp expand_tuple_example
726 : *
727 : * This is the function being called in the above example:
728 : *
729 : * \snippet Test_TaggedTuple.cpp expand_tuple_example_function
730 : *
731 : * \see std::apply
732 : */
733 : template <typename ApplyTags, typename F, typename... Tags>
734 1 : constexpr decltype(auto) apply(F&& f, const TaggedTuple<Tags...>& t) {
735 : return TaggedTuple_detail::apply_impl(std::forward<F>(f), t, ApplyTags{});
736 : }
737 :
738 : template <typename F, typename... Tags>
739 1 : constexpr decltype(auto) apply(F&& f, const TaggedTuple<Tags...>& t) {
740 : return TaggedTuple_detail::apply_impl(
741 : std::forward<F>(f), t, typename TaggedTuple<Tags...>::tags_list{});
742 : }
743 : /// @}
744 :
745 : /// @{
746 : /*!
747 : * Constructs a TaggedTuple that is a concatenation of two TaggedTuples.
748 : * \example
749 : * \snippet Test_TaggedTuple.cpp tagged_tuple_cat_example
750 : */
751 : template <typename... Tags1, typename... Tags2>
752 1 : tuples::TaggedTuple<Tags1..., Tags2...> tagged_tuple_cat(
753 : const tuples::TaggedTuple<Tags1...>& tuple1,
754 : const tuples::TaggedTuple<Tags2...>& tuple2) {
755 : return {get<Tags1>(tuple1)..., get<Tags2>(tuple2)...};
756 : }
757 :
758 : template <typename... Tags1, typename... Tags2>
759 1 : tuples::TaggedTuple<Tags1..., Tags2...> tagged_tuple_cat(
760 : tuples::TaggedTuple<Tags1...>&& tuple1,
761 : tuples::TaggedTuple<Tags2...>&& tuple2) {
762 : return {std::move(get<Tags1>(tuple1))..., std::move(get<Tags2>(tuple2))...};
763 : }
764 : /// @}
765 :
766 : } // namespace tuples
767 :
768 : namespace MakeWithValueImpls {
769 : /// \brief Makes a `TaggedTuple`; each element of the `TaggedTuple`
770 : /// must be `make_with_value`-creatable from a `T`.
771 : template <typename... Tags, typename T>
772 1 : struct MakeWithValueImpl<tuples::TaggedTuple<Tags...>, T> {
773 : template <typename ValueType>
774 0 : static SPECTRE_ALWAYS_INLINE tuples::TaggedTuple<Tags...> apply(
775 : const T& input, const ValueType value) {
776 : return tuples::TaggedTuple<Tags...>(
777 : make_with_value<typename Tags::type>(input, value)...);
778 : }
779 : };
780 :
781 : template <typename Tag, typename... Tags>
782 0 : struct NumberOfPoints<tuples::TaggedTuple<Tag, Tags...>> {
783 0 : static SPECTRE_ALWAYS_INLINE size_t apply(
784 : const tuples::TaggedTuple<Tag, Tags...>& input) {
785 : const size_t points = number_of_points(tuples::get<Tag>(input));
786 : ASSERT((... and (number_of_points(tuples::get<Tags>(input)) == points)),
787 : "Inconsistent number of points in tuple entries.");
788 : return points;
789 : }
790 : };
791 : } // namespace MakeWithValueImpls
792 :
793 : template <typename... Tags>
794 0 : struct SetNumberOfGridPointsImpls::SetNumberOfGridPointsImpl<
795 : tuples::TaggedTuple<Tags...>> {
796 0 : static constexpr bool is_trivial =
797 : (... and SetNumberOfGridPointsImpl<typename Tags::type>::is_trivial);
798 0 : static void apply(const gsl::not_null<tuples::TaggedTuple<Tags...>*> result,
799 : const size_t size) {
800 : expand_pack((set_number_of_grid_points(
801 : make_not_null(&tuples::get<Tags>(*result)), size),
802 : 0)...);
803 : }
804 : };
805 :
806 : namespace std {
807 : template <typename... Tags>
808 : struct tuple_size<tuples::TaggedTuple<Tags...>>
809 : : std::integral_constant<int, sizeof...(Tags)> {};
810 : template <size_t I, typename... Tags>
811 : struct tuple_element<I, tuples::TaggedTuple<Tags...>> {
812 : using type = typename tmpl::at_c<tmpl::list<Tags...>, I>::type;
813 : };
814 : } // namespace std
|