// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2021 The Eigen Team // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_TUPLE_GPU #define EIGEN_TUPLE_GPU #include #include // This is a replacement of std::tuple that can be used in device code. namespace Eigen { namespace internal { namespace tuple_impl { // Internal tuple implementation. template class TupleImpl; // Generic recursive tuple. template class TupleImpl { public: // Tuple may contain Eigen types. EIGEN_MAKE_ALIGNED_OPERATOR_NEW // Default constructor, enable if all types are default-constructible. template ::value && reduce_all::value...>::value>> constexpr EIGEN_DEVICE_FUNC TupleImpl() : head_{}, tail_{} {} // Element constructor. template 1 || std::is_convertible::value)>> constexpr EIGEN_DEVICE_FUNC TupleImpl(U1&& arg1, Us&&... args) : head_(std::forward(arg1)), tail_(std::forward(args)...) {} // The first stored value. EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T1& head() { return head_; } EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const T1& head() const { return head_; } // The tail values. EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TupleImpl& tail() { return tail_; } EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const TupleImpl& tail() const { return tail_; } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void swap(TupleImpl& other) { using numext::swap; swap(head_, other.head_); swap(tail_, other.tail_); } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl& operator=(const TupleImpl& other) { head_ = other.head_; tail_ = other.tail_; return *this; } template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl& operator=(TupleImpl&& other) { head_ = std::move(other.head_); tail_ = std::move(other.tail_); return *this; } private: // Allow related tuples to reference head_/tail_. template friend class TupleImpl; T1 head_; TupleImpl tail_; }; // Empty tuple specialization. template <> class TupleImpl {}; template struct is_tuple : std::false_type {}; template struct is_tuple> : std::true_type {}; // Gets an element from a tuple. template struct tuple_get_impl { using TupleType = TupleImpl; using ReturnType = typename tuple_get_impl::ReturnType; static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE ReturnType& run(TupleType& tuple) { return tuple_get_impl::run(tuple.tail()); } static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const ReturnType& run(const TupleType& tuple) { return tuple_get_impl::run(tuple.tail()); } }; // Base case, getting the head element. template struct tuple_get_impl<0, T1, Ts...> { using TupleType = TupleImpl; using ReturnType = T1; static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T1& run(TupleType& tuple) { return tuple.head(); } static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const T1& run(const TupleType& tuple) { return tuple.head(); } }; // Concatenates N Tuples. template struct tuple_cat_impl; template struct tuple_cat_impl, TupleImpl, Tuples...> { using TupleType1 = TupleImpl; using TupleType2 = TupleImpl; using MergedTupleType = TupleImpl; using ReturnType = typename tuple_cat_impl::ReturnType; // Uses the index sequences to extract and merge elements from tuple1 and tuple2, // then recursively calls again. template static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1, std::index_sequence, Tuple2&& tuple2, std::index_sequence, MoreTuples&&... tuples) { return tuple_cat_impl::run( MergedTupleType(tuple_get_impl::run(std::forward(tuple1))..., tuple_get_impl::run(std::forward(tuple2))...), std::forward(tuples)...); } // Concatenates the first two tuples. template static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1, Tuple2&& tuple2, MoreTuples&&... tuples) { return run(std::forward(tuple1), std::make_index_sequence{}, std::forward(tuple2), std::make_index_sequence{}, std::forward(tuples)...); } }; // Base case with a single tuple. template struct tuple_cat_impl<1, TupleImpl> { using ReturnType = TupleImpl; template static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1) { return tuple1; } }; // Special case of no tuples. template <> struct tuple_cat_impl<0> { using ReturnType = TupleImpl<0>; static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run() { return ReturnType{}; } }; // For use in make_tuple, unwraps a reference_wrapper. template struct unwrap_reference_wrapper { using type = T; }; template struct unwrap_reference_wrapper> { using type = T&; }; // For use in make_tuple, decays a type and unwraps a reference_wrapper. template struct unwrap_decay { using type = typename unwrap_reference_wrapper::type>::type; }; /** * Utility for determining a tuple's size. */ template struct tuple_size; template struct tuple_size> : std::integral_constant {}; /** * Gets an element of a tuple. * \tparam Idx index of the element. * \tparam Types ... tuple element types. * \param tuple the tuple. * \return a reference to the desired element. */ template constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename tuple_get_impl::ReturnType& get( const TupleImpl& tuple) { return tuple_get_impl::run(tuple); } template constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename tuple_get_impl::ReturnType& get( TupleImpl& tuple) { return tuple_get_impl::run(tuple); } /** * Concatenate multiple tuples. * \param tuples ... list of tuples. * \return concatenated tuple. */ template ::type>::value...>::value>> constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename tuple_cat_impl::type...>::ReturnType tuple_cat(Tuples&&... tuples) { return tuple_cat_impl::type...>::run(std::forward(tuples)...); } /** * Tie arguments together into a tuple. */ template > constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType tie(Args&... args) EIGEN_NOEXCEPT { return ReturnType{args...}; } /** * Create a tuple of l-values with the supplied arguments. */ template ::type...>> constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType make_tuple(Args&&... args) { return ReturnType{std::forward(args)...}; } /** * Forward a set of arguments as a tuple. */ template constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl forward_as_tuple(Args&&... args) { return TupleImpl(std::forward(args)...); } /** * Alternative to std::tuple that can be used on device. */ template using tuple = TupleImpl; } // namespace tuple_impl } // namespace internal } // namespace Eigen #endif // EIGEN_TUPLE_GPU