cuda-kat
CUDA kernel author's tools
tuple.hpp
1 
10 //
11 // Original code Copyright (c) Electronic Arts Inc. All rights reserved
12 // Modifications Copyright (c) 2020 Eyal Rozenberg.
13 //
14 // Redistribution and use in source and binary forms, with or without
15 // modification, are permitted provided that the following conditions are met:
16 //
17 // 1. Redistributions of source code must retain the above copyright notice, this
18 // list of conditions and the following disclaimer.
19 //
20 // 2. Redistributions in binary form must reproduce the above copyright notice,
21 // this list of conditions and the following disclaimer in the documentation
22 // and/or other materials provided with the distribution.
23 //
24 // 3. Neither the name of the copyright holder nor the names of its
25 // contributors may be used to endorse or promote products derived from
26 // this software without specific prior written permission.
27 //
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
32 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Note: Retrieved from https://github.com/electronicarts/EASTL/ , master branch,
40 // on 2020-03-06.
41 
42 #ifndef CUDA_KAT_TUPLE_HPP_
43 #define CUDA_KAT_TUPLE_HPP_
44 
45 #include <kat/common.hpp>
46 #include <kat/utility.hpp>
48 
49 #include <functional>
50 #include <type_traits>
51 #include <tuple>
52 
53 // Forward declarations - originally from EASTL/detail/tuple_fwd_decls.h
54 namespace kat {
55 
56 template <typename... T>
57 class tuple;
58 
59 template <typename Tuple>
60 class tuple_size;
61 
62 template <size_t I, typename Tuple>
64 
65 template <size_t I, typename Tuple>
66 using tuple_element_t = typename tuple_element<I, Tuple>::type;
67 
68 // const typename for tuple_element_t, for when tuple or tuple_impl cannot itself be const
69 template <size_t I, typename Tuple>
70 using const_tuple_element_t = typename std::conditional<
71  std::is_lvalue_reference<tuple_element_t<I, Tuple>>::value,
72  typename std::add_lvalue_reference<const typename std::remove_reference<tuple_element_t<I, Tuple>>::type >,
73  const tuple_element_t<I, Tuple>
74  >::type;
75 
76 // get
77 template <size_t I, typename... Ts_>
78 KAT_HD tuple_element_t<I, tuple<Ts_...>>& get(tuple<Ts_...>& t);
79 
80 template <size_t I, typename... Ts_>
81 KAT_HD const_tuple_element_t<I, tuple<Ts_...>>& get(const tuple<Ts_...>& t);
82 
83 template <size_t I, typename... Ts_>
84 KAT_HD tuple_element_t<I, tuple<Ts_...>>&& get(tuple<Ts_...>&& t);
85 
86 template <typename T, typename... ts_>
87 KAT_HD T& get(tuple<ts_...>& t);
88 
89 template <typename T, typename... ts_>
90 KAT_HD const T& get(const tuple<ts_...>& t);
91 
92 template <typename T, typename... ts_>
93 KAT_HD T&& get(tuple<ts_...>&& t);
94 
95 } // namespace kat
96 
97 
98 //EA_DISABLE_VC_WARNING(4623) // warning C4623: default constructor was implicitly defined as deleted
99 //EA_DISABLE_VC_WARNING(4625) // warning C4625: copy constructor was implicitly defined as deleted
100 //EA_DISABLE_VC_WARNING(4510) // warning C4510: default constructor could not be generated
101 
102 namespace kat
103 {
104 // non-recursive tuple implementation based on libc++ tuple implementation and description at
105 // http://mitchnull.blogspot.ca/2012/06/c11-tuple-implementation-details-part-1.html
106 
107 // tuple_types helper
108 template <typename... Ts> struct tuple_types {};
109 
110 // tuple_size helper
111 template <typename T> class tuple_size {};
112 template <typename T> class tuple_size<const T> : public tuple_size<T> {};
113 template <typename T> class tuple_size<volatile T> : public tuple_size<T> {};
114 template <typename T> class tuple_size<const volatile T> : public tuple_size<T> {};
115 
116 template <typename... Ts> class tuple_size<tuple_types<Ts...>> : public std::integral_constant<size_t, sizeof...(Ts)> {};
117 template <typename... Ts> class tuple_size<tuple<Ts...>> : public std::integral_constant<size_t, sizeof...(Ts)> {};
118 
119 template <typename... Ts> class tuple_size<std::tuple<Ts...>> : public std::integral_constant<size_t, sizeof...(Ts)> {};
120 
121 // Originally from EASTL's tuple implementation in their <utility> header
122 
123 template <typename T1, typename T2>
124 class tuple_size<std::pair<T1, T2>> : public std::integral_constant<size_t, 2> {};
125 
126 template <typename T1, typename T2>
127 class tuple_size<const std::pair<T1, T2>> : public std::integral_constant<size_t, 2> {};
128 
129 #if __cplusplus >= 201703L
130  template <class T>
131  constexpr size_t tuple_size_v = tuple_size<T>::value;
132 #endif
133 
134 namespace detail
135 {
136  template <typename TupleIndices, typename... Ts>
137  struct tuple_impl;
138 } // namespace detail
139 
140 template <typename Indices, typename... Ts>
141 class tuple_size<detail::tuple_impl<Indices, Ts...>> : public std::integral_constant<size_t, sizeof...(Ts)> { };
142 
143 // tuple_element helper to be able to isolate a type given an index
144 template <size_t I, typename T>
145 class tuple_element { };
146 
147 template <size_t I>
149 {
150 public:
151  static_assert(I != I, "tuple_element index out of range");
152 };
153 
154 template <typename H, typename... Ts>
155 class tuple_element<0, tuple_types<H, Ts...>>
156 {
157 public:
158  using type = H;
159 };
160 
161 template <size_t I, typename H, typename... Ts>
162 class tuple_element<I, tuple_types<H, Ts...>>
163 {
164 public:
165  using type = tuple_element_t<I - 1, tuple_types<Ts...>>;
166 };
167 
168 // specialization for tuple
169 template <size_t I, typename... Ts>
170 class tuple_element<I, tuple<Ts...>>
171 {
172 public:
173  using type = tuple_element_t<I, tuple_types<Ts...>>;
174 };
175 
176 // tuple-std-tuple compatibility adaptation of the above
177 template <size_t I, typename... Ts>
178 class tuple_element<I, std::tuple<Ts...>>
179 {
180 public:
181  using type = typename std::tuple_element<I, std::tuple<Ts...>>::type;
182 };
183 
184 template <size_t I, typename... Ts>
185 class tuple_element<I, const tuple<Ts...>>
186 {
187 public:
188  using type = typename std::add_const<tuple_element_t<I, tuple_types<Ts...>>>::type;
189 };
190 
191 // tuple-std-tuple compatibility adaptation of the above
192 template <size_t I, typename... Ts>
193 class tuple_element<I, const std::tuple<Ts...>>
194 {
195 public:
196  using type = typename std::tuple_element<I, const std::tuple<Ts...>>::type;
197 };
198 
199 template <size_t I, typename... Ts>
200 class tuple_element<I, volatile tuple<Ts...>>
201 {
202 public:
203  using type = typename std::add_volatile<tuple_element_t<I, tuple_types<Ts...>>>::type;
204 };
205 
206 // tuple-std-tuple compatibility adaptation of the above
207 template <size_t I, typename... Ts>
208 class tuple_element<I, volatile std::tuple<Ts...>>
209 {
210 public:
211  using type = typename std::tuple_element<I, volatile std::tuple<Ts...>>::type;
212 };
213 
214 
215 template <size_t I, typename... Ts>
216 class tuple_element<I, const volatile tuple<Ts...>>
217 {
218 public:
219  using type = typename std::add_cv<tuple_element_t<I, tuple_types<Ts...>>>::type;
220 };
221 
222 // tuple-std-tuple compatibility adaptation of the above
223 template <size_t I, typename... Ts>
224 class tuple_element<I, const volatile std::tuple<Ts...>>
225 {
226 public:
227  using type = typename std::tuple_element<I, const volatile std::tuple<Ts...>>::type;
228 };
229 
230 // specialization for tuple_impl
231 template <size_t I, typename Indices, typename... Ts>
232 class tuple_element<I, detail::tuple_impl<Indices, Ts...>> : public tuple_element<I, tuple<Ts...>>
233 {
234 };
235 
236 template <size_t I, typename Indices, typename... Ts>
237 class tuple_element<I, const detail::tuple_impl<Indices, Ts...>> : public tuple_element<I, const tuple<Ts...>>
238 {
239 };
240 
241 template <size_t I, typename Indices, typename... Ts>
242 class tuple_element<I, volatile detail::tuple_impl<Indices, Ts...>> : public tuple_element<I, volatile tuple<Ts...>>
243 {
244 };
245 
246 template <size_t I, typename Indices, typename... Ts>
247 class tuple_element<I, const volatile detail::tuple_impl<Indices, Ts...>> : public tuple_element<
248  I, const volatile tuple<Ts...>>
249 {
250 };
251 
252 // Originally from EASTL's tuple implementation in their <utility> header
253 
254 template<typename T1, typename T2>
255 class tuple_element<0, std::pair<T1, T2>> {
256 public:
257  typedef T1 type;
258 };
259 
260 template<typename T1, typename T2>
261 class tuple_element<1, std::pair<T1, T2>> {
262 public:
263  typedef T2 type;
264 };
265 
266 template<typename T1, typename T2>
267 class tuple_element<0, const std::pair<T1, T2>> {
268 public:
269  typedef const T1 type;
270 };
271 
272 template<typename T1, typename T2>
273 class tuple_element<1, const std::pair<T1, T2>> {
274 public:
275  typedef const T2 type;
276 };
277 
278 // attempt to isolate index given a type
279 template <typename T, typename Tuple>
281 {
282 };
283 
284 template <typename T>
286 {
287  typedef void DuplicateTypeCheck;
288  tuple_index() = delete; // tuple_index should only be used for compile-time assistance, and never be instantiated
289  static const size_t index = 0;
290 };
291 
292 template <typename T, typename... TsRest>
293 struct tuple_index<T, tuple_types<T, TsRest...>>
294 {
295  typedef int DuplicateTypeCheck;
296  // after finding type T in the list of types, try to find type T in TsRest.
297  // If we stumble back into this version of tuple_index, i.e. type T appears twice in the list of types, then DuplicateTypeCheck will be of type int, and the static_assert will fail.
298  // If we don't, then we'll go through the version of tuple_index above, where all of the types have been exhausted, and DuplicateTypeCheck will be void.
299  static_assert(std::is_void<typename tuple_index<T, tuple_types<TsRest...>>::DuplicateTypeCheck>::value, "duplicate type T in tuple_vector::get<T>(); unique types must be provided in declaration, or only use get<size_t>()");
300 
301  static const size_t index = 0;
302 };
303 
304 template <typename T, typename TsHead, typename... TsRest>
305 struct tuple_index<T, tuple_types<TsHead, TsRest...>>
306 {
307  typedef typename tuple_index<T, tuple_types<TsRest...>>::DuplicateTypeCheck DuplicateTypeCheck;
308  static const size_t index = tuple_index<T, tuple_types<TsRest...>>::index + 1;
309 };
310 
311 template <typename T, typename Indices, typename... Ts>
312 struct tuple_index<T, detail::tuple_impl<Indices, Ts...>> : public tuple_index<T, tuple_types<Ts...>>
313 {
314 };
315 
316 
317 namespace detail {
318 
319 // swallow
320 //
321 // Provides a vessel to expand variadic packs.
322 //
323 template <typename... Ts>
324 constexpr KAT_HD void swallow(Ts&&...) {}
325 
326 
327 // tuple_leaf
328 //
329 template <size_t I, typename ValueType, bool IsEmpty = std::is_empty<ValueType>::value>
331 
332 
333 template <size_t I, typename ValueType, bool IsEmpty>
334 CONSTEXPR_SINCE_CPP_14 inline KAT_HD void swap(
337  ) noexcept(noexcept(kat::swap(a.get_internal(),b.get_internal())))
338 {
339  kat::swap(a.get_internal(), b.get_internal());
340 }
341 
342 template <size_t I, typename ValueType, bool IsEmpty>
343 class tuple_leaf
344 {
345 public:
346  KAT_HD tuple_leaf() : mValue() {}
347  KAT_HD tuple_leaf(const tuple_leaf&) = default; // TODO: This might not work
348  KAT_HD tuple_leaf& operator=(const tuple_leaf&) = delete;
349 
350  // We shouldn't need this explicit constructor as it should be handled by the template below but OSX clang
351  // is_constructible type trait incorrectly gives false for is_constructible<T&&, T&&>::value
352  KAT_HD explicit tuple_leaf(ValueType&& v) : mValue(std::move(v)) {}
353 
354  template <typename T, typename = typename std::enable_if<std::is_constructible<ValueType, T&&>::value>::type>
355  KAT_HD explicit tuple_leaf(T&& t)
356  : mValue(std::forward<T>(t))
357  {
358  }
359 
360  template <typename T>
361  KAT_HD explicit tuple_leaf(const tuple_leaf<I, T>& t)
362  : mValue(t.get_internal())
363  {
364  }
365 
366  template <typename T>
367  KAT_HD tuple_leaf& operator=(T&& t)
368  {
369  mValue = std::forward<T>(t);
370  return *this;
371  }
372 
373  KAT_HD int swap(tuple_leaf& t)
374  {
375  kat::detail::swap(*this, t);
376  return 0;
377  }
378 
379  KAT_HD ValueType& get_internal() { return mValue; }
380  KAT_HD const ValueType& get_internal() const { return mValue; }
381 
382 private:
383  ValueType mValue;
384 };
385 
386 // tuple_leaf: Specialize for when ValueType is a reference
387 template <size_t I, typename ValueType, bool IsEmpty>
388 class tuple_leaf<I, ValueType&, IsEmpty>
389 {
390 public:
391  tuple_leaf(const tuple_leaf&) = default;
392  tuple_leaf& operator=(const tuple_leaf&) = delete;
393 
394  template <typename T, typename = typename std::enable_if<std::is_constructible<ValueType, T&&>::value>::type>
395  KAT_HD explicit tuple_leaf(T&& t)
396  : mValue(std::forward<T>(t))
397  {
398  }
399 
400  KAT_HD explicit tuple_leaf(ValueType& t) : mValue(t)
401  {
402  }
403 
404  template <typename T>
405  KAT_HD explicit tuple_leaf(const tuple_leaf<I, T>& t)
406  : mValue(t.get_internal())
407  {
408  }
409 
410  template <typename T>
411  KAT_HD tuple_leaf& operator=(T&& t)
412  {
413  mValue = std::forward<T>(t);
414  return *this;
415  }
416 
417  KAT_HD int swap(tuple_leaf& t)
418  {
419  kat::detail::swap(*this, t);
420  return 0;
421  }
422 
423  KAT_HD ValueType& get_internal() { return mValue; }
424  KAT_HD const ValueType& get_internal() const { return mValue; }
425 
426 private:
427  ValueType& mValue;
428 };
429 
430 // tuple_leaf: partial specialization for when we can use the Empty Base Class Optimization
431 template <size_t I, typename ValueType>
432 class tuple_leaf<I, ValueType, true> : private ValueType
433 {
434 public:
435  // std::true_type / std::false_type constructors for case where ValueType is default constructible and should be value
436  // initialized and case where it is not
437  tuple_leaf(const tuple_leaf&) = default;
438 
439  template <typename T, typename = typename std::enable_if<std::is_constructible<ValueType, T&&>::value>::type>
440  KAT_HD explicit tuple_leaf(T&& t)
441  : ValueType(std::forward<T>(t))
442  {
443  }
444 
445  template <typename T>
446  KAT_HD explicit tuple_leaf(const tuple_leaf<I, T>& t)
447  : ValueType(t.get_internal())
448  {
449  }
450 
451  template <typename T>
452  KAT_HD tuple_leaf& operator=(T&& t)
453  {
454  ValueType::operator=(std::forward<T>(t));
455  return *this;
456  }
457 
458  KAT_HD int swap(tuple_leaf& t)
459  {
460  kat::detail::swap(*this, t);
461  return 0;
462  }
463 
464  KAT_HD ValueType& get_internal() { return static_cast<ValueType&>(*this); }
465  KAT_HD const ValueType& get_internal() const { return static_cast<const ValueType&>(*this); }
466 
467 private:
468  KAT_HD tuple_leaf& operator=(const tuple_leaf&) = delete;
469 };
470 
471 
472 
473 // make_tuple_types
474 //
475 //
476 template <typename tuple_types, typename Tuple, size_t Start, size_t End>
478 
479 template <typename... Types, typename Tuple, size_t Start, size_t End>
480 struct make_tuple_types_impl<tuple_types<Types...>, Tuple, Start, End>
481 {
482  typedef typename std::remove_reference<Tuple>::type tuple_type;
483  typedef typename make_tuple_types_impl<
484  tuple_types<Types..., typename std::conditional<std::is_lvalue_reference<Tuple>::value,
485  // append ref if Tuple is ref
486  tuple_element_t<Start, tuple_type>&,
487  // append non-ref otherwise
488  tuple_element_t<Start, tuple_type>>::type>,
489  Tuple, Start + 1, End>::type type;
490 };
491 
492 template <typename... Types, typename Tuple, size_t End>
493 struct make_tuple_types_impl<tuple_types<Types...>, Tuple, End, End>
494 {
495  typedef tuple_types<Types...> type;
496 };
497 
498 template <typename Tuple>
499 using make_tuple_types_t = typename make_tuple_types_impl<tuple_types<>, Tuple, 0,
501 
502 
503 // tuple_impl
504 //
505 //
506 template <size_t I, typename Indices, typename... Ts>
507 inline KAT_HD tuple_element_t<I, tuple_impl<Indices, Ts...>>& get(tuple_impl<Indices, Ts...>& t);
508 
509 template <size_t I, typename Indices, typename... Ts>
510 inline KAT_HD const_tuple_element_t<I, tuple_impl<Indices, Ts...>>& get(const tuple_impl<Indices, Ts...>& t);
511 
512 template <size_t I, typename Indices, typename... Ts>
513 KAT_HD tuple_element_t<I, tuple_impl<Indices, Ts...>>&& get(tuple_impl<Indices, Ts...>&& t);
514 
515 template <typename T, typename Indices, typename... Ts>
516 KAT_HD T& get(tuple_impl<Indices, Ts...>& t);
517 
518 template <typename T, typename Indices, typename... Ts>
519 KAT_HD const T& get(const tuple_impl<Indices, Ts...>& t);
520 
521 template <typename T, typename Indices, typename... Ts>
522 KAT_HD T&& get(tuple_impl<Indices, Ts...>&& t);
523 
524 template <size_t... Indices, typename... Ts>
525 struct tuple_impl<std::integer_sequence<size_t, Indices...>, Ts...> : public tuple_leaf<Indices, Ts>...
526 {
527  tuple_impl() = default; // TODO: Probably won't work
528 
529  // index_sequence changed to integer_sequence due to issues described below in VS2015 CTP 6.
530  // https://connect.microsoft.com/VisualStudio/feedback/details/1126958/error-in-template-parameter-pack-expansion-of-std-index-sequence
531  //
532  template <typename... Us, typename... ValueTypes>
533  explicit KAT_HD tuple_impl(std::integer_sequence<size_t, Indices...>, tuple_types<Us...>, ValueTypes&&... values)
534  : tuple_leaf<Indices, Ts>(std::forward<ValueTypes>(values))...
535  {
536  }
537 
538  template <typename OtherTuple>
539  KAT_HD tuple_impl(OtherTuple&& t)
540  : tuple_leaf<Indices, Ts>(std::forward<tuple_element_t<Indices, make_tuple_types_t<OtherTuple>>>(get<Indices>(t)))...
541  {
542  }
543 
544  template <typename OtherTuple>
545  KAT_HD tuple_impl& operator=(OtherTuple&& t)
546  {
548  std::forward<tuple_element_t<Indices, make_tuple_types_t<OtherTuple>>>(get<Indices>(t)))...);
549  return *this;
550  }
551 
552  KAT_HD tuple_impl& operator=(const tuple_impl& t)
553  {
554  swallow(tuple_leaf<Indices, Ts>::operator=(static_cast<const tuple_leaf<Indices, Ts>&>(t).get_internal())...);
555  return *this;
556  }
557 
558  KAT_HD void swap(tuple_impl& t) { swallow(tuple_leaf<Indices, Ts>::swap(static_cast<tuple_leaf<Indices, Ts>&>(t))...); }
559 
560 };
561 
562 template <size_t I, typename Indices, typename... Ts>
563 inline KAT_HD tuple_element_t<I, tuple_impl<Indices, Ts...>>& get(tuple_impl<Indices, Ts...>& t)
564 {
565  typedef tuple_element_t<I, tuple_impl<Indices, Ts...>> Type;
566  return static_cast<detail::tuple_leaf<I, Type>&>(t).get_internal();
567 }
568 
569 template <size_t I, typename Indices, typename... Ts>
570 inline KAT_HD const_tuple_element_t<I, tuple_impl<Indices, Ts...>>& get(const tuple_impl<Indices, Ts...>& t)
571 {
572  typedef tuple_element_t<I, tuple_impl<Indices, Ts...>> Type;
573  return static_cast<const detail::tuple_leaf<I, Type>&>(t).get_internal();
574 }
575 
576 template <size_t I, typename Indices, typename... Ts>
577 inline KAT_HD tuple_element_t<I, tuple_impl<Indices, Ts...>>&& get(tuple_impl<Indices, Ts...>&& t)
578 {
579  typedef tuple_element_t<I, tuple_impl<Indices, Ts...>> Type;
580  return static_cast<Type&&>(static_cast<detail::tuple_leaf<I, Type>&>(t).get_internal());
581 }
582 
583 template <typename T, typename Indices, typename... Ts>
584 KAT_HD T& get(tuple_impl<Indices, Ts...>& t)
585 {
586  typedef tuple_index<T, tuple_impl<Indices, Ts...>> Index;
587  return static_cast<detail::tuple_leaf<Index::index, T>&>(t).get_internal();
588 }
589 
590 template <typename T, typename Indices, typename... Ts>
591 inline KAT_HD const T& get(const tuple_impl<Indices, Ts...>& t)
592 {
593  typedef tuple_index<T, tuple_impl<Indices, Ts...>> Index;
594  return static_cast<const detail::tuple_leaf<Index::index, T>&>(t).get_internal();
595 }
596 
597 template <typename T, typename Indices, typename... Ts>
598 inline KAT_HD T&& get(tuple_impl<Indices, Ts...>&& t)
599 {
600  typedef tuple_index<T, tuple_impl<Indices, Ts...>> Index;
601  return static_cast<T&&>(static_cast<detail::tuple_leaf<Index::index, T>&>(t).get_internal());
602 }
603 
604 template <size_t... Indices, typename... Ts>
605 inline KAT_HOST std::tuple<Ts...> as_std_tuple(tuple_impl<std::integer_sequence<size_t, Indices...>, Ts...> ti);
606 
607 // tuple_like
608 //
609 // type-trait that determines if a type is an eastl::tuple or an eastl::pair.
610 //
611 // TODO: Do we really need these for anything?
612 template <typename T> struct tuple_like : public std::false_type {};
613 template <typename T> struct tuple_like<const T> : public tuple_like<T> {};
614 template <typename T> struct tuple_like<volatile T> : public tuple_like<T> {};
615 template <typename T> struct tuple_like<const volatile T> : public tuple_like<T> {};
616 
617 template <typename... Ts>
618 struct tuple_like<tuple<Ts...>> : public std::true_type {};
619 
620 // tuple-std-tuple compatibility adaptation of the above
621 template <typename... Ts>
622 struct tuple_like<std::tuple<Ts...>> : public std::true_type {};
623 
624 template <typename First, typename Second>
625 struct tuple_like<std::pair<First, Second>> : public std::true_type {};
626 
627 // kat::pair ?
628 //template <typename First, typename Second>
629 //struct tuple_like<kat::pair<First, Second>> : public std::true_type {};
630 
631 
632 // tuple_convertible
633 //
634 //
635 //
636 template <bool IsSameSize, typename From, typename To>
637 struct tuple_convertible_impl : public std::false_type
638 {
639 };
640 
641 template <typename... FromTypes, typename... ToTypes>
642 struct tuple_convertible_impl<true, tuple_types<FromTypes...>, tuple_types<ToTypes...>>
643  : public kat::bool_constant<conjunction<std::is_convertible<FromTypes, ToTypes>...>::value>
644 {
645 };
646 
647 template <typename From, typename To,
650 struct tuple_convertible : public std::false_type
651 {
652 };
653 
654 template <typename From, typename To>
655 struct tuple_convertible<From, To, true, true>
656  : public tuple_convertible_impl<tuple_size<typename std::remove_reference<From>::type>::value ==
657  tuple_size<typename std::remove_reference<To>::type>::value,
658  make_tuple_types_t<From>, make_tuple_types_t<To>>
659 {
660 };
661 
662 
663 // tuple_assignable
664 //
665 //
666 //
667 template <bool IsSameSize, typename Target, typename From>
668 struct tuple_assignable_impl : public std::false_type
669 {
670 };
671 
672 template <typename... TargetTypes, typename... FromTypes>
673 struct tuple_assignable_impl<true, tuple_types<TargetTypes...>, tuple_types<FromTypes...>>
674  : public bool_constant<conjunction<std::is_assignable<TargetTypes, FromTypes>...>::value>
675 {
676 };
677 
678 template <typename Target, typename From,
681 struct tuple_assignable : public std::false_type
682 {
683 };
684 
685 template <typename Target, typename From>
686 struct tuple_assignable<Target, From, true, true>
687  : public tuple_assignable_impl<
688  tuple_size<typename std::remove_reference<Target>::type>::value ==
689  tuple_size<typename std::remove_reference<From>::type>::value,
690  make_tuple_types_t<Target>, make_tuple_types_t<From>>
691 {
695  make_tuple_types_t<Target>, make_tuple_types_t<From>>;
696 };
697 
698 
699 // tuple_implicitly_convertible and tuple_explicitly_convertible
700 //
701 // helpers for constraining conditionally-explicit ctors
702 //
703 template <bool IsSameSize, typename TargetType, typename... FromTypes>
704 struct tuple_implicitly_convertible_impl : public std::false_type
705 {
706 };
707 
708 
709 template <typename... TargetTypes, typename... FromTypes>
710 struct tuple_implicitly_convertible_impl<true, tuple_types<TargetTypes...>, FromTypes...>
711  : public conjunction<
712  std::is_constructible<TargetTypes, FromTypes>...,
713  std::is_convertible<FromTypes, TargetTypes>...>
714 {
715 };
716 
717 template <typename TargetTupleType, typename... FromTypes>
720  tuple_size<TargetTupleType>::value == sizeof...(FromTypes),
721  make_tuple_types_t<TargetTupleType>, FromTypes...>::type
722 {
723 };
724 
725 template<typename TargetTupleType, typename... FromTypes>
726 using tuple_implicitly_convertible_t = std::enable_if_t<tuple_implicitly_convertible<TargetTupleType, FromTypes...>::value, bool>;
727 
728 template <bool IsSameSize, typename TargetType, typename... FromTypes>
729 struct tuple_explicitly_convertible_impl : public std::false_type
730 {
731 };
732 
733 template <typename... TargetTypes, typename... FromTypes>
734 struct tuple_explicitly_convertible_impl<true, tuple_types<TargetTypes...>, FromTypes...>
735  : public conjunction<
736  std::is_constructible<TargetTypes, FromTypes>...,
737  negation<conjunction<std::is_convertible<FromTypes, TargetTypes>...>>>
738 {
739 };
740 
741 template <typename TargetTupleType, typename... FromTypes>
744  tuple_size<TargetTupleType>::value == sizeof...(FromTypes),
745  make_tuple_types_t<TargetTupleType>, FromTypes...>::type
746 {
747 };
748 
749 template<typename TargetTupleType, typename... FromTypes>
750 using tuple_explicitly_convertible_t = std::enable_if_t<tuple_explicitly_convertible<TargetTupleType, FromTypes...>::value, bool>;
751 
752 
753 // tuple_equal
754 //
755 //
756 //
757 template <size_t I>
759 {
760  template <typename Tuple1, typename Tuple2>
761  KAT_HD bool operator()(const Tuple1& t1, const Tuple2& t2)
762  {
763  static_assert(tuple_size<Tuple1>::value == tuple_size<Tuple2>::value, "comparing tuples of different sizes.");
764  return tuple_equal<I - 1>()(t1, t2) && get<I - 1>(t1) == get<I - 1>(t2);
765  }
766 };
767 
768 template <>
769 struct tuple_equal<0>
770 {
771  template <typename Tuple1, typename Tuple2>
772  KAT_HD bool operator()(const Tuple1&, const Tuple2&)
773  {
774  return true;
775  }
776 };
777 
778 
779 // tuple_less
780 //
781 //
782 //
783 template <size_t I>
785 {
786  template <typename Tuple1, typename Tuple2>
787  KAT_HD bool operator()(const Tuple1& t1, const Tuple2& t2)
788  {
789  static_assert(tuple_size<Tuple1>::value == tuple_size<Tuple2>::value, "comparing tuples of different sizes.");
790  return tuple_less<I - 1>()(t1, t2) || (!tuple_less<I - 1>()(t2, t1) && get<I - 1>(t1) < get<I - 1>(t2));
791  }
792 };
793 
794 template <>
795 struct tuple_less<0>
796 {
797  template <typename Tuple1, typename Tuple2>
798  KAT_HD bool operator()(const Tuple1&, const Tuple2&)
799  {
800  return false;
801  }
802 };
803 
804 
805 // MakeTupleReturnImpl
806 //
807 //
808 //
809 template <typename T> struct MakeTupleReturnImpl { typedef T type; };
810 template <typename T> struct MakeTupleReturnImpl<reference_wrapper<T>> { typedef T& type; };
811 
812 template <typename T>
813 using make_tuple_return_t = typename MakeTupleReturnImpl<typename std::decay<T>::type>::type;
814 
815 
816 // tuple_cat helpers
817 //
818 //
819 //
820 
821 // tuple_cat_2_impl
822 template <typename Tuple1, typename Is1, typename Tuple2, typename Is2>
824 
825 template <typename... T1s, size_t... I1s, typename... T2s, size_t... I2s>
826 struct tuple_cat_2_impl<tuple<T1s...>, index_sequence<I1s...>, tuple<T2s...>, index_sequence<I2s...>>
827 {
828  using result_type = tuple<T1s..., T2s...>;
829 
830  template <typename Tuple1, typename Tuple2>
831  static KAT_HD result_type do_cat_2(Tuple1&& t1, Tuple2&& t2)
832  {
833  return result_type(get<I1s>(std::forward<Tuple1>(t1))..., get<I2s>(std::forward<Tuple2>(t2))...);
834  }
835 };
836 
837 // tuple_cat_2
838 template <typename Tuple1, typename Tuple2>
839 struct tuple_cat_2 { };
840 
841 template <typename... T1s, typename... T2s>
842 struct tuple_cat_2<tuple<T1s...>, tuple<T2s...>>
843 {
844  using Is1 = make_index_sequence<sizeof...(T1s)>;
845  using Is2 = make_index_sequence<sizeof...(T2s)>;
846  using tci_type = tuple_cat_2_impl<tuple<T1s...>, Is1, tuple<T2s...>, Is2>;
847  using result_type = typename tci_type::result_type;
848 
849  template <typename Tuple1, typename Tuple2>
850  static inline KAT_HD result_type do_cat_2(Tuple1&& t1, Tuple2&& t2)
851  {
852  return tci_type::do_cat_2(std::forward<Tuple1>(t1), std::forward<Tuple2>(t2));
853  }
854 };
855 
856 // tuple_cat
857 template <typename... Tuples>
858 struct tuple_cat;
859 
860 template <typename Tuple1, typename Tuple2, typename... TuplesRest>
861 struct tuple_cat<Tuple1, Tuple2, TuplesRest...>
862 {
863  using first_result_type = typename tuple_cat_2<Tuple1, Tuple2>::result_type;
864  using result_type = typename tuple_cat<first_result_type, TuplesRest...>::result_type;
865 
866  template <typename TupleArg1, typename TupleArg2, typename... TupleArgsRest>
867  static inline KAT_HD result_type do_cat(TupleArg1&& t1, TupleArg2&& t2, TupleArgsRest&&... ts)
868  {
870  tuple_cat_2<TupleArg1, TupleArg2>::do_cat_2(std::forward<TupleArg1>(t1), std::forward<TupleArg2>(t2)),
871  std::forward<TupleArgsRest>(ts)...);
872  }
873 };
874 
875 template <typename Tuple1, typename Tuple2>
876 struct tuple_cat<Tuple1, Tuple2>
877 {
879  using result_type = typename tc2_type::result_type;
880 
881  template <typename TupleArg1, typename TupleArg2>
882  static KAT_HD result_type do_cat(TupleArg1&& t1, TupleArg2&& t2)
883  {
884  return tc2_type::do_cat_2(std::forward<TupleArg1>(t1), std::forward<TupleArg2>(t2));
885  }
886 };
887 
888 } // namespace detail
889 
890 
891 
898 template <typename T, typename... Ts>
899 class tuple<T, Ts...>
900 {
901 public:
902  tuple() = default; // TODO: This won't work
903 
904  template <typename T2 = T,
905  detail::tuple_implicitly_convertible_t<tuple, const T2&, const Ts&...> = 0>
906  constexpr KAT_HD tuple(const T& t, const Ts&... ts)
907  : impl_(make_index_sequence<sizeof...(Ts) + 1>{}, detail::make_tuple_types_t<tuple>{}, t, ts...)
908  {
909  }
910 
911  template <typename T2 = T,
912  detail::tuple_explicitly_convertible_t<tuple, const T2&, const Ts&...> = 0>
913  explicit constexpr KAT_HD tuple(const T& t, const Ts&... ts)
914  : impl_(make_index_sequence<sizeof...(Ts) + 1>{}, detail::make_tuple_types_t<tuple>{}, t, ts...)
915  {
916  }
917 
918  template <typename U, typename... Us,
919  detail::tuple_implicitly_convertible_t<tuple, U, Us...> = 0>
920  constexpr KAT_HD tuple(U&& u, Us&&... us)
921  : impl_(make_index_sequence<sizeof...(Us) + 1>{}, detail::make_tuple_types_t<tuple>{}, std::forward<U>(u),
922  std::forward<Us>(us)...)
923  {
924  }
925 
926  template <typename U, typename... Us,
927  detail::tuple_explicitly_convertible_t<tuple, U, Us...> = 0>
928  explicit constexpr KAT_HD tuple(U&& u, Us&&... us)
929  : impl_(make_index_sequence<sizeof...(Us) + 1>{}, detail::make_tuple_types_t<tuple>{}, std::forward<U>(u),
930  std::forward<Us>(us)...)
931  {
932  }
933 
934  template <typename OtherTuple,
935  typename std::enable_if<detail::tuple_convertible<OtherTuple, tuple>::value, bool>::type = false>
936  KAT_HD tuple(OtherTuple&& t)
937  : impl_(std::forward<OtherTuple>(t))
938  {
939  }
940 
941  template <typename OtherTuple,
942  typename std::enable_if<detail::tuple_assignable<tuple, OtherTuple>::value, bool>::type = false>
943  KAT_HD tuple& operator=(OtherTuple&& t)
944  {
945  impl_.operator=(std::forward<OtherTuple>(t));
946  return *this;
947  }
948 
949  KAT_HD void swap(tuple& t) { impl_.swap(t.impl_); }
950 
951  // TODO: Perhaps make this explicit?
952  operator std::tuple<T, Ts...>() const {
953  return detail::as_std_tuple(impl_);
954  }
955 
956 private:
957  typedef detail::tuple_impl<kat::make_index_sequence<sizeof...(Ts) + 1>, T, Ts...> impl_type;
958  impl_type impl_;
959 
960  template <size_t I, typename... Ts_>
961  friend KAT_HD tuple_element_t<I, tuple<Ts_...>>& get(tuple<Ts_...>& t);
962 
963  template <size_t I, typename... Ts_>
964  friend KAT_HD const_tuple_element_t<I, tuple<Ts_...>>& get(const tuple<Ts_...>& t);
965 
966  template <size_t I, typename... Ts_>
967  friend KAT_HD tuple_element_t<I, tuple<Ts_...>>&& get(tuple<Ts_...>&& t);
968 
969  template <typename T_, typename... ts_>
970  friend KAT_HD T_& get(tuple<ts_...>& t);
971 
972  template <typename T_, typename... ts_>
973  friend KAT_HD const T_& get(const tuple<ts_...>& t);
974 
975  template <typename T_, typename... ts_>
976  friend KAT_HD T_&& get(tuple<ts_...>&& t);
977 };
978 
979 // template specialization for an empty tuple
980 template <>
981 class tuple<>
982 {
983 public:
984  KAT_HD void swap(tuple&) {}
985 
986  // TODO: Perhaps make this explicit?
987  operator std::tuple<>() const
988  {
989  return std::tuple<>();
990  }
991 };
992 
993 template <size_t I, typename... Ts>
994 inline KAT_HD tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& t)
995 {
996  return get<I>(t.impl_);
997 }
998 
999 template <size_t I, typename... Ts>
1000 inline KAT_HD const_tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& t)
1001 {
1002  return get<I>(t.impl_);
1003 }
1004 
1005 template <size_t I, typename... Ts>
1006 inline KAT_HD tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& t)
1007 {
1008  return get<I>(std::move(t.impl_));
1009 }
1010 
1011 template <typename T, typename... Ts>
1012 inline KAT_HD T& get(tuple<Ts...>& t)
1013 {
1014  return get<T>(t.impl_);
1015 }
1016 
1017 template <typename T, typename... Ts>
1018 inline KAT_HD const T& get(const tuple<Ts...>& t)
1019 {
1020  return get<T>(t.impl_);
1021 }
1022 
1023 template <typename T, typename... Ts>
1024 inline KAT_HD T&& get(tuple<Ts...>&& t)
1025 {
1026  return get<T>(std::move(t.impl_));
1027 }
1028 
1029 template <typename... Ts>
1030 inline KAT_HD void swap(tuple<Ts...>& a, tuple<Ts...>& b)
1031 {
1032  a.swap(b);
1033 }
1034 
1035 
1036 // tuple operators
1037 //
1038 //
1039 template <typename... T1s, typename... T2s>
1040 inline KAT_HD bool operator==(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
1041 {
1042  return detail::tuple_equal<sizeof...(T1s)>()(t1, t2);
1043 }
1044 
1045 // tuple-std-tuple adaptation of the above
1046 template <typename... T1s, typename... T2s>
1047 KAT_HOST bool operator==(const tuple<T1s...>& t1, const std::tuple<T2s...>& t2)
1048 {
1049  return detail::tuple_equal<sizeof...(T1s)>()(t1, tuple<T2s...>{t2});
1050 }
1051 
1052 // tuple-std-tuple adaptation of the above
1053 template <typename... T1s, typename... T2s>
1054 KAT_HOST bool operator==(const std::tuple<T1s...>& t1, const tuple<T2s...>& t2)
1055 {
1056  return detail::tuple_equal<sizeof...(T1s)>()(t1, tuple<T2s...>{t2});
1057 }
1058 
1059 
1060 
1061 template <typename... T1s, typename... T2s>
1062 inline KAT_HD bool operator<(const tuple<T1s...>& t1, const tuple<T2s...>& t2)
1063 {
1064  return detail::tuple_less<sizeof...(T1s)>()(t1, t2);
1065 }
1066 
1067 // tuple-std-tuple adaptation of the above
1068 template <typename... T1s, typename... T2s>
1069 KAT_HOST bool operator<(const tuple<T1s...>& t1, const std::tuple<T2s...>& t2)
1070 {
1071  return detail::tuple_less<sizeof...(T1s)>()(t1, t2);
1072 }
1073 
1074 // tuple-std-tuple adaptation of the above
1075 template <typename... T1s, typename... T2s>
1076 KAT_HOST bool operator<(const std::tuple<T1s...>& t1, const tuple<T2s...>& t2)
1077 {
1078  return detail::tuple_less<sizeof...(T1s)>()(t1, t2);
1079 }
1080 
1081 template <typename... T1s, typename... T2s> inline KAT_HD bool operator!=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 == t2); }
1082 template <typename... T1s, typename... T2s> inline KAT_HD bool operator> (const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return t2 < t1; }
1083 template <typename... T1s, typename... T2s> inline KAT_HD bool operator<=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t2 < t1); }
1084 template <typename... T1s, typename... T2s> inline KAT_HD bool operator>=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 < t2); }
1085 
1086 // tuple-std-tuple adaptation of the above
1087 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator!=(const tuple<T1s...>& t1, const std::tuple<T2s...>& t2) { return !(t1 == t2); }
1088 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator> (const tuple<T1s...>& t1, const std::tuple<T2s...>& t2) { return t2 < t1; }
1089 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator<=(const tuple<T1s...>& t1, const std::tuple<T2s...>& t2) { return !(t2 < t1); }
1090 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator>=(const tuple<T1s...>& t1, const std::tuple<T2s...>& t2) { return !(t1 < t2); }
1091 
1092 // tuple-std-tuple adaptation of the above
1093 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator!=(const std::tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 == t2); }
1094 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator> (const std::tuple<T1s...>& t1, const tuple<T2s...>& t2) { return t2 < t1; }
1095 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator<=(const std::tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t2 < t1); }
1096 template <typename... T1s, typename... T2s> inline KAT_HOST bool operator>=(const std::tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 < t2); }
1097 
1098 
1099 // tuple_cat
1100 //
1101 //
1102 template <typename... Tuples>
1103 inline KAT_HD typename detail::tuple_cat<Tuples...>::result_type tuple_cat(Tuples&&... ts)
1104 {
1105  return detail::tuple_cat<Tuples...>::do_cat(std::forward<Tuples>(ts)...);
1106 }
1107 
1108 
1109 // make_tuple
1110 //
1111 //
1112 template <typename... Ts>
1113 inline KAT_HD constexpr tuple<detail::make_tuple_return_t<Ts>...> make_tuple(Ts&&... values)
1114 {
1115  return tuple<detail::make_tuple_return_t<Ts>...>(std::forward<Ts>(values)...);
1116 }
1117 
1118 
1119 // forward_as_tuple
1120 //
1121 //
1122 template <typename... Ts>
1123 inline KAT_HD constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... ts) noexcept
1124 {
1125  return tuple<Ts&&...>(std::forward<Ts&&>(ts)...);
1126 }
1127 
1128 namespace detail {
1129 
1130 template <size_t... Indices, typename... Ts>
1131 inline KAT_HOST std::tuple<Ts...> as_std_tuple(tuple_impl<std::integer_sequence<size_t, Indices...>, Ts...> ti)
1132 {
1133  return std::make_tuple(get<Indices>(ti)...);
1134 }
1135 
1136 } // namespace detail
1137 
1138 namespace detail {
1139 // ignore
1140 //
1141 // An object of unspecified type such that any value can be assigned to it with no effect.
1142 //
1143 // https://en.cppreference.com/w/cpp/utility/tuple/ignore
1144 //
1145 template <class U>
1146 struct ignore_t
1147 {
1148  template <class T> KAT_HD constexpr const ignore_t& operator=(T&&) const { return *this; }
1149 };
1150 } // namespace detail
1151 
1152 namespace {
1153 // Note: This will probably fail in device side code...
1154 static constexpr const detail::ignore_t<unsigned char> ignore { };
1155 // So you might want to use:
1156 // __device__ static const detail::ignore_t<unsigned char> device_ignore { };
1157 // but we won't enable that here - for now
1158 }
1159 
1165 template <typename... Ts>
1166 inline KAT_HD constexpr tuple<Ts&...> tie(Ts&... ts) noexcept
1167 {
1168  return tuple<Ts&...>(ts...);
1169 }
1170 
1171 #if __cplusplus >= 201703L
1172 
1173 
1174 // apply
1175 //
1176 // Invoke a callable object using a tuple to supply the arguments.
1177 //
1178 // http://en.cppreference.com/w/cpp/utility/apply
1179 //
1180 namespace detail
1181 {
1182  template <class F, class Tuple, size_t... I>
1183  constexpr KAT_HD decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>)
1184  {
1185  // TODO: Will std::invoke really work here? I doubt it.
1186  return std::invoke(forward<F>(f), get<I>(forward<Tuple>(t))...);
1187  }
1188 } // namespace detail
1189 
1190 template <class F, class Tuple>
1191 constexpr KAT_HD decltype(auto) apply(F&& f, Tuple&& t)
1192 {
1193  return detail::apply_impl(std::forward<F>(f), forward<Tuple>(t),
1194  make_index_sequence<tuple_size_v<typename std::remove_reference<Tuple>::type>>{});
1195 }
1196 
1197 #endif
1198 
1199 } // namespace kat
1200 
1201 
1203 // C++17 structured bindings support for kat::tuple
1204 //
1205 #if __cplusplus >= 201703L
1206 
1207 #include <tuple>
1208 namespace std {
1209 
1210 // NOTE(rparolin): Some platform implementations didn't check the standard specification and implemented the
1211 // "tuple_size" and "tuple_element" primary template with as a struct. The standard specifies they are
1212 // implemented with the class keyword so we provide the template specializations as a class and disable the
1213 // generated warning.
1214 
1215 // EA_DISABLE_CLANG_WARNING(-Wmismatched-tags)
1216 
1217 template <class... Ts>
1218 class tuple_size<::kat::tuple<Ts...>> : public std::integral_constant<size_t, sizeof...(Ts)>
1219 {
1220 };
1221 
1222 template <size_t I, class... Ts>
1223 class tuple_element<I, ::kat::tuple<Ts...>> : public ::kat::tuple_element<I, ::kat::tuple<Ts...>>
1224 {
1225 };
1226 
1227 // EA_RESTORE_CLANG_WARNING()
1228 
1229 } // namespace std
1230 
1231 #endif // __cplusplus >= 201703L
1232 
1233 #endif // CUDA_KAT_TUPLE_HPP_
Definition: tuple.hpp:330
reference_wrapper
Definition: reference_wrapper.hpp:53
Definition: tuple.hpp:477
Definition: tuple.hpp:60
Definition: tuple.hpp:758
Definition: tuple.hpp:784
Definition: tuple.hpp:637
Definition: tuple.hpp:839
Definition: tuple.hpp:137
STL namespace.
Definition: tuple.hpp:1146
Definition: common.hpp:16
Basic type and macro definitions used throughout the KAT library.
Definition: tuple.hpp:809
Definition: tuple.hpp:668
Definition: tuple.hpp:63
KAT_FHD CONSTEXPR_SINCE_CPP_14 void swap(T &a, T &b) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value)
Swap two values on the device-side, in-place.
Definition: utility.hpp:73
An adaptation for host-and-device use of some of the standard C++ library&#39;s <utility> code...
Definition: array.hpp:358
Definition: tuple.hpp:823
Definition: tuple.hpp:612
This file implements kat::reference_wrapper, an equivalent of C++11&#39;s std::reference_wrapper which ma...
Definition: tuple.hpp:858
Definition: tuple.hpp:57
Definition: tuple.hpp:108
Definition: tuple.hpp:280
Definition: tuple.hpp:681
Definition: tuple.hpp:650
Definition: common.hpp:32