Block-Structured AMR Software Framework
AMReX_Tuple.H
Go to the documentation of this file.
1 
2 #ifndef AMREX_TUPLE_H_
3 #define AMREX_TUPLE_H_
4 #include <AMReX_Config.H>
5 
6 #include <AMReX_Array.H>
7 #include <AMReX_Functional.H>
8 #include <AMReX_GpuQualifiers.H>
9 #include <AMReX_TypeList.H>
10 #include <AMReX_TypeTraits.H>
11 
12 #include <array>
13 #include <functional>
14 #include <tuple>
15 
16 namespace amrex {
17  template <class... Ts>
18  using Tuple = std::tuple<Ts...>;
19 }
20 
21 namespace amrex {
22 
23 namespace detail {
24 
25 template <std::size_t I, typename T>
27 {
28  template <typename U=T, std::enable_if_t<std::is_default_constructible_v<U>,int> = 0>
30  constexpr gpu_tuple_element () {} // NOLINT
31 
32  explicit constexpr gpu_tuple_element (T const& a_value)
33  : m_value(a_value)
34  {}
35 
36  template <typename U, std::enable_if_t<std::is_convertible_v<U&&,T>,int> = 0>
37  explicit constexpr gpu_tuple_element (U && a_value) // NOLINT(bugprone-forwarding-reference-overload)
38  : m_value(std::forward<U>(a_value))
39  {}
40 
41  T m_value{};
42 };
43 
44 template <std::size_t I, typename... Ts> struct gpu_tuple_impl;
45 
46 template <std::size_t I, typename Head, typename... Tail>
47 struct gpu_tuple_impl<I, Head, Tail...>
48  : public gpu_tuple_impl<I+1, Tail...>,
49  public gpu_tuple_element<I, Head>
50 {
51  template<typename U=Head, std::enable_if_t<std::is_default_constructible_v<U>,int> = 0>
53  constexpr gpu_tuple_impl () {} // NOLINT
54 
55  constexpr gpu_tuple_impl (Head const& a_head, Tail const&... a_tail)
56  : gpu_tuple_impl<I+1, Tail...>(a_tail...),
57  gpu_tuple_element<I, Head>(a_head)
58  {}
59 
60  template <typename UH, typename... UT, std::enable_if_t<std::is_convertible_v<UH&&,Head>,int> = 0>
61  constexpr gpu_tuple_impl (UH&& a_head, UT &&... a_tail)
62  : gpu_tuple_impl<I+1, Tail...>(std::forward<UT>(a_tail)...),
63  gpu_tuple_element<I, Head>(std::forward<UH>(a_head))
64  {}
65 };
66 
67 template <std::size_t I, typename Head>
68 struct gpu_tuple_impl<I, Head>
69  : public gpu_tuple_element<I, Head>
70 {
71 
72  template<typename U=Head, std::enable_if_t<std::is_default_constructible_v<U>,int> = 0>
74  constexpr gpu_tuple_impl () {} // NOLINT
75 
76  explicit constexpr gpu_tuple_impl (Head const& a_head)
77  : gpu_tuple_element<I, Head>(a_head)
78  {}
79 
80  template <typename U, std::enable_if_t<std::is_convertible_v<U&&,Head>,int> = 0>
81  explicit constexpr gpu_tuple_impl (U&& a_head) // NOLINT(bugprone-forwarding-reference-overload)
82  : gpu_tuple_element<I, Head>(std::forward<U>(a_head))
83  {}
84 };
85 
86 } // detail
87 
88 // GpuTuple
89 
90 template <typename... Ts>
91 class GpuTuple
92  : public detail::gpu_tuple_impl<0, Ts...>
93 {
94 public:
95  AMREX_GPU_HOST_DEVICE // Some versions of nvcc require this in debug build
96  constexpr GpuTuple () = default;
97 
98  constexpr GpuTuple (Ts const&... args)
99  : detail::gpu_tuple_impl<0, Ts...>(args...)
100  {}
101 
102  template <typename... Us, std::enable_if_t<sizeof...(Us) == sizeof...(Ts),int> = 0>
103  constexpr GpuTuple (Us&&... args)
104  : detail::gpu_tuple_impl<0, Ts...>(std::forward<Us>(args)...)
105  {}
106 
107  template <typename... Us, std::enable_if_t<sizeof...(Us) == sizeof...(Ts),int> = 0>
109  inline GpuTuple<Ts...>&
111 
112  template <typename... Us, std::enable_if_t<sizeof...(Us) == sizeof...(Ts),int> = 0>
114  inline GpuTuple<Ts...>&
116 };
117 
118 // GpuTupleSize
119 
120 template <typename T> struct GpuTupleSize;
121 
122 template <typename... Ts>
123 struct GpuTupleSize<GpuTuple<Ts...> >
124  : public std::integral_constant<std::size_t, sizeof...(Ts)> {};
125 
126 // GpuTupleElement
127 
128 template <std::size_t I, typename T> struct GpuTupleElement;
129 
130 template <std::size_t I, typename Head, typename... Tail>
131 struct GpuTupleElement<I, GpuTuple<Head, Tail...> >
132  : GpuTupleElement<I-1, GpuTuple<Tail...> > {};
133 
134 template <typename Head, typename... Tail>
135 struct GpuTupleElement<0, GpuTuple<Head, Tail...> > {
136  using type = Head;
137 };
138 
139 // get
140 
141 namespace detail {
142 
143 template <std::size_t I, typename... Ts>
145 constexpr
146 typename GpuTupleElement<I, GpuTuple<Ts...> >::type&
148  <I, typename GpuTupleElement<I, GpuTuple<Ts...> >::type>& te) noexcept
149 {
150  return te.m_value;
151 }
152 
153 template <std::size_t I, typename... Ts>
155 constexpr
156 typename GpuTupleElement<I, GpuTuple<Ts...> >::type const&
158  <I, typename GpuTupleElement<I, GpuTuple<Ts...> >::type> const& te) noexcept
159 {
160  return te.m_value;
161 }
162 
163 template <std::size_t I, typename... Ts>
165 constexpr
166 typename GpuTupleElement<I, GpuTuple<Ts...> >::type &&
168  <I, typename GpuTupleElement<I, GpuTuple<Ts...> >::type> && te) noexcept
169 {
170  return std::move(te).m_value;
171 }
172 
173 } // detail
174 
175 template <std::size_t I, typename... Ts>
177 constexpr
178 typename GpuTupleElement<I, GpuTuple<Ts...> >::type&
179 get (GpuTuple<Ts...>& tup) noexcept
180 {
181  return detail::get_impl<I,Ts...>(tup);
182 }
183 
184 template <std::size_t I, typename... Ts>
186 constexpr
187 typename GpuTupleElement<I, GpuTuple<Ts...> >::type const&
188 get (GpuTuple<Ts...> const& tup) noexcept
189 {
190  return detail::get_impl<I,Ts...>(tup);
191 }
192 
193 template <std::size_t I, typename... Ts>
195 constexpr
196 typename GpuTupleElement<I, GpuTuple<Ts...> >::type &&
197 get (GpuTuple<Ts...> && tup) noexcept
198 {
199  return detail::get_impl<I,Ts...>(std::move(tup));
200 }
201 
202 namespace detail {
203  template <std::size_t I, std::size_t N, typename TP1, typename TP2>
205  std::enable_if_t<(I<N-1),void>
206  tuple_copy (TP1 & a, TP2 && b)
207  {
208  (amrex::get<I>(a) = amrex::get<I>(std::forward<TP2>(b)),
209  tuple_copy<I+1,N>(a,std::forward<TP2>(b)));
210  }
211 
212  template <std::size_t I, std::size_t N, typename TP1, typename TP2>
214  std::enable_if_t<I==N-1,void>
215  tuple_copy (TP1 & a, TP2 && b)
216  {
217  amrex::get<I>(a) = amrex::get<I>(std::forward<TP2>(b));
218  }
219 }
220 
221 template <typename... Ts>
222 template <typename... Us, std::enable_if_t<sizeof...(Us) == sizeof...(Ts),int> >
223 AMREX_GPU_HOST_DEVICE inline GpuTuple<Ts...>&
225 {
226  detail::tuple_copy<0,sizeof...(Ts)>(*this, rhs);
227  return *this;
228 }
229 
230 template <typename... Ts>
231 template <typename... Us, std::enable_if_t<sizeof...(Us) == sizeof...(Ts),int> >
232 AMREX_GPU_HOST_DEVICE inline GpuTuple<Ts...>&
234 {
235  detail::tuple_copy<0,sizeof...(Ts)>(*this, std::move(rhs));
236  return *this;
237 }
238 
239 // makeTuple
240 
241 namespace detail {
242  template <typename T> struct unwrap { using type = T; };
243  template <typename T> struct unwrap<std::reference_wrapper<T> > { using type = T&; };
244  template <typename T>
245  using tuple_decay_t = typename unwrap<std::decay_t<T>>::type;
246 }
247 
248 template <typename... Ts>
250 constexpr
252 makeTuple (Ts &&... args)
253 {
254  return GpuTuple<detail::tuple_decay_t<Ts>...>(std::forward<Ts>(args)...);
255 }
256 
257 namespace detail {
258  template <typename...> struct tuple_cat_result {};
259 
260  template <typename... Ts>
261  struct tuple_cat_result<GpuTuple<Ts...> >
262  {
263  using type = GpuTuple<Ts...>;
264  };
265 
266  template <typename... T1s, typename... T2s, typename... TPs>
267  struct tuple_cat_result<GpuTuple<T1s...>,GpuTuple<T2s...>,TPs...>
268  {
269  using type = typename tuple_cat_result<GpuTuple<T1s..., T2s...>, TPs...>::type;
270  };
271 
272  template <typename R, typename TP1, typename TP2, std::size_t... N1, std::size_t... N2>
273  AMREX_GPU_HOST_DEVICE constexpr R
274  make_tuple (TP1 const& a, TP2 const& b,
275  std::index_sequence<N1...> const& /*n1*/, std::index_sequence<N2...> const& /*n2*/)
276  {
277  return R(amrex::get<N1>(a)..., amrex::get<N2>(b)...);
278  }
279 }
280 
281 // TupleCat
282 
283 template <typename TP>
285 constexpr auto
287 {
288  using ReturnType = typename detail::tuple_cat_result<detail::tuple_decay_t<TP> >::type;
289  return ReturnType(std::forward<TP>(a));
290 }
291 
292 template <typename TP1, typename TP2>
294 constexpr auto
297 {
298  using ReturnType = typename detail::tuple_cat_result<detail::tuple_decay_t<TP1>,
300  return detail::make_tuple<ReturnType>
301  (std::forward<TP1>(a), std::forward<TP2>(b),
302  std::make_index_sequence<GpuTupleSize<std::decay_t<TP1>>::value>(),
303  std::make_index_sequence<GpuTupleSize<std::decay_t<TP2>>::value>());
304 }
305 
306 template <typename TP1, typename TP2, typename... TPs>
308 constexpr auto
309 TupleCat (TP1&& a, TP2&& b, TPs&&... args)
313 {
314  return TupleCat(TupleCat(std::forward<TP1>(a),std::forward<TP2>(b)),
315  std::forward<TPs>(args)...);
316 }
317 
318 // TupleSplit
319 
320 namespace detail {
321 
322  template<std::size_t...Is>
323  struct SplitIndexList {
324  template<std::size_t J>
326  static constexpr std::size_t get () noexcept {
327  std::size_t arr[sizeof...(Is)] = {Is...};
328  return arr[J];
329  }
330 
331  template<std::size_t J>
333  static constexpr std::size_t get_exclusive_sum () noexcept {
334  std::size_t arr[sizeof...(Is)] = {Is...};
335  std::size_t sum = 0;
336  for (std::size_t k=0; k<J; ++k) {
337  sum += arr[k];
338  }
339  return sum;
340  }
341  };
342 
343  template <std::size_t start, typename... Args, std::size_t... Is>
345  constexpr auto
346  GetSubTuple (const GpuTuple<Args...>& tup, std::index_sequence<Is...>) noexcept
347  {
348  return makeTuple(amrex::get<start+Is>(tup)...);
349  }
350 
351  template <typename... Args, std::size_t... Is, typename SIL>
353  constexpr auto
354  TupleSplitImp (const GpuTuple<Args...>& tup, std::index_sequence<Is...>, SIL) noexcept
355  {
356  return makeTuple(
357  GetSubTuple<(SIL::template get_exclusive_sum<Is>())>(
358  tup,
359  std::make_index_sequence<SIL::template get<Is>()>()
360  )...
361  );
362  }
363 }
364 
369 template <std::size_t... Is, typename... Args>
371 constexpr auto
372 TupleSplit (const GpuTuple<Args...>& tup) noexcept
373 {
374  static_assert((0 + ... + Is) == sizeof...(Args), "Incorrect total size in TupleSplit");
375  return detail::TupleSplitImp(
376  tup,
377  std::make_index_sequence<sizeof...(Is)>(),
379  );
380 }
381 
382 // Apply
383 
384 namespace detail {
385 
386  template <typename F, typename... Args>
388  auto INVOKE (F&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...));
389 
390  template <typename V, typename F, typename... Args> struct invoke_result {};
391 
392  template <typename F, typename... Args>
393  struct invoke_result<decltype(void(INVOKE(std::declval<F>(), std::declval<Args>()...))),
394  F, Args...>
395  {
396  using type = decltype(INVOKE(std::declval<F>(), std::declval<Args>()...));
397  };
398 
399  template <typename F, typename...> struct apply_result {};
400 
401  template <typename F, typename... Ts>
402  struct apply_result<F, GpuTuple<Ts...> >
403  {
404  using type = typename invoke_result<void, F, Ts...>::type;
405  };
406 
407  template <typename F, typename TP, std::size_t... N>
409  constexpr auto
410  apply_impl (F&& f, TP&& t, std::index_sequence<N...> /*is*/)
412  {
413  return std::forward<F>(f)(amrex::get<N>(std::forward<TP>(t))...);
414  }
415 }
416 
417 template <typename F, typename TP>
419 constexpr auto
421 {
422  return detail::apply_impl(std::forward<F>(f), std::forward<TP>(t),
423  std::make_index_sequence<GpuTupleSize<std::decay_t<TP>>::value>());
424 }
425 
426 // Tie
427 
428 template <typename... Args>
430 constexpr GpuTuple<Args&...>
431 Tie (Args&... args) noexcept
432 {
433  return GpuTuple<Args&...>(args...);
434 }
435 
436 // ForwardAsTuple
437 
438 template <typename... Ts>
440 constexpr GpuTuple<Ts&&...>
441 ForwardAsTuple (Ts&&... args) noexcept
442 {
443  return GpuTuple<Ts&&...>(std::forward<Ts>(args)...);
444 }
445 
446 // MakeZeroTuple
447 
452 template <typename... Ts>
454 constexpr GpuTuple<Ts...>
456 {
457  return GpuTuple<Ts...>(static_cast<Ts>(0)...);
458 }
459 
460 namespace detail {
461  template <typename T, std::size_t... I>
462  AMREX_GPU_HOST_DEVICE constexpr
463  auto tuple_to_array_helper (T const& tup, std::index_sequence<I...>) {
464  return GpuArray<typename GpuTupleElement<0,T>::type, sizeof...(I)>{amrex::get<I>(tup)...};
465  }
466 }
467 
468 template <typename T>
469 AMREX_GPU_HOST_DEVICE constexpr
470 auto tupleToArray (GpuTuple<T> const& tup)
471 {
472  return GpuArray<T,1>{amrex::get<0>(tup)};
473 }
474 
476 template <typename T, typename T2, typename... Ts, std::enable_if_t<Same<T,T2,Ts...>::value, int> = 0>
477 AMREX_GPU_HOST_DEVICE constexpr
479 {
480  return detail::tuple_to_array_helper(tup, std::index_sequence_for<T,T2,Ts...>{});
481 }
482 
483 } // namespace amrex
484 
485 // Spcialize std::tuple_size for GpuTuple. Used by structured bindings.
486 template<typename... Ts>
487 struct std::tuple_size<amrex::GpuTuple<Ts...>> {
488  static constexpr std::size_t value = sizeof...(Ts);
489 };
490 
491 // Spcialize std::tuple_element for GpuTuple. Used by structured bindings.
492 template<typename T, typename... Ts>
493 struct std::tuple_element<std::size_t{0}, amrex::GpuTuple<T, Ts...>> {
494  using type = T;
495 };
496 
497 template<std::size_t s, typename T, typename... Ts>
498 struct std::tuple_element<s, amrex::GpuTuple<T, Ts...>> {
499  using type = typename std::tuple_element<s-1, amrex::GpuTuple<Ts...>>::type;
500 };
501 
502 #endif /*AMREX_TUPLE_H_*/
#define AMREX_GPU_HOST_DEVICE
Definition: AMReX_GpuQualifiers.H:20
Definition: AMReX_Tuple.H:93
constexpr GpuTuple(Us &&... args)
Definition: AMReX_Tuple.H:103
constexpr GpuTuple(Ts const &... args)
Definition: AMReX_Tuple.H:98
AMREX_GPU_HOST_DEVICE GpuTuple< Ts... > & operator=(GpuTuple< Us... > const &rhs)
Definition: AMReX_Tuple.H:224
constexpr AMREX_GPU_HOST_DEVICE GpuTuple()=default
static int f(amrex::Real t, N_Vector y_data, N_Vector y_rhs, void *user_data)
Definition: AMReX_SundialsIntegrator.H:44
@ sum
Definition: AMReX_ParallelReduce.H:19
constexpr AMREX_GPU_HOST_DEVICE R make_tuple(TP1 const &a, TP2 const &b, std::index_sequence< N1... > const &, std::index_sequence< N2... > const &)
Definition: AMReX_Tuple.H:274
constexpr AMREX_GPU_HOST_DEVICE auto GetSubTuple(const GpuTuple< Args... > &tup, std::index_sequence< Is... >) noexcept
Definition: AMReX_Tuple.H:346
constexpr AMREX_GPU_HOST_DEVICE auto TupleSplitImp(const GpuTuple< Args... > &tup, std::index_sequence< Is... >, SIL) noexcept
Definition: AMReX_Tuple.H:354
AMREX_GPU_HOST_DEVICE std::enable_if_t<(I< N-1), void > tuple_copy(TP1 &a, TP2 &&b)
Definition: AMReX_Tuple.H:206
constexpr AMREX_GPU_HOST_DEVICE auto tuple_to_array_helper(T const &tup, std::index_sequence< I... >)
Definition: AMReX_Tuple.H:463
constexpr AMREX_GPU_HOST_DEVICE GpuTupleElement< I, GpuTuple< Ts... > >::type & get_impl(detail::gpu_tuple_element< I, typename GpuTupleElement< I, GpuTuple< Ts... > >::type > &te) noexcept
Definition: AMReX_Tuple.H:147
constexpr AMREX_GPU_HOST_DEVICE auto apply_impl(F &&f, TP &&t, std::index_sequence< N... >) -> typename detail::apply_result< F, detail::tuple_decay_t< TP > >::type
Definition: AMReX_Tuple.H:410
typename unwrap< std::decay_t< T > >::type tuple_decay_t
Definition: AMReX_Tuple.H:245
AMREX_GPU_HOST_DEVICE auto INVOKE(F &&f, Args &&... args) -> decltype(f(std::forward< Args >(args)...))
Definition: AMReX_Amr.cpp:49
std::tuple< Ts... > Tuple
Definition: AMReX_Tuple.H:18
constexpr AMREX_GPU_HOST_DEVICE auto tupleToArray(GpuTuple< T > const &tup)
Definition: AMReX_Tuple.H:470
constexpr AMREX_GPU_HOST_DEVICE GpuTuple< Args &... > Tie(Args &... args) noexcept
Definition: AMReX_Tuple.H:431
constexpr AMREX_GPU_HOST_DEVICE GpuTuple< detail::tuple_decay_t< Ts >... > makeTuple(Ts &&... args)
Definition: AMReX_Tuple.H:252
constexpr AMREX_GPU_HOST_DEVICE GpuTupleElement< I, GpuTuple< Ts... > >::type & get(GpuTuple< Ts... > &tup) noexcept
Definition: AMReX_Tuple.H:179
constexpr AMREX_GPU_HOST_DEVICE auto TupleSplit(const GpuTuple< Args... > &tup) noexcept
Returns a GpuTuple of GpuTuples obtained by splitting the input GpuTuple according to the sizes speci...
Definition: AMReX_Tuple.H:372
constexpr AMREX_GPU_HOST_DEVICE auto Apply(F &&f, TP &&t) -> typename detail::apply_result< F, detail::tuple_decay_t< TP > >::type
Definition: AMReX_Tuple.H:420
constexpr AMREX_GPU_HOST_DEVICE GpuTuple< Ts... > MakeZeroTuple(GpuTuple< Ts... >) noexcept
Return a GpuTuple containing all zeros. Note that a default-constructed GpuTuple can have uninitializ...
Definition: AMReX_Tuple.H:455
constexpr AMREX_GPU_HOST_DEVICE GpuTuple< Ts &&... > ForwardAsTuple(Ts &&... args) noexcept
Definition: AMReX_Tuple.H:441
constexpr AMREX_GPU_HOST_DEVICE auto TupleCat(TP &&a) -> typename detail::tuple_cat_result< detail::tuple_decay_t< TP > >::type
Definition: AMReX_Tuple.H:286
Definition: AMReX_FabArrayCommI.H:841
Definition: AMReX_Array.H:34
Definition: AMReX_Tuple.H:128
Definition: AMReX_Tuple.H:120
Definition: AMReX_Tuple.H:323
static constexpr AMREX_GPU_HOST_DEVICE std::size_t get_exclusive_sum() noexcept
Definition: AMReX_Tuple.H:333
static constexpr AMREX_GPU_HOST_DEVICE std::size_t get() noexcept
Definition: AMReX_Tuple.H:326
typename invoke_result< void, F, Ts... >::type type
Definition: AMReX_Tuple.H:404
Definition: AMReX_Tuple.H:399
Definition: AMReX_Tuple.H:27
constexpr gpu_tuple_element(U &&a_value)
Definition: AMReX_Tuple.H:37
constexpr AMREX_GPU_HOST_DEVICE gpu_tuple_element()
Definition: AMReX_Tuple.H:30
T m_value
Definition: AMReX_Tuple.H:41
constexpr gpu_tuple_element(T const &a_value)
Definition: AMReX_Tuple.H:32
constexpr gpu_tuple_impl(Head const &a_head, Tail const &... a_tail)
Definition: AMReX_Tuple.H:55
constexpr AMREX_GPU_HOST_DEVICE gpu_tuple_impl()
Definition: AMReX_Tuple.H:53
constexpr gpu_tuple_impl(UH &&a_head, UT &&... a_tail)
Definition: AMReX_Tuple.H:61
constexpr gpu_tuple_impl(Head const &a_head)
Definition: AMReX_Tuple.H:76
constexpr gpu_tuple_impl(U &&a_head)
Definition: AMReX_Tuple.H:81
constexpr AMREX_GPU_HOST_DEVICE gpu_tuple_impl()
Definition: AMReX_Tuple.H:74
Definition: AMReX_Tuple.H:44
decltype(INVOKE(std::declval< F >(), std::declval< Args >()...)) type
Definition: AMReX_Tuple.H:396
Definition: AMReX_Tuple.H:390
typename tuple_cat_result< GpuTuple< T1s..., T2s... >, TPs... >::type type
Definition: AMReX_Tuple.H:269
Definition: AMReX_Tuple.H:258
Definition: AMReX_Tuple.H:242
T type
Definition: AMReX_Tuple.H:242
typename std::tuple_element< s-1, amrex::GpuTuple< Ts... > >::type type
Definition: AMReX_Tuple.H:499