1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Mehdi Goli    Codeplay Software Ltd.
5// Ralph Potter  Codeplay Software Ltd.
6// Luke Iwanski  Codeplay Software Ltd.
7// Contact: <eigen@codeplay.com>
8//
9// This Source Code Form is subject to the terms of the Mozilla
10// Public License v. 2.0. If a copy of the MPL was not distributed
11// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
13/*****************************************************************
14 * TensroSyclTuple.h
15 *
16 * \brief:
17 *  Minimal implementation of std::tuple that can be used inside a SYCL kernel.
18 *
19*****************************************************************/
20
21#ifndef UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSORSYCL_TUPLE_HPP
22#define UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSORSYCL_TUPLE_HPP
23namespace utility {
24namespace tuple {
25/// \struct StaticIf
26/// \brief The StaticIf struct is used to statically choose the type based on the
27/// condition.
28template <bool, typename T = void> struct StaticIf;
29/// \brief specialisation of the \ref StaticIf when the condition is true
30template <typename T>
31struct StaticIf<true, T> {
32  typedef T type;
33};
34
35/// \struct Tuple
36/// \brief is a fixed-size collection of heterogeneous values
37/// \ztparam Ts...	-	the types of the elements that the tuple stores.
38/// Empty list is supported.
39template <class... Ts>
40struct Tuple {};
41
42/// \brief specialisation of the \ref Tuple class when the tuple has at least
43/// one element.
44/// \tparam T : the type of the first element in the tuple.
45/// \tparam Ts... the rest of the elements in the tuple. Ts... can be empty.
46template <class T, class... Ts>
47struct Tuple<T, Ts...> {
48  Tuple(T t, Ts... ts) : head(t), tail(ts...) {}
49  T head;
50  Tuple<Ts...> tail;
51};
52
53///\ struct ElemTypeHolder
54/// \brief ElemTypeHolder class is used to specify the types of the
55/// elements inside the tuple
56/// \tparam size_t the number of elements inside the tuple
57/// \tparam class the tuple class
58template <size_t, class>
59struct ElemTypeHolder;
60
61/// \brief specialisation of the \ref ElemTypeHolder class when the number of
62/// elements inside the tuple is 1
63template <class T, class... Ts>
64struct ElemTypeHolder<0, Tuple<T, Ts...> > {
65  typedef T type;
66};
67
68/// \brief specialisation of the \ref ElemTypeHolder class when the number of
69/// elements inside the tuple is bigger than 1. It recursively calls itself to
70/// detect the type of each element in the tuple
71/// \tparam T : the type of the first element in the tuple.
72/// \tparam Ts... the rest of the elements in the tuple. Ts... can be empty.
73/// \tparam K is the Kth element in the tuple
74template <size_t k, class T, class... Ts>
75struct ElemTypeHolder<k, Tuple<T, Ts...> > {
76  typedef typename ElemTypeHolder<k - 1, Tuple<Ts...> >::type type;
77};
78
79/// get
80/// \brief Extracts the first element from the tuple.
81/// K=0 represents the first element of the tuple. The tuple cannot be empty.
82/// \tparam Ts... are the type of the elements in the tuple.
83/// \param t is the tuple whose contents to extract
84/// \return  typename ElemTypeHolder<0, Tuple<Ts...> >::type &>::type
85
86#define TERMINATE_CONDS_TUPLE_GET(CVQual) \
87template <size_t k, class... Ts> \
88typename StaticIf<k == 0, CVQual typename ElemTypeHolder<0, Tuple<Ts...> >::type &>::type \
89get(CVQual Tuple<Ts...> &t) { \
90  static_assert(sizeof...(Ts)!=0, "The requseted value is bigger than the size of the tuple"); \
91  return t.head; \
92}
93
94TERMINATE_CONDS_TUPLE_GET(const)
95TERMINATE_CONDS_TUPLE_GET()
96#undef TERMINATE_CONDS_TUPLE_GET
97/// get
98/// \brief Extracts the Kth element from the tuple.
99///\tparam K is an integer value in [0,sizeof...(Types)).
100/// \tparam T is the (sizeof...(Types) -(K+1)) element in the tuple
101/// \tparam Ts... are the type of the elements  in the tuple.
102/// \param t is the tuple whose contents to extract
103/// \return  typename ElemTypeHolder<K, Tuple<Ts...> >::type &>::type
104#define RECURSIVE_TUPLE_GET(CVQual) \
105template <size_t k, class T, class... Ts> \
106typename StaticIf<k != 0, CVQual typename ElemTypeHolder<k, Tuple<T, Ts...> >::type &>::type \
107get(CVQual Tuple<T, Ts...> &t) { \
108  return utility::tuple::get<k - 1>(t.tail); \
109}
110RECURSIVE_TUPLE_GET(const)
111RECURSIVE_TUPLE_GET()
112#undef RECURSIVE_TUPLE_GET
113
114/// make_tuple
115/// \brief Creates a tuple object, deducing the target type from the types of
116/// arguments.
117/// \tparam Args the type of the arguments to construct the tuple from
118/// \param args zero or more arguments to construct the tuple from
119/// \return Tuple<Args...>
120template <typename... Args>
121Tuple<Args...> make_tuple(Args... args) {
122  return Tuple<Args...>(args...);
123}
124
125/// size
126/// \brief Provides access to the number of elements in a tuple as a
127/// compile-time constant expression.
128/// \tparam Args the type of the arguments to construct the tuple from
129/// \return size_t
130template <typename... Args>
131static constexpr size_t size(Tuple<Args...> &) {
132  return sizeof...(Args);
133}
134
135/// \struct IndexList
136/// \brief Creates a list of index from the elements in the tuple
137/// \tparam Is... a list of index from [0 to sizeof...(tuple elements))
138template <size_t... Is>
139struct IndexList {};
140
141/// \struct RangeBuilder
142/// \brief Collects internal details for generating index ranges [MIN, MAX)
143/// Declare primary template for index range builder
144/// \tparam MIN is the starting index in the tuple
145/// \tparam N represents sizeof..(elemens)- sizeof...(Is)
146/// \tparam Is... are the list of generated index so far
147template <size_t MIN, size_t N, size_t... Is>
148struct RangeBuilder;
149
150/// \brief base Step: Specialisation of the \ref RangeBuilder when the
151/// MIN==MAX. In this case the Is... is [0 to sizeof...(tuple elements))
152/// \tparam MIN is the starting index of the tuple
153/// \tparam Is is [0 to sizeof...(tuple elements))
154template <size_t MIN, size_t... Is>
155struct RangeBuilder<MIN, MIN, Is...> {
156  typedef IndexList<Is...> type;
157};
158
159/// Induction step: Specialisation of the RangeBuilder class when N!=MIN
160/// in this case we are recursively subtracting N by one and adding one
161/// index to Is... list until MIN==N
162/// \tparam MIN is the starting index in the tuple
163/// \tparam N represents sizeof..(elemens)- sizeof...(Is)
164/// \tparam Is... are the list of generated index so far
165template <size_t MIN, size_t N, size_t... Is>
166struct RangeBuilder : public RangeBuilder<MIN, N - 1, N - 1, Is...> {};
167
168/// \brief IndexRange that returns a [MIN, MAX) index range
169/// \tparam MIN is the starting index in the tuple
170/// \tparam MAX is the size of the tuple
171template <size_t MIN, size_t MAX>
172struct IndexRange: RangeBuilder<MIN, MAX>::type {};
173
174/// append_base
175/// \brief unpacking the elements of the input tuple t and creating a new tuple
176/// by adding element a at the end of it.
177///\tparam Args... the type of the elements inside the tuple t
178/// \tparam T the type of the new element going to be added at the end of tuple
179/// \tparam I... is the list of index from [0 to sizeof...(t))
180/// \param t the tuple on which we want to append a.
181/// \param a the new elements going to be added to the tuple
182/// \return Tuple<Args..., T>
183template <typename... Args, typename T, size_t... I>
184Tuple<Args..., T> append_base(Tuple<Args...> t, T a,IndexList<I...>) {
185  return utility::tuple::make_tuple(get<I>(t)..., a);
186}
187
188/// append
189/// \brief the deduction function for \ref append_base that automatically
190/// generate the \ref IndexRange
191///\tparam Args... the type of the elements inside the tuple t
192/// \tparam T the type of the new element going to be added at the end of tuple
193/// \param t the tuple on which we want to append a.
194/// \param a the new elements going to be added to the tuple
195/// \return Tuple<Args..., T>
196template <typename... Args, typename T>
197Tuple<Args..., T> append(Tuple<Args...> t, T a) {
198  return utility::tuple::append_base(t, a,  IndexRange<0, sizeof...(Args)>());
199}
200
201/// append_base
202/// \brief This is a specialisation of \ref append_base when we want to
203/// concatenate
204/// tuple t2 at the end of the tuple t1. Here we unpack both tuples, generate the
205/// IndexRange for each of them and create an output tuple T that contains both
206/// elements of t1 and t2.
207///\tparam Args1... the type of the elements inside the tuple t1
208///\tparam Args2... the type of the elements inside the tuple t2
209/// \tparam I1... is the list of index from [0 to sizeof...(t1))
210/// \tparam I2... is the list of index from [0 to sizeof...(t2))
211/// \param t1 is the tuple on which we want to append t2.
212/// \param t2 is the tuple that is going to be added on t1.
213/// \return Tuple<Args1..., Args2...>
214template <typename... Args1, typename... Args2, size_t... I1, size_t... I2>
215Tuple<Args1..., Args2...> append_base(Tuple<Args1...> t1, Tuple<Args2...> t2, IndexList<I1...>, IndexList<I2...>) {
216  return utility::tuple::make_tuple(get<I1>(t1)...,get<I2>(t2)...);
217}
218
219/// append
220/// \brief deduction function for \ref append_base when we are appending tuple
221/// t1 by tuple t2. In this case the \ref IndexRange for both tuple are
222/// automatically generated.
223///\tparam Args1... the type of the elements inside the tuple t1
224///\tparam Args2... the type of the elements inside the tuple t2
225/// \param t1 is the tuple on which we want to append t2.
226/// \param t2 is the tuple that is going to be added on t1.
227/// \return Tuple<Args1..., Args2...>
228template <typename... Args1, typename... Args2>
229Tuple<Args1..., Args2...> append(Tuple<Args1...> t1,Tuple<Args2...> t2) {
230  return utility::tuple::append_base(t1, t2, IndexRange<0, sizeof...(Args1)>(), IndexRange<0, sizeof...(Args2)>());
231}
232}  // tuple
233}  // utility
234#endif  // UNSUPPORTED_EIGEN_CXX11_SRC_TENSOR_TENSORSYCL_TUPLE_HPP
235