MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
tuple.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11#pragma once
12
13#include <ostream>
15#include <utility>
16#include <type_traits>
17#include <tuple>
18
19namespace mfem::future
20{
21
22// Forward declaration
23template <typename... T>
24struct tuple;
25
26// Implementation detail: storage using multiple inheritance from tuple_leaf,
27// which lets the tuple be defined for an arbitrary number of elements.
28// Structured bindings come from the std::tuple_size / std::tuple_element / get
29// specializations at the bottom of this file, not from the layout.
30namespace detail
31{
32/**
33 * @brief Trait that is true when @a U is a single argument that is (a reference
34 * to) @a Self
35 *
36 * A variadic constructor taking @c "U&&..." is a better match than the copy
37 * constructor for a non-const lvalue of its own type; this is used to constrain
38 * it out of those overload sets.
39 */
40template <typename Self, typename... U>
41struct is_self_arg : std::false_type {};
42
43/// @overload
44template <typename Self, typename U>
45struct is_self_arg<Self, U> : std::is_same<Self, std::decay_t<U>> {};
46
47/// SFINAE guard enabling a constructor for every @a U except @a Self itself
48template <typename Self, typename... U>
49using disable_if_self_t = std::enable_if_t<!is_self_arg<Self, U...>::value>;
50
51/**
52 * @brief A single tuple element storage
53 * @tparam I The index of this element in the tuple
54 * @tparam T The type stored in this element
55 */
56template <size_t I, typename T>
57struct tuple_leaf
58{
59 T value; ///< The stored value
60
61 /// Default constructor
62 MFEM_HOST_DEVICE constexpr tuple_leaf() = default;
63
64 /// Construct from value
65 template <typename U, typename = disable_if_self_t<tuple_leaf, U>>
66 MFEM_HOST_DEVICE constexpr explicit tuple_leaf(U&& v) :
67 value(std::forward<U>(v)) {}
68};
69
70/**
71 * @brief Implementation of tuple storage using multiple inheritance
72 * @tparam Indices Index sequence for tuple elements
73 * @tparam T The types stored in the tuple
74 *
75 * This uses multiple inheritance from tuple_leaf base classes so that a single
76 * definition covers any number of elements, while keeping the storage layout
77 * (and the trivial copyability that device kernels rely on) of a plain struct.
78 */
79template <typename Indices, typename... T>
80struct tuple_impl;
81
82/// Specialization that inherits from all tuple_leaf instances
83template <size_t... I, typename... T>
84struct tuple_impl<std::index_sequence<I...>, T...> : tuple_leaf<I, T>...
85{
86 /// Default constructor
87 MFEM_HOST_DEVICE constexpr tuple_impl() = default;
88
89 /**
90 * @brief Construct from values
91 * @param args The values to store in the tuple
92 *
93 * @note the arguments are perfectly forwarded, so that constructing a tuple
94 * from lvalues costs exactly one copy per element (taking them by value
95 * would add a copy plus a move).
96 */
97 template <typename... U, typename = disable_if_self_t<tuple_impl, U...>>
98 MFEM_HOST_DEVICE
99 constexpr explicit tuple_impl(U&&... args)
100 : tuple_leaf<I, T>(std::forward<U>(args))... {}
101 };
102
103/**
104 * @brief Element-wise constructibility check, only instantiated once the
105 * argument list is known to have the right length
106 * @tparam Viable whether the arity and self-argument checks have passed
107 * @tparam Tuple the @p tuple being constructed
108 * @tparam U the constructor argument types
109 */
110template <bool Viable, typename Tuple, typename... U>
111struct is_constructible_from : std::false_type {};
112
113/// @overload
114template <typename... T, typename... U>
115struct is_constructible_from<true, tuple<T...>, U...>
116: std::bool_constant<(std::is_constructible_v<T, U&&> && ...)> {};
117
118/**
119 * @brief Trait that is true when @a Tuple can be constructed element-wise from
120 * the argument list @a U
121 * @tparam Tuple the @p tuple being constructed
122 * @tparam U the constructor argument types
123 */
124template <typename Tuple, typename... U>
125struct is_elementwise_constructible : std::false_type {};
126
127/// @overload
128template <typename... T, typename... U>
129struct is_elementwise_constructible<tuple<T...>, U...>
130 : is_constructible_from<sizeof...(U) == sizeof...(T) && sizeof...(U) != 0 &&
131 !is_self_arg<tuple<T...>, U...>::value, tuple<T...>, U...> {};
132
133/// SFINAE guard for the element-wise constructor of @p tuple
134template <typename Tuple, typename... U>
135using enable_elementwise_t =
136 std::enable_if_t<is_elementwise_constructible<Tuple, U...>::value>;
137} // namespace detail
138
139/**
140 * @tparam T the types stored in the tuple
141 * @brief This is a class that mimics most of std::tuple's interface,
142 * except that it is usable in CUDA kernels and admits some arithmetic operator
143 * overloads.
144 *
145 * See https://en.cppreference.com/w/cpp/utility/tuple for more information
146 * about std::tuple.
147 */
148template <typename... T>
149struct tuple : detail::tuple_impl<std::index_sequence_for<T...>, T...>
150{
151 using base_type = detail::tuple_impl<std::index_sequence_for<T...>, T...>;
152
153 /// Default constructor
154 MFEM_HOST_DEVICE
155 constexpr tuple() = default;
156
157 /**
158 * @brief Construct tuple from values
159 * @param args The values to store
160 *
161 * @note this constructor is deliberately *not* explicit, so that the
162 * copy-list-initialization forms that worked when @p tuple was an aggregate
163 * (@c "tuple<A,B> t = {a,b};", @c "return {a,b};", passing @c "{a,b}" to a
164 * function) keep working.
165 */
166 template <typename... U,
167 typename = detail::enable_elementwise_t<tuple, U...>>
168 MFEM_HOST_DEVICE
169 constexpr tuple(U&&... args) : base_type(std::forward<U>(args)...) {}
170
171 /// Copy constructor
172 MFEM_HOST_DEVICE
173 constexpr tuple(const tuple&) = default;
174
175 /// Move constructor
176 MFEM_HOST_DEVICE
177 constexpr tuple(tuple&&) = default;
178
179 /// Copy assignment operator
180 MFEM_HOST_DEVICE
181 constexpr tuple& operator=(const tuple&) = default;
182
183 /// Move assignment operator
184 MFEM_HOST_DEVICE
185 constexpr tuple& operator=(tuple&&) = default;
186};
187
188/**
189 * @brief Specialization for empty tuple
190 */
191template <>
193{
194 /// Default constructor
195 MFEM_HOST_DEVICE constexpr tuple() = default;
196};
197
198/**
199 * @brief Class template argument deduction rule for tuples
200 * @tparam T the variadic template parameter for tuple types
201 */
202template <typename... T>
203MFEM_HOST_DEVICE
204tuple(T...) -> tuple<T...>;
205
206/**
207 * @brief helper function for combining a list of values into a tuple
208 * @tparam T types of the values to be tuple-d
209 * @param args the actual values to be put into a tuple
210 */
211template <typename... T>
212MFEM_HOST_DEVICE constexpr tuple<T...> make_tuple(const T&... args)
213{
214 return tuple<T...> {args...};
215}
216
217/**
218 * @brief Get the size of a tuple type
219 * @tparam Types the types in the tuple
220 */
221template <class... Types>
223
224template <class... Types>
225struct tuple_size<tuple<Types...> >
226: std::integral_constant<std::size_t, sizeof...(Types)> {};
227
228/**
229 * @brief a struct used to determine the type at index I of a tuple
230 *
231 * @note see: https://en.cppreference.com/w/cpp/utility/tuple/tuple_element
232 *
233 * @tparam I the index of the desired type
234 * @tparam T a tuple of different types
235 */
236template <size_t I, class T>
238
239// recursive case
240/// @overload
241template <size_t I, class Head, class... Tail>
242struct tuple_element<I, tuple<Head, Tail...> >
243 : tuple_element<I - 1, tuple<Tail...>> {};
244
245// base case
246/// @overload
247template <class Head, class... Tail>
248struct tuple_element<0, tuple<Head, Tail...>>
249{
250 using type = Head; ///< the type at the specified index
251};
252
253namespace detail
254{
255/**
256 * @brief Get implementation for tuple_leaf - non-const lvalue reference
257 * @tparam I the index of the tuple element
258 * @tparam T the type of the tuple element
259 * @param leaf the tuple_leaf containing the value
260 * @return reference to the value
261 *
262 * @note @a T is deduced from the (unique) @p tuple_leaf base class of the
263 * argument, so callers only have to supply the index @a I.
264 */
265template <size_t I, typename T>
266MFEM_HOST_DEVICE constexpr T& get_impl(tuple_leaf<I, T>& leaf)
267{
268 return leaf.value;
269}
270
271/**
272 * @brief Get implementation for tuple_leaf - const lvalue reference
273 * @tparam I the index of the tuple element
274 * @tparam T the type of the tuple element
275 * @param leaf the tuple_leaf containing the value
276 * @return const reference to the value
277 */
278template <size_t I, typename T>
279MFEM_HOST_DEVICE constexpr const T& get_impl(const tuple_leaf<I, T>& leaf)
280{
281 return leaf.value;
282}
283
284/**
285 * @brief Get implementation for tuple_leaf - non-const rvalue reference
286 * @tparam I the index of the tuple element
287 * @tparam T the type of the tuple element
288 * @param leaf the tuple_leaf containing the value
289 * @return rvalue reference to the value
290 */
291template <size_t I, typename T>
292MFEM_HOST_DEVICE constexpr T&& get_impl(tuple_leaf<I, T>&& leaf)
293{
294 return static_cast<T&&>(leaf.value);
295}
296
297/**
298 * @brief Get implementation for tuple_leaf - const rvalue reference
299 * @tparam I the index of the tuple element
300 * @tparam T the type of the tuple element
301 * @param leaf the tuple_leaf containing the value
302 * @return const rvalue reference to the value
303 */
304template <size_t I, typename T>
305MFEM_HOST_DEVICE constexpr const T&& get_impl(const tuple_leaf<I, T>&& leaf)
306{
307 return static_cast<const T&&>(leaf.value);
308}
309} // namespace detail
310
311/**
312 * @tparam I the tuple index to access
313 * @tparam T the types stored in the tuple
314 * @brief return a reference to the ith tuple entry
315 * @param t the tuple to access
316 */
317template <size_t I, typename... T>
318MFEM_HOST_DEVICE constexpr auto& get(tuple<T...>& t)
319{
320 static_assert(I < sizeof...(T), "Tuple index out of bounds");
321 return detail::get_impl<I>(t);
322}
323
324/**
325 * @tparam I the tuple index to access
326 * @tparam T the types stored in the tuple
327 * @brief return a const reference to the ith tuple entry
328 * @param t the tuple to access
329 */
330template <size_t I, typename... T>
331MFEM_HOST_DEVICE constexpr const auto& get(const tuple<T...>& t)
332{
333 static_assert(I < sizeof...(T), "Tuple index out of bounds");
334 return detail::get_impl<I>(t);
335}
336
337/**
338 * @tparam I the tuple index to access
339 * @tparam T the types stored in the tuple
340 * @brief return an rvalue reference to the ith tuple entry
341 * @param t the tuple to access
342 */
343template <size_t I, typename... T>
344MFEM_HOST_DEVICE constexpr auto&& get(tuple<T...>&& t)
345{
346 static_assert(I < sizeof...(T), "Tuple index out of bounds");
347 return detail::get_impl<I>(std::move(t));
348}
349
350/**
351 * @tparam I the tuple index to access
352 * @tparam T the types stored in the tuple
353 * @brief return a const rvalue reference to the ith tuple entry
354 * @param t the tuple to access
355 */
356template <size_t I, typename... T>
357MFEM_HOST_DEVICE constexpr const auto&& get(const tuple<T...>&& t)
358{
359 static_assert(I < sizeof...(T), "Tuple index out of bounds");
360 return detail::get_impl<I>(std::move(t));
361}
362
363/**
364 * @brief a function intended to be used for extracting the ith type from a
365 * tuple.
366 *
367 * @note type<i>(my_tuple) returns a value, whereas get<i>(my_tuple) returns a
368 * reference
369 *
370 * @tparam I the index of the tuple to query
371 * @tparam T the types stored in the tuple
372 * @param t the tuple of values
373 * @return a copy of the ith entry of the input
374 */
375template <size_t I, typename... T>
376MFEM_HOST_DEVICE constexpr auto type(const tuple<T...>& t)
377{
378 static_assert(I < sizeof...(T), "Tuple index out of bounds");
379 return get<I>(t);
380}
381
382namespace detail
383{
384/**
385 * @brief Helper for applying binary operations element-wise
386 *
387 * @tparam Op The binary operation type
388 * @tparam S the types stored in the tuple x
389 * @tparam T the types stored in the tuple y
390 * @tparam I The integer sequence for indexing
391 * @param x first tuple of values
392 * @param y second tuple of values
393 * @param op the binary operation to apply
394 * @return tuple containing the result of applying op to each element pair
395 */
396template <typename Op, typename... S, typename... T, size_t... I>
397MFEM_HOST_DEVICE constexpr auto apply_op_helper(
398 const tuple<S...>& x,
399 const tuple<T...>& y,
400 Op op,
401 std::index_sequence<I...>)
402{
403 return tuple{op(get<I>(x), get<I>(y))...};
404}
405} // namespace detail
406
407/**
408 * @tparam S the types stored in the tuple x
409 * @tparam T the types stored in the tuple y
410 * @param x a tuple of values
411 * @param y a tuple of values
412 * @brief return a tuple of values defined by elementwise sum of x and y
413 */
414template <typename... S, typename... T>
415MFEM_HOST_DEVICE constexpr auto operator+(const tuple<S...>& x,
416 const tuple<T...>& y)
417{
418 static_assert(sizeof...(S) == sizeof...(T), "tuples must have same size");
419 return detail::apply_op_helper(x, y,
420 [](const auto& a, const auto& b) { return a + b; },
421 std::make_index_sequence<sizeof...(S)> {});
422}
423
424/**
425 * @tparam S the types stored in the tuple x
426 * @tparam T the types stored in the tuple y
427 * @param x a tuple of values
428 * @param y a tuple of values
429 * @brief return a tuple of values defined by elementwise difference of x and y
430 */
431template <typename... S, typename... T>
432MFEM_HOST_DEVICE constexpr auto operator-(const tuple<S...>& x,
433 const tuple<T...>& y)
434{
435 static_assert(sizeof...(S) == sizeof...(T), "tuples must have same size");
436 return detail::apply_op_helper(x, y,
437 [](const auto& a, const auto& b) { return a - b; },
438 std::make_index_sequence<sizeof...(S)> {});
439}
440
441/**
442 * @tparam S the types stored in the tuple x
443 * @tparam T the types stored in the tuple y
444 * @param x a tuple of values
445 * @param y a tuple of values
446 * @brief return a tuple of values defined by elementwise multiplication of x
447 * and y
448 */
449template <typename... S, typename... T>
450MFEM_HOST_DEVICE constexpr auto operator*(const tuple<S...>& x,
451 const tuple<T...>& y)
452{
453 static_assert(sizeof...(S) == sizeof...(T), "tuples must have same size");
454 return detail::apply_op_helper(x, y,
455 [](const auto& a, const auto& b) { return a * b; },
456 std::make_index_sequence<sizeof...(S)> {});
457}
458
459/**
460 * @tparam S the types stored in the tuple x
461 * @tparam T the types stored in the tuple y
462 * @param x a tuple of values
463 * @param y a tuple of values
464 * @brief return a tuple of values defined by elementwise division of x by y
465 */
466template <typename... S, typename... T>
467MFEM_HOST_DEVICE constexpr auto operator/(const tuple<S...>& x,
468 const tuple<T...>& y)
469{
470 static_assert(sizeof...(S) == sizeof...(T), "tuples must have same size");
471 return detail::apply_op_helper(x, y,
472 [](const auto& a, const auto& b) { return a / b; },
473 std::make_index_sequence<sizeof...(S)> {});
474}
475
476namespace detail
477{
478/**
479 * @brief A helper function for the += operator of tuples
480 *
481 * @tparam T the types stored in the tuples x and y
482 * @tparam I integer sequence used to index the tuples
483 * @param x tuple of values to be incremented
484 * @param y tuple of increment values
485 */
486template <typename... T, size_t... I>
487MFEM_HOST_DEVICE constexpr void inplace_add_helper(
488 tuple<T...>& x,
489 const tuple<T...>& y,
490 std::index_sequence<I...>)
491{
492 ((get<I>(x) += get<I>(y)), ...);
493}
494} // namespace detail
495
496/**
497 * @tparam T the types stored in the tuples x and y
498 * @param x a tuple of values
499 * @param y a tuple of values
500 * @brief add values contained in y, to the tuple x
501 */
502template <typename... T>
503MFEM_HOST_DEVICE constexpr tuple<T...>& operator+=(tuple<T...>& x,
504 const tuple<T...>& y)
505{
506 detail::inplace_add_helper(x, y, std::make_index_sequence<sizeof...(T)> {});
507 return x;
508}
509
510namespace detail
511{
512/**
513 * @brief A helper function for the -= operator of tuples
514 *
515 * @tparam T the types stored in the tuples x and y
516 * @tparam I integer sequence used to index the tuples
517 * @param x tuple of values to be subtracted from
518 * @param y tuple of values to subtract from x
519 */
520template <typename... T, size_t... I>
521MFEM_HOST_DEVICE constexpr void inplace_sub_helper(
522 tuple<T...>& x,
523 const tuple<T...>& y,
524 std::index_sequence<I...>)
525{
526 ((get<I>(x) -= get<I>(y)), ...);
527}
528} // namespace detail
529
530/**
531 * @tparam T the types stored in the tuples x and y
532 * @param x a tuple of values
533 * @param y a tuple of values
534 * @brief subtract values contained in y from the tuple x
535 */
536template <typename... T>
537MFEM_HOST_DEVICE constexpr tuple<T...>& operator-=(tuple<T...>& x,
538 const tuple<T...>& y)
539{
540 detail::inplace_sub_helper(x, y, std::make_index_sequence<sizeof...(T)> {});
541 return x;
542}
543
544namespace detail
545{
546/**
547 * @brief A helper function for the unary - operator of tuples
548 *
549 * @tparam T the types stored in the tuple x
550 * @tparam I The integer sequence for indexing
551 * @param x tuple of values
552 * @return the returned tuple with negated values
553 */
554template <typename... T, size_t... I>
555MFEM_HOST_DEVICE constexpr auto unary_minus_helper(
556 const tuple<T...>& x,
557 std::index_sequence<I...>)
558{
559 return tuple{-get<I>(x)...};
560}
561} // namespace detail
562
563/**
564 * @tparam T the types stored in the tuple x
565 * @param x a tuple of values
566 * @brief return a tuple of values defined by applying the unary minus operator
567 * to each element of x
568 */
569template <typename... T>
570MFEM_HOST_DEVICE constexpr auto operator-(const tuple<T...>& x)
571{
572 return detail::unary_minus_helper(
573 x, std::make_index_sequence<sizeof...(T)> {});
574}
575
576namespace detail
577{
578/**
579 * @brief A helper function for the * operator of tuples with scalar
580 *
581 * @tparam T the types stored in the tuple x
582 * @tparam I The integer sequence for indexing
583 * @param a a constant multiplier
584 * @param x tuple of values
585 * @return the returned tuple product
586 */
587template <typename scalar_t, typename... T, size_t... I>
588MFEM_HOST_DEVICE constexpr auto scalar_mult_helper(
589 scalar_t a,
590 const tuple<T...>& x,
591 std::index_sequence<I...>)
592{
593 return tuple{a * get<I>(x)...};
594}
595} // namespace detail
596
597/**
598 * @tparam T the types stored in the tuple
599 * @param a a scaling factor
600 * @param x the tuple object
601 * @brief multiply each component of x by the value a on the left
602 */
603template <typename scalar_t, typename... T>
604MFEM_HOST_DEVICE constexpr auto operator*(scalar_t a, const tuple<T...>& x)
605{
606 return detail::scalar_mult_helper(
607 a, x, std::make_index_sequence<sizeof...(T)> {});
608}
609
610/**
611 * @tparam T the types stored in the tuple
612 * @param x the tuple object
613 * @param a a scaling factor
614 * @brief multiply each component of x by the value a on the right
615 */
616template <typename scalar_t, typename... T>
617MFEM_HOST_DEVICE constexpr auto operator*(const tuple<T...>& x, scalar_t a)
618{
619 return a * x;
620}
621
622namespace detail
623{
624/**
625 * @brief A helper function for the / operator of tuples with scalar denominator
626 *
627 * @tparam T the types stored in the tuple x
628 * @tparam I The integer sequence for indexing
629 * @param x tuple of values
630 * @param a the constant denominator
631 * @return the returned tuple ratio
632 */
633template <typename scalar_t, typename... T, size_t... I>
634MFEM_HOST_DEVICE constexpr auto scalar_div_helper(
635 const tuple<T...>& x,
636 scalar_t a,
637 std::index_sequence<I...>)
638{
639 return tuple{get<I>(x) / a...};
640}
641} // namespace detail
642
643/**
644 * @tparam T the types stored in the tuple x
645 * @param x a tuple of numerator values
646 * @param a a denominator
647 * @brief return a tuple of values defined by elementwise division of x by a
648 */
649template <typename scalar_t, typename... T>
650MFEM_HOST_DEVICE constexpr auto operator/(const tuple<T...>& x, scalar_t a)
651{
652 return detail::scalar_div_helper(
653 x, a, std::make_index_sequence<sizeof...(T)> {});
654}
655
656namespace detail
657{
658/**
659 * @brief A helper function for the / operator with scalar numerator
660 *
661 * @tparam T the types stored in the tuple x
662 * @tparam I The integer sequence for indexing
663 * @param a the constant numerator
664 * @param x tuple of values
665 * @return the returned tuple ratio
666 */
667template <typename scalar_t, typename... T, size_t... I>
668MFEM_HOST_DEVICE constexpr auto scalar_div_inv_helper(
669 scalar_t a,
670 const tuple<T...>& x,
671 std::index_sequence<I...>)
672{
673 return tuple{a / get<I>(x)...};
674}
675} // namespace detail
676
677/**
678 * @tparam T the types stored in the tuple x
679 * @param a the numerator
680 * @param x a tuple of denominator values
681 * @brief return a tuple of values defined by division of a by the elements of x
682 */
683template <typename scalar_t, typename... T>
684MFEM_HOST_DEVICE constexpr auto operator/(scalar_t a, const tuple<T...>& x)
685{
686 return detail::scalar_div_inv_helper(
687 a, x, std::make_index_sequence<sizeof...(T)> {});
688}
689
690namespace detail
691{
692/**
693 * @tparam T the types stored in the tuple
694 * @tparam I a list of indices used to access each element of the tuple
695 * @param out the ostream to write the output to
696 * @param t the tuple of values
697 * @brief helper used to implement printing a tuple of values
698 */
699template <typename... T, size_t... I>
700auto& print_helper(std::ostream& out, const tuple<T...>& t,
701 std::index_sequence<I...>)
702{
703 out << "tuple{";
704 (..., (out << (I == 0 ? "" : ", ") << get<I>(t)));
705 out << "}";
706 return out;
707}
708} // namespace detail
709
710/**
711 * @tparam T the types stored in the tuple
712 * @param out the ostream to write the output to
713 * @param t the tuple of values
714 * @brief print a tuple of values
715 */
716template <typename... T>
717auto& operator<<(std::ostream& out, const tuple<T...>& t)
718{
719 return detail::print_helper(
720 out, t, std::make_index_sequence<sizeof...(T)> {});
721}
722
723namespace detail
724{
725/**
726 * @brief A helper to apply a lambda to a tuple
727 *
728 * @tparam F The functor type
729 * @tparam T The tuple types
730 * @tparam I The integer sequence for indexing
731 * @param f The functor to apply to the tuple
732 * @param args The input tuple
733 * @return The functor output
734 */
735template <typename F, typename... T, size_t... I>
736MFEM_HOST_DEVICE auto apply_helper(F&& f, tuple<T...>& args,
737 std::index_sequence<I...>)
738{
739 return std::forward<F>(f)(get<I>(args)...);
740}
741} // namespace detail
742
743/**
744 * @tparam F a callable type
745 * @tparam T the types of arguments to be passed in to f
746 * @param f the callable object
747 * @param args a tuple of arguments
748 * @brief a way of passing an n-tuple to a function that expects n separate
749 * arguments
750 *
751 * For example, foo(bar, baz) is equivalent to apply(foo, mfem::tuple(bar,baz)).
752 */
753template <typename F, typename... T>
754MFEM_HOST_DEVICE auto apply(F&& f, tuple<T...>& args)
755{
756 return detail::apply_helper(std::forward<F>(f), args,
757 std::make_index_sequence<sizeof...(T)> {});
758}
759
760namespace detail
761{
762/**
763 * @overload
764 */
765template <typename F, typename... T, size_t... I>
766MFEM_HOST_DEVICE auto apply_helper(F&& f, const tuple<T...>& args,
767 std::index_sequence<I...>)
768{
769 return std::forward<F>(f)(get<I>(args)...);
770}
771} // namespace detail
772
773/**
774 * @tparam F a callable type
775 * @tparam T the types of arguments to be passed in to f
776 * @param f the callable object
777 * @param args a tuple of arguments
778 * @brief a way of passing an n-tuple to a function that expects n separate
779 * arguments
780 *
781 * For example, foo(bar, baz) is equivalent to apply(foo, mfem::tuple(bar,baz)).
782 */
783template <typename F, typename... T>
784MFEM_HOST_DEVICE auto apply(F&& f, const tuple<T...>& args)
785{
786 return detail::apply_helper(std::forward<F>(f), args,
787 std::make_index_sequence<sizeof...(T)> {});
788}
789
790/**
791 * @brief Trait for checking if a type is a @p mfem::tuple
792 */
793template <typename T>
794struct is_tuple : std::false_type
795{
796};
797
798/// @overload
799template <typename... T>
800struct is_tuple<tuple<T...>> : std::true_type
801{
802};
803
804/**
805 * @brief Trait for checking if a type if a @p mfem::tuple containing only
806 * @p mfem::tuple
807 */
808template <typename T>
809struct is_tuple_of_tuples : std::false_type
810{
811};
812
813/**
814 * @brief Trait for checking if a type if a @p mfem::tuple containing only
815 * @p mfem::tuple
816 */
817template <typename... T>
819{
820 static constexpr bool value = (is_tuple<T>::value &&
821 ...); ///< true/false result of type check
822};
823
824/** @brief Auxiliary template function that merges (concatenates) two
825 mfem::future::tuple types into a single std::tuple that is empty, i.e. it is
826 value initialized. */
827template <typename... T1s, typename... T2s>
829 const tuple<T1s...>&,
830 const tuple<T2s...>&)
831{
832 return std::tuple<T1s..., T2s...> {};
833}
834
835} // namespace mfem::future
836
837// Enable structured bindings for mfem::future::tuple
838namespace std
839{
840/**
841 * @brief Specialization of std::tuple_size for mfem::future::tuple
842 * @tparam T The types in the mfem::future::tuple
843 */
844template <typename... T>
845struct tuple_size<mfem::future::tuple<T...> >
846: integral_constant<size_t, sizeof...(T)> {};
847
848/**
849 * @brief Specialization of std::tuple_element for mfem::future::tuple
850 * @tparam I The index of the element
851 * @tparam T The types in the mfem::future::tuple
852 */
853template <size_t I, typename... T>
854struct tuple_element<I, mfem::future::tuple<T...>>
855{
856 using type = typename
858};
859} // namespace std
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
MFEM_HOST_DEVICE constexpr auto operator-(dual< value_type, gradient_type > x) -> dual< value_type, gradient_type >
unary negation of a dual number
Definition dual.hpp:112
MFEM_HOST_DEVICE constexpr auto operator+(dual< value_type, gradient_type > a, other_type b) -> dual< value_type, gradient_type >
addition of a dual number and a non-dual number
Definition dual.hpp:74
MFEM_HOST_DEVICE constexpr auto type(const tuple< T... > &t)
a function intended to be used for extracting the ith type from a tuple.
Definition tuple.hpp:376
gradient_type MFEM_HOST_DEVICE dual< value_type, gradient_type > & operator+=(dual< value_type, gradient_type > &a, const dual< value_type, gradient_type > &b)
Definition dual.hpp:243
MFEM_HOST_DEVICE auto apply(F &&f, tuple< T... > &args)
a way of passing an n-tuple to a function that expects n separate arguments
Definition tuple.hpp:754
MFEM_HOST_DEVICE tuple(T...) -> tuple< T... >
Class template argument deduction rule for tuples.
MFEM_HOST_DEVICE dual< value_type, gradient_type > & operator-=(dual< value_type, gradient_type > &a, const dual< value_type, gradient_type > &b)
compound assignment (-) for dual numbers
Definition dual.hpp:253
MFEM_HOST_DEVICE constexpr tuple< T... > make_tuple(const T &... args)
helper function for combining a list of values into a tuple
Definition tuple.hpp:212
std::ostream & operator<<(std::ostream &os, dual< value_type, gradient_type > A)
overload of operator<< for dual to work with work with standard output streams
Definition dual.hpp:412
MFEM_HOST_DEVICE constexpr auto operator*(const dual< value_type, gradient_type > &a, real_t b) -> dual< decltype(a.value *b), decltype(a.gradient *b)>
multiplication of a dual number and a non-dual number
Definition dual.hpp:146
MFEM_HOST_DEVICE constexpr auto operator/(const dual< value_type, gradient_type > &a, real_t b) -> dual< decltype(a.value/b), decltype(a.gradient/b)>
division of a dual number by a non-dual number
Definition dual.hpp:173
MFEM_HOST_DEVICE zero & get(zero &x)
let zero be accessed like a tuple
Definition tensor.hpp:281
constexpr auto merge_mfem_tuples_as_empty_std_tuple(const tuple< T1s... > &, const tuple< T2s... > &)
Auxiliary template function that merges (concatenates) two mfem::future::tuple types into a single st...
Definition tuple.hpp:828
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
STL namespace.
Trait for checking if a type if a mfem::tuple containing only mfem::tuple.
Definition tuple.hpp:810
Trait for checking if a type is a mfem::tuple.
Definition tuple.hpp:795
Specialization for empty tuple.
Definition tuple.hpp:193
MFEM_HOST_DEVICE constexpr tuple()=default
Default constructor.
Head type
the type at the specified index
Definition tuple.hpp:250
a struct used to determine the type at index I of a tuple
Definition tuple.hpp:237
Get the size of a tuple type.
Definition tuple.hpp:222
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...
Definition tuple.hpp:150
MFEM_HOST_DEVICE constexpr tuple(U &&... args)
Construct tuple from values.
Definition tuple.hpp:169
detail::tuple_impl< std::index_sequence_for< T... >, T... > base_type
Definition tuple.hpp:151
MFEM_HOST_DEVICE constexpr tuple()=default
Default constructor.
MFEM_HOST_DEVICE constexpr tuple & operator=(const tuple &)=default
Copy assignment operator.
MFEM_HOST_DEVICE constexpr tuple & operator=(tuple &&)=default
Move assignment operator.
MFEM_HOST_DEVICE constexpr tuple(tuple &&)=default
Move constructor.
MFEM_HOST_DEVICE constexpr tuple(const tuple &)=default
Copy constructor.
typename mfem::future::tuple_element< I, mfem::future::tuple< T... > >::type type
Definition tuple.hpp:856