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