rocPRIM
tuple.hpp
1 // Copyright (c) 2018-2023 Advanced Micro Devices, Inc. All rights reserved.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #ifndef ROCPRIM_TYPES_TUPLE_HPP_
22 #define ROCPRIM_TYPES_TUPLE_HPP_
23 
24 #include <tuple>
25 #include <type_traits>
26 
27 #include "../config.hpp"
28 #include "../detail/all_true.hpp"
29 
30 #include "integer_sequence.hpp"
31 
34 
35 BEGIN_ROCPRIM_NAMESPACE
36 
37 // ////////////////////////
38 // tuple (FORWARD DECLARATION)
39 // ////////////////////////
40 template<class... Types>
41 class tuple;
42 
43 // ////////////////////////
44 // tuple_size
45 // ////////////////////////
46 
50 template<class T>
51 class tuple_size;
52 
57 template<class... Types>
58 class tuple_size<::rocprim::tuple<Types...>> : public std::integral_constant<size_t, sizeof...(Types)>
59 {
60  // All member functions of std::integral_constant are constexpr, so it should work
61  // without problems on HIP
62 };
64 template<class T>
65 class tuple_size<const T>
66  : public std::integral_constant<size_t, tuple_size<T>::value>
67 {
68 
69 };
71 template<class T>
72 class tuple_size<volatile T>
73  : public std::integral_constant<size_t, tuple_size<T>::value>
74 {
75 
76 };
78 template<class T>
79 class tuple_size<const volatile T>
80  : public std::integral_constant<size_t, tuple_size<T>::value>
81 {
82 
83 };
84 
85 // ////////////////////////
86 // tuple_element
87 // ////////////////////////
88 
92 template<size_t I, class T>
93 struct tuple_element; // rocprim::tuple_size is defined only for rocprim::tuple
94 
95 namespace detail
96 {
97 
98 template<size_t I, class T>
100 
101 template<size_t I, class T, class... Types>
102 struct tuple_element_impl<I, ::rocprim::tuple<T, Types...>>
103  : tuple_element_impl<I-1, ::rocprim::tuple<Types...>>
104 {
105 
106 };
107 
108 template<class T, class... Types>
109 struct tuple_element_impl<0, ::rocprim::tuple<T, Types...>>
110 {
111  using type = T;
112 };
113 
114 template<size_t I>
115 struct tuple_element_impl<I, ::rocprim::tuple<>>
116 {
117  static_assert(I != I, "tuple_element index out of range");
118 };
119 
120 } // end detail namespace
121 
124 template<size_t I, class... Types>
125 struct tuple_element<I, ::rocprim::tuple<Types...>>
126 {
128  #ifndef DOXYGEN_SHOULD_SKIP_THIS
129  using type = typename detail::tuple_element_impl<I, ::rocprim::tuple<Types...>>::type;
130  #else
131  typedef type;
132  #endif
133 };
135 template<size_t I, class T>
136 struct tuple_element<I, const T>
137 {
139  using type = typename std::add_const<typename tuple_element<I, T>::type>::type;
140 };
142 template<size_t I, class T>
143 struct tuple_element<I, volatile T>
144 {
146  using type = typename std::add_volatile<typename tuple_element<I, T>::type>::type;
147 };
149 template<size_t I, class T>
150 struct tuple_element<I, const volatile T>
151 {
153  using type = typename std::add_cv<typename tuple_element<I, T>::type>::type;
154 };
155 
159 template <size_t I, class T>
161 
162 // get<I> forward declaration
163 #ifndef DOXYGEN_SHOULD_SKIP_THIS
164 template<size_t I, class... UTypes>
165 ROCPRIM_HOST_DEVICE
166 const tuple_element_t<I, tuple<UTypes...>>& get(const tuple<UTypes...>&) noexcept;
167 
168 template<size_t I, class... UTypes>
169 ROCPRIM_HOST_DEVICE
170 tuple_element_t<I, tuple<UTypes...>>& get(tuple<UTypes...>&) noexcept;
171 
172 template<size_t I, class... UTypes>
173 ROCPRIM_HOST_DEVICE
174 tuple_element_t<I, tuple<UTypes...>>&& get(tuple<UTypes...>&&) noexcept;
175 #endif
176 
177 // ////////////////////////
178 // tuple
179 // ////////////////////////
180 
181 namespace detail
182 {
183 
184  template <class T>
185  ROCPRIM_HOST_DEVICE
186  inline T&& custom_forward(typename std::remove_reference<T>::type& t) noexcept
187  {
188  return static_cast<T&&>(t);
189  }
190 
191  template <class T>
192  ROCPRIM_HOST_DEVICE
193  inline T&& custom_forward(typename std::remove_reference<T>::type&& t) noexcept
194  {
195  static_assert(!std::is_lvalue_reference<T>::value,
196  "Can not forward an rvalue as an lvalue.");
197  return static_cast<T&&>(t);
198  }
199 
200 
201 #ifdef __cpp_lib_is_final
202  template<class T>
203  using is_final = std::is_final<T>;
204 #elif defined(__clang__) // use clang extention
205  template<class T>
206  using is_final = std::integral_constant<bool, __is_final(T)>;
207 #else
208  template<class T>
209  struct is_final : std::false_type
210  {
211  };
212 #endif
213 
214 // tuple_value - represents single element in a tuple
215 template<
216  size_t I,
217  class T,
218  bool /* Empty base optimization switch */ = std::is_empty<T>::value && !is_final<T>::value
219 >
221 {
222  T value;
223 
224  ROCPRIM_HOST_DEVICE inline
225  constexpr tuple_value() noexcept : value()
226  {
227  static_assert(!std::is_reference<T>::value, "can't default construct a reference element in a tuple" );
228  }
229 
230  ROCPRIM_HOST_DEVICE inline
231  tuple_value(const tuple_value&) = default;
232 
233  ROCPRIM_HOST_DEVICE inline
234  tuple_value(tuple_value&&) = default;
235 
236  template<
237  class U,
238  typename = typename std::enable_if<
239  !std::is_same<typename std::decay<U>::type, tuple_value>::value
240  >::type,
241  typename = typename std::enable_if<
242  std::is_constructible<T, const U&>::value
243  >::type
244  >
245  ROCPRIM_HOST_DEVICE inline
246  explicit tuple_value(const U& v) noexcept : value(v)
247  {
248  }
249 
250  template<
251  class U,
252  typename = typename std::enable_if<
253  // So U can't be tuple_value<T>
254  !std::is_same<typename std::decay<U>::type, tuple_value>::value
255  >::type,
256  typename = typename std::enable_if<
257  std::is_constructible<T, U&&>::value
258  >::type
259  >
260  ROCPRIM_HOST_DEVICE inline
261  explicit tuple_value(U&& v) noexcept : value(::rocprim::detail::custom_forward<U>(v))
262  {
263  }
264 
265  ROCPRIM_HOST_DEVICE inline
266  ~tuple_value() = default;
267 
268  template<class U>
269  ROCPRIM_HOST_DEVICE inline
270  tuple_value& operator=(U&& v) noexcept
271  {
272  value = ::rocprim::detail::custom_forward<U>(v);
273  return *this;
274  }
275 
276  ROCPRIM_HOST_DEVICE inline
277  void swap(tuple_value& v) noexcept
278  {
279  auto tmp = std::move(v.value);
280  v.value = std::move(this->value);
281  this->value = std::move(tmp);
282  }
283 
284  ROCPRIM_HOST_DEVICE inline
285  T& get() noexcept
286  {
287  return value;
288  }
289 
290  ROCPRIM_HOST_DEVICE inline
291  const T& get() const noexcept
292  {
293  return value;
294  }
295 };
296 
297 // Specialization for empty base optimization
298 template<size_t I, class T>
299 struct tuple_value<I, T, true> : private T
300 {
301  ROCPRIM_HOST_DEVICE inline
302  constexpr tuple_value() noexcept : T()
303  {
304  static_assert(!std::is_reference<T>::value, "can't default construct a reference element in a tuple" );
305  }
306 
307  ROCPRIM_HOST_DEVICE inline
308  tuple_value(const tuple_value&) = default;
309 
310  ROCPRIM_HOST_DEVICE inline
311  tuple_value(tuple_value&&) = default;
312 
313  template<
314  class U,
315  typename = typename std::enable_if<
316  !std::is_same<typename std::decay<U>::type, tuple_value>::value
317  >::type,
318  typename = typename std::enable_if<
319  std::is_constructible<T, const U&>::value
320  >::type
321  >
322  ROCPRIM_HOST_DEVICE inline
323  explicit tuple_value(const U& v) noexcept : T(v)
324  {
325  }
326 
327  template<
328  class U,
329  typename = typename std::enable_if<
330  // So U can't be tuple_value<T>
331  !std::is_same<typename std::decay<U>::type, tuple_value>::value
332  >::type,
333  typename = typename std::enable_if<
334  std::is_constructible<T, U&&>::value
335  >::type
336  >
337  ROCPRIM_HOST_DEVICE inline
338  explicit tuple_value(U&& v) noexcept : T(::rocprim::detail::custom_forward<U>(v))
339  {
340  }
341 
342  ROCPRIM_HOST_DEVICE inline
343  ~tuple_value() = default;
344 
345  template<class U>
346  ROCPRIM_HOST_DEVICE inline
347  tuple_value& operator=(U&& v) noexcept
348  {
349  T::operator=(::rocprim::detail::custom_forward<U>(v));
350  return *this;
351  }
352 
353  ROCPRIM_HOST_DEVICE inline
354  void swap(tuple_value& v) noexcept
355  {
356  auto tmp = std::move(v);
357  v = std::move(*this);
358  *this = std::move(tmp);
359  }
360 
361  ROCPRIM_HOST_DEVICE inline
362  T& get() noexcept
363  {
364  return static_cast<T&>(*this);
365  }
366 
367  ROCPRIM_HOST_DEVICE inline
368  const T& get() const noexcept
369  {
370  return static_cast<const T&>(*this);
371  }
372 };
373 
374 template <class... Types>
375 ROCPRIM_HOST_DEVICE inline
376 void swallow(Types&&...) noexcept {}
377 
378 template<class Sequences, class... Types>
379 struct tuple_impl;
380 
381 template<size_t... Indices, class... Types>
382 struct tuple_impl<::rocprim::index_sequence<Indices...>, Types...>
383  : tuple_value<Indices, Types>...
384 {
385  ROCPRIM_HOST_DEVICE inline
386  constexpr tuple_impl() = default;
387 
388  ROCPRIM_HOST_DEVICE inline
389  tuple_impl(const tuple_impl&) = default;
390 
391  ROCPRIM_HOST_DEVICE inline
392  tuple_impl(tuple_impl&&) = default;
393 
394  template<
395  class... UTypes,
396  typename = typename std::enable_if<
397  sizeof...(UTypes) == sizeof...(Types)
398  >::type,
399  typename = typename std::enable_if<
400  sizeof...(Types) >= 1
401  >::type
402  >
403  ROCPRIM_HOST_DEVICE inline
404  explicit tuple_impl(UTypes&&... values)
405  : tuple_value<Indices, Types>(::rocprim::detail::custom_forward<UTypes>(values))...
406  {
407  }
408 
409  template<
410  class... UTypes,
411  typename = typename std::enable_if<
412  sizeof...(UTypes) == sizeof...(Types)
413  >::type,
414  typename = typename std::enable_if<
415  sizeof...(Types) >= 1
416  >::type
417  >
418  ROCPRIM_HOST_DEVICE inline
419  tuple_impl(::rocprim::tuple<UTypes...>&& other)
420  : tuple_value<Indices, Types>(::rocprim::detail::custom_forward<UTypes>(::rocprim::get<Indices>(other)))...
421  {
422  }
423 
424  template<
425  class... UTypes,
426  typename = typename std::enable_if<
427  sizeof...(UTypes) == sizeof...(Types)
428  >::type,
429  typename = typename std::enable_if<
430  sizeof...(Types) >= 1
431  >::type
432  >
433  ROCPRIM_HOST_DEVICE inline
434  tuple_impl(const ::rocprim::tuple<UTypes...>& other)
435  : tuple_value<Indices, Types>(::rocprim::get<Indices>(other))...
436  {
437  }
438 
439  ROCPRIM_HOST_DEVICE inline
440  ~tuple_impl() = default;
441 
442  ROCPRIM_HOST_DEVICE inline
443  tuple_impl& operator=(const tuple_impl& other) noexcept
444  {
445  swallow(
447  static_cast<const tuple_value<Indices, Types>&>(other).get()
448  )...
449  );
450  return *this;
451  }
452 
453  ROCPRIM_HOST_DEVICE inline
454  tuple_impl& operator=(tuple_impl&& other) noexcept
455  {
456  swallow(
458  static_cast<tuple_value<Indices, Types>&>(other).get()
459  )...
460  );
461  return *this;
462  }
463 
464  template<class... UTypes>
465  ROCPRIM_HOST_DEVICE inline
466  tuple_impl& operator=(const ::rocprim::tuple<UTypes...>& other) noexcept
467  {
468  swallow(tuple_value<Indices, Types>::operator=(::rocprim::get<Indices>(other))...);
469  return *this;
470  }
471 
472  template<class... UTypes>
473  ROCPRIM_HOST_DEVICE inline
474  tuple_impl& operator=(::rocprim::tuple<UTypes...>&& other) noexcept
475  {
476  swallow(
478  ::rocprim::get<Indices>(std::move(other))
479  )...
480  );
481  return *this;
482  }
483 
484  ROCPRIM_HOST_DEVICE inline
485  tuple_impl& swap(tuple_impl& other) noexcept
486  {
487  swallow(
488  (static_cast<tuple_value<Indices, Types>&>(*this).swap(
489  static_cast<tuple_value<Indices, Types>&>(other)
490  ), 0)...
491  );
492  return *this;
493  }
494 };
495 
496 template<class... Types>
497 using tuple_base =
498  tuple_impl<
499  typename ::rocprim::index_sequence_for<Types...>,
500  Types...
501  >;
502 
503 } // end detail namespace
504 
514 template<class... Types>
515 class tuple
516 {
517  using base_type = detail::tuple_base<Types...>;
518  // tuple_impl
519  base_type base;
520 
521  template<class Dummy>
522  struct check_constructor
523  {
524  template<class... Args>
525  static constexpr bool enable_default()
526  {
528  }
529 
530  template<class... Args>
531  static constexpr bool enable_copy()
532  {
534  }
535  };
536 
537  #ifndef DOXYGEN_SHOULD_SKIP_THIS
538  template<size_t I, class... UTypes>
539  ROCPRIM_HOST_DEVICE
540  friend const tuple_element_t<I, tuple<UTypes...>>& get(const tuple<UTypes...>&) noexcept;
541 
542  template<size_t I, class... UTypes>
543  ROCPRIM_HOST_DEVICE
544  friend tuple_element_t<I, tuple<UTypes...>>& get(tuple<UTypes...>&) noexcept;
545 
546  template<size_t I, class... UTypes>
547  ROCPRIM_HOST_DEVICE
548  friend tuple_element_t<I, tuple<UTypes...>>&& get(tuple<UTypes...>&&) noexcept;
549  #endif
550 
551 public:
556  #ifndef DOXYGEN_SHOULD_SKIP_THIS
557  template<
558  class Dummy = void,
559  typename = typename std::enable_if<
560  check_constructor<Dummy>::template enable_default<Types...>()
561  >::type
562  >
563  #endif
564  ROCPRIM_HOST_DEVICE inline
565  constexpr tuple() noexcept : base() {};
566 
568  ROCPRIM_HOST_DEVICE inline
569  tuple(const tuple&) = default;
570 
572  ROCPRIM_HOST_DEVICE inline
573  tuple(tuple&&) = default;
574 
580  #ifndef DOXYGEN_SHOULD_SKIP_THIS
581  template<
582  class Dummy = void,
583  typename = typename std::enable_if<
584  check_constructor<Dummy>::template enable_copy<Types...>()
585  >::type
586  >
587  #endif
588  ROCPRIM_HOST_DEVICE inline
589  explicit tuple(const Types&... values)
590  : base(values...)
591  {
592  }
593 
601  template<
602  class... UTypes
603  #ifndef DOXYGEN_SHOULD_SKIP_THIS
604  ,typename = typename std::enable_if<
605  sizeof...(UTypes) == sizeof...(Types)
606  >::type,
607  typename = typename std::enable_if<
608  sizeof...(Types) >= 1
609  >::type,
610  typename = typename std::enable_if<
611  detail::all_true<std::is_constructible<Types, UTypes&&>::value...>::value
612  >::type
613  #endif
614  >
615  ROCPRIM_HOST_DEVICE inline
616  explicit tuple(UTypes&&... values) noexcept
617  : base(::rocprim::detail::custom_forward<UTypes>(values)...)
618  {
619  }
620 
628  template<
629  class... UTypes,
630  #ifndef DOXYGEN_SHOULD_SKIP_THIS
631  typename = typename std::enable_if<
632  sizeof...(UTypes) == sizeof...(Types)
633  >::type,
634  typename = typename std::enable_if<
635  sizeof...(Types) >= 1
636  >::type,
637  typename = typename std::enable_if<
638  detail::all_true<std::is_constructible<Types, const UTypes&>::value...>::value
639  >::type
640  #endif
641  >
642  ROCPRIM_HOST_DEVICE inline
643  tuple(const tuple<UTypes...>& other) noexcept
644  : base(other)
645  {
646  }
647 
655  template<
656  class... UTypes,
657  #ifndef DOXYGEN_SHOULD_SKIP_THIS
658  typename = typename std::enable_if<
659  sizeof...(UTypes) == sizeof...(Types)
660  >::type,
661  typename = typename std::enable_if<
662  sizeof...(Types) >= 1
663  >::type,
664  typename = typename std::enable_if<
665  detail::all_true<std::is_constructible<Types, UTypes&&>::value...>::value
666  >::type
667  #endif
668  >
669  ROCPRIM_HOST_DEVICE inline
670  tuple(tuple<UTypes...>&& other) noexcept
671  : base(::rocprim::detail::custom_forward<tuple<UTypes...>>(other))
672  {
673  }
674 
676  ROCPRIM_HOST_DEVICE inline
677  ~tuple() noexcept = default;
678 
679  #ifndef DOXYGEN_SHOULD_SKIP_THIS
680  template<
681  class T,
682  typename = typename std::enable_if<
683  std::is_assignable<base_type&, T>::value
684  >::type
685  >
686  ROCPRIM_HOST_DEVICE inline
687  tuple& operator=(T&& v) noexcept
688  {
689  base = ::rocprim::detail::custom_forward<T>(v);
690  return *this;
691  }
692 
693  ROCPRIM_HOST_DEVICE inline
694  tuple& operator=(const tuple& other) noexcept
695  {
696  base = other.base;
697  return *this;
698  }
699  #else // For documentation
700  tuple& operator=(const tuple& other) noexcept;
705  tuple& operator=(tuple&& other) noexcept;
708  template<class... UTypes>
709  tuple& operator=(const tuple<UTypes...>& other) noexcept;
712  template<class... UTypes>
713  tuple& operator=(tuple<UTypes...>&& other) noexcept;
714  #endif
715 
718  ROCPRIM_HOST_DEVICE void swap(tuple& other) noexcept
719  {
720  base.swap(other.base);
721  }
722 };
723 
724 #ifndef DOXYGEN_SHOULD_SKIP_THIS
725 template<>
726 class tuple<>
727 {
728 public:
729  ROCPRIM_HOST_DEVICE inline
730  constexpr tuple() noexcept
731  {
732  }
733 
734  ROCPRIM_HOST_DEVICE inline
735  ~tuple() = default;
736 
737  ROCPRIM_HOST_DEVICE inline
738  void swap(tuple&) noexcept
739  {
740  }
741 };
742 #endif
743 
744 namespace detail
745 {
746 
747 template<size_t I>
749 {
750  template<class T, class U>
751  ROCPRIM_HOST_DEVICE inline
752  bool operator()(const T& lhs, const U& rhs) const
753  {
754  return tuple_equal_to<I-1>()(lhs, rhs) && get<I-1>(lhs) == get<I-1>(rhs);
755  }
756 };
757 
758 template<>
759 struct tuple_equal_to<0>
760 {
761  template<class T, class U>
762  ROCPRIM_HOST_DEVICE inline
763  bool operator()(const T&, const U&) const
764  {
765  return true;
766  }
767 };
768 
769 template<size_t I>
771 {
772  template<class T, class U>
773  ROCPRIM_HOST_DEVICE inline
774  bool operator()(const T& lhs, const U& rhs) const
775  {
776  constexpr size_t idx = tuple_size<T>::value - I;
777  if(get<idx>(lhs) < get<idx>(rhs))
778  return true;
779  if(get<idx>(rhs) < get<idx>(lhs))
780  return false;
781  return tuple_less_than<I-1>()(lhs, rhs);
782  }
783 };
784 
785 template<>
787 {
788  template<class T, class U>
789  ROCPRIM_HOST_DEVICE inline
790  bool operator()(const T&, const U&) const
791  {
792  return false;
793  }
794 };
795 
796 } // end namespace detail
797 
811 template<
812  class... TTypes,
813  class... UTypes,
814  typename = typename std::enable_if<
815  sizeof...(TTypes) == sizeof...(UTypes)
816  >::type
817 >
818 ROCPRIM_HOST_DEVICE inline
819 bool operator==(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
820 {
821  return detail::tuple_equal_to<sizeof...(TTypes)>()(lhs, rhs);
822 }
823 
836 template<class... TTypes, class... UTypes>
837 ROCPRIM_HOST_DEVICE inline
838 bool operator!=(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
839 {
840  return !(lhs == rhs);
841 }
842 
856 template<
857  class... TTypes,
858  class... UTypes,
859  typename = typename std::enable_if<
860  sizeof...(TTypes) == sizeof...(UTypes)
861  >::type
862 >
863 ROCPRIM_HOST_DEVICE inline
864 bool operator<(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
865 {
866  return detail::tuple_less_than<sizeof...(TTypes)>()(lhs, rhs);
867 }
868 
879 template<class... TTypes, class... UTypes>
880 ROCPRIM_HOST_DEVICE inline
881 bool operator>(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
882 {
883  return rhs < lhs;
884 }
885 
896 template<class... TTypes, class... UTypes>
897 ROCPRIM_HOST_DEVICE inline
898 bool operator<=(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
899 {
900  return !(rhs < lhs);
901 }
902 
913 template<class... TTypes, class... UTypes>
914 ROCPRIM_HOST_DEVICE inline
915 bool operator>=(const tuple<TTypes...>& lhs, const tuple<UTypes...>& rhs)
916 {
917  return !(lhs < rhs);
918 }
919 
920 // ////////////////////////
921 // swap
922 // ////////////////////////
923 
926 template<class... Types>
927 ROCPRIM_HOST_DEVICE inline
928 void swap(tuple<Types...>& lhs, tuple<Types...>& rhs) noexcept
929 {
930  lhs.swap(rhs);
931 }
932 
933 // ////////////////////////
934 // get<Index>
935 // ////////////////////////
936 
941 template<size_t I, class... Types>
942 ROCPRIM_HOST_DEVICE inline
943 const tuple_element_t<I, tuple<Types...>>& get(const tuple<Types...>& t) noexcept
944 {
945  using type = detail::tuple_value<I, tuple_element_t<I, tuple<Types...>>>;
946  return static_cast<const type&>(t.base).get();
947 }
948 
953 template<size_t I, class... Types>
954 ROCPRIM_HOST_DEVICE inline
955 tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>& t) noexcept
956 {
957  using type = detail::tuple_value<I, tuple_element_t<I, tuple<Types...>>>;
958  return static_cast<type&>(t.base).get();
959 }
960 
965 template<size_t I, class... Types>
966 ROCPRIM_HOST_DEVICE inline
967 tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&& t) noexcept
968 {
969  using value_type = tuple_element_t<I, tuple<Types...>>;
970  using type = detail::tuple_value<I, tuple_element_t<I, tuple<Types...>>>;
971  return static_cast<value_type&&>(static_cast<type&>(t.base).get());
972 }
973 
974 // ////////////////////////
975 // make_tuple
976 // ////////////////////////
977 
978 namespace detail
979 {
980 
981 template<class T>
983 {
984  using type = T;
985 };
986 
987 template<class T>
988 struct make_tuple_return<std::reference_wrapper<T>>
989 {
990  using type = T&;
991 };
992 
993 template <class T>
994 using make_tuple_return_t = typename make_tuple_return<typename std::decay<T>::type>::type;
995 
996 } // end detail namespace
997 
998 #ifndef DOXYGEN_SHOULD_SKIP_THIS
999 template<class... Types>
1000 ROCPRIM_HOST_DEVICE inline
1001 tuple<detail::make_tuple_return_t<Types>...> make_tuple(Types&&... args) noexcept
1002 {
1003  return tuple<detail::make_tuple_return_t<Types>...>(::rocprim::detail::custom_forward<Types>(args)...);
1004 }
1005 #else
1006 template<class... Types>
1017 tuple<VTypes...> make_tuple(Types&&... args);
1018 #endif
1019 
1020 // ////////////////////////
1021 // ignore
1022 // ////////////////////////
1023 
1024 namespace detail
1025 {
1026 
1027 struct ignore_t
1028 {
1029  ROCPRIM_HOST_DEVICE inline
1030  ignore_t() = default;
1031 
1032  ROCPRIM_HOST_DEVICE inline
1033  ~ignore_t() = default;
1034 
1035  template<class T>
1036  ROCPRIM_HOST_DEVICE inline
1037  const ignore_t& operator=(const T&) const
1038  {
1039  return *this;
1040  }
1041 };
1042 
1043 }
1044 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1046 #else
1047 struct ignore_type;
1048 #endif
1049 const ignore_type ignore;
1056 
1057 // ////////////////////////
1058 // tie
1059 // ////////////////////////
1060 
1067 template<class... Types>
1068 ROCPRIM_HOST_DEVICE inline
1069 tuple<Types&...> tie(Types&... args) noexcept
1070 {
1071  return ::rocprim::tuple<Types&...>(args...);
1072 }
1073 
1074 END_ROCPRIM_NAMESPACE
1075 
1077 // end of group utilsmodule_tuple
1078 
1079 #endif // ROCPRIM_TYPES_TUPLE_HPP_
Definition: tuple.hpp:220
Definition: tuple.hpp:379
ROCPRIM_HOST_DEVICE tuple< Types &... > tie(Types &... args) noexcept
Creates a tuple of lvalue references to its arguments args or instances of rocprim::ignore.
Definition: tuple.hpp:1069
typename detail::tuple_element_impl< I, ::rocprim::tuple< Types... > >::type type
The type of Ith element of the tuple, where I is in [0, sizeof...(Types))
Definition: tuple.hpp:129
const ignore_type ignore
Assigning value to ignore object has no effect.
Definition: tuple.hpp:1055
ROCPRIM_HOST_DEVICE bool operator>=(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Greater than or equal to operator for tuples.
Definition: tuple.hpp:915
ROCPRIM_HOST_DEVICE void swap(tuple< Types... > &lhs, tuple< Types... > &rhs) noexcept
Swaps the content of lhs tuple with the content rhs.
Definition: tuple.hpp:928
ROCPRIM_HOST_DEVICE bool operator<(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Less than operator for tuples.
Definition: tuple.hpp:864
ROCPRIM_HOST_DEVICE constexpr tuple() noexcept
Default constructor.
Definition: tuple.hpp:565
Definition: tuple.hpp:99
typename std::add_volatile< typename tuple_element< I, T >::type >::type type
The type of Ith element of the tuple, where I is in [0, sizeof...(Types))
Definition: tuple.hpp:146
typename tuple_element< I, T >::type tuple_element_t
This is an alias used for convenience.
Definition: tuple.hpp:160
ROCPRIM_HOST_DEVICE bool operator!=(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Not equal to operator for tuples.
Definition: tuple.hpp:838
ROCPRIM_HOST_DEVICE void swap(tuple &other) noexcept
Swaps the content of the tuple (*this) with the content other.
Definition: tuple.hpp:718
Deprecated: Configuration of device-level scan primitives.
Definition: block_histogram.hpp:62
Definition: all_true.hpp:35
typename std::add_cv< typename tuple_element< I, T >::type >::type type
The type of Ith element of the tuple, where I is in [0, sizeof...(Types))
Definition: tuple.hpp:153
Provides compile-time indexed access to the types of the elements of the tuple.
Definition: tuple.hpp:93
ROCPRIM_HOST_DEVICE bool operator<=(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Less than or equal to operator for tuples.
Definition: tuple.hpp:898
Definition: tuple.hpp:982
Fixed-size collection of heterogeneous values.
Definition: tuple.hpp:41
ROCPRIM_HOST_DEVICE bool operator>(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Greater than operator for tuples.
Definition: tuple.hpp:881
ROCPRIM_HOST_DEVICE bool operator==(const tuple< TTypes... > &lhs, const tuple< UTypes... > &rhs)
Equal to operator for tuples.
Definition: tuple.hpp:819
Definition: tuple.hpp:748
Definition: tuple.hpp:1027
Definition: tuple.hpp:209
Provides access to the number of elements in a tuple as a compile-time constant expression.
Definition: tuple.hpp:51
ROCPRIM_HOST_DEVICE tuple(const Types &... values)
Direct constructor.
Definition: tuple.hpp:589
Definition: tuple.hpp:770
typename std::add_const< typename tuple_element< I, T >::type >::type type
The type of Ith element of the tuple, where I is in [0, sizeof...(Types))
Definition: tuple.hpp:139