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