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