Low-Level Abstraction of Memory Access
Tuple.hpp
Go to the documentation of this file.
1 // Copyright 2023 Alexander Matthes, Bernhard Manfred Gruber
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #pragma once
5 
6 #include "Meta.hpp"
7 #include "macros.hpp"
8 
9 namespace llama
10 {
11  namespace internal
12  {
13  template<std::size_t I, typename T, bool = std::is_empty_v<T> && !std::is_final_v<T>>
15  {
16  T val;
17 
18  LLAMA_FN_HOST_ACC_INLINE constexpr auto value() -> T&
19  {
20  return val;
21  }
22 
23  LLAMA_FN_HOST_ACC_INLINE constexpr auto value() const -> const T&
24  {
25  return val;
26  }
27  };
28 
29  template<std::size_t I, typename T>
31  {
32  static_assert(!std::is_reference_v<T>, "llama::Tuple cannot store references to stateless types");
33 
34  LLAMA_FN_HOST_ACC_INLINE constexpr explicit TupleLeaf(T)
35  {
36  }
37 
38  LLAMA_FN_HOST_ACC_INLINE constexpr auto value() const -> T
39  {
40  return {};
41  }
42  };
43  } // namespace internal
44 
46  template<typename... Elements>
48  {
49  };
50 
53  template<typename TFirstElement, typename... RestElements>
54  struct LLAMA_DECLSPEC_EMPTY_BASES Tuple<TFirstElement, RestElements...>
55  : internal::TupleLeaf<1 + sizeof...(RestElements), TFirstElement>
56  , Tuple<RestElements...>
57  {
58  private:
59  using Leaf = internal::TupleLeaf<1 + sizeof...(RestElements), TFirstElement>;
60 
61  public:
62  using FirstElement = TFirstElement;
63  using RestTuple = Tuple<RestElements...>;
64 
65  constexpr Tuple() = default;
66 
68  LLAMA_FN_HOST_ACC_INLINE constexpr explicit Tuple(FirstElement first, RestElements... rest)
69  : Leaf{std::move(first)}
70  , RestTuple(std::move(rest)...)
71  {
72  }
73 
75  // SFINAE away this ctor if tuple elements cannot be constructed from ctor arguments
76  template<
77  typename T,
78  typename... Ts,
79  std::enable_if_t<
80  sizeof...(RestElements) == sizeof...(Ts)
81  && std::is_constructible_v<FirstElement, T> && (std::is_constructible_v<RestElements, Ts> && ...),
82  int>
83  = 0>
84  LLAMA_FN_HOST_ACC_INLINE constexpr explicit Tuple(T&& firstArg, Ts&&... restArgs)
85  : Leaf{static_cast<FirstElement>(std::forward<T>(firstArg))}
86  , RestTuple(std::forward<Ts>(restArgs)...)
87  {
88  }
89 
91  LLAMA_FN_HOST_ACC_INLINE constexpr auto first() -> decltype(auto)
92  {
93  return Leaf::value();
94  }
95 
97  LLAMA_FN_HOST_ACC_INLINE constexpr auto first() const -> decltype(auto)
98  {
99  return Leaf::value();
100  }
101 
104  {
105  return static_cast<RestTuple&>(*this);
106  }
107 
109  LLAMA_FN_HOST_ACC_INLINE constexpr auto rest() const -> const RestTuple&
110  {
111  return static_cast<const RestTuple&>(*this);
112  }
113  };
114 
116  template<typename... Elements>
118 
120  template<std::size_t I, typename... Elements>
121  LLAMA_FN_HOST_ACC_INLINE constexpr auto get(Tuple<Elements...>& tuple) -> auto&
122  {
123  using Base [[maybe_unused]] // clang claims Base is unused ...
124  = internal::TupleLeaf<sizeof...(Elements) - I, mp_at_c<llama::Tuple<Elements...>, I>>;
125  return tuple.Base::value();
126  }
127 
129  template<std::size_t I, typename... Elements>
130  LLAMA_FN_HOST_ACC_INLINE constexpr auto get(const Tuple<Elements...>& tuple) -> const auto&
131  {
132  using Base [[maybe_unused]] // clang claims Base is unused ...
133  = internal::TupleLeaf<sizeof...(Elements) - I, mp_at_c<llama::Tuple<Elements...>, I>>;
134  return tuple.Base::value();
135  }
136 } // namespace llama
137 
139 template<typename... Elements>
140 struct std::tuple_size<llama::Tuple<Elements...>> // NOLINT(cert-dcl58-cpp)
141 {
142  static constexpr auto value = sizeof...(Elements);
143 };
144 
146 template<std::size_t I, typename... Elements>
147 struct std::tuple_element<I, llama::Tuple<Elements...>> // NOLINT(cert-dcl58-cpp)
148 {
149  using type = boost::mp11::mp_at_c<llama::Tuple<Elements...>, I>;
150 };
151 
152 namespace llama
153 {
154  namespace internal
155  {
156  template<typename... Elements, std::size_t... Is>
158  const Tuple<Elements...>& a,
159  const Tuple<Elements...>& b,
160  std::index_sequence<Is...>) -> bool
161  {
162  return ((get<Is>(a) == get<Is>(b)) && ...);
163  }
164  } // namespace internal
165 
167  template<typename... ElementsA, typename... ElementsB>
169  -> bool
170  {
171  if constexpr(sizeof...(ElementsA) == sizeof...(ElementsB))
172  if constexpr(mp_apply<mp_all, mp_transform<std::is_same, mp_list<ElementsA...>, mp_list<ElementsB...>>>::
173  value)
174  return internal::areEqual(a, b, std::make_index_sequence<sizeof...(ElementsA)>{});
175  return false;
176  }
177 
179  template<typename... ElementsA, typename... ElementsB>
181  -> bool
182  {
183  return !(a == b);
184  }
185 
186  namespace internal
187  {
188  template<typename Tuple1, typename Tuple2, size_t... Is1, size_t... Is2>
190  const Tuple1& t1,
191  const Tuple2& t2,
192  std::index_sequence<Is1...>,
193  std::index_sequence<Is2...>)
194  {
195  return Tuple{get<Is1>(t1)..., get<Is2>(t2)...};
196  }
197  } // namespace internal
198 
200  template<typename Tuple1, typename Tuple2>
201  LLAMA_FN_HOST_ACC_INLINE constexpr auto tupleCat(const Tuple1& t1, const Tuple2& t2)
202  {
203  return internal::tupleCatImpl(
204  t1,
205  t2,
206  std::make_index_sequence<std::tuple_size_v<Tuple1>>{},
207  std::make_index_sequence<std::tuple_size_v<Tuple2>>{});
208  }
209 
210  namespace internal
211  {
212  template<
213  std::size_t Pos,
214  typename Tuple,
215  typename Replacement,
216  std::size_t... IsBefore,
217  std::size_t... IsAfter>
219  Tuple&& tuple,
220  Replacement&& replacement,
221  std::index_sequence<IsBefore...>,
222  std::index_sequence<IsAfter...>)
223  {
224  return llama::Tuple{
225  get<IsBefore>(std::forward<Tuple>(tuple))...,
226  std::forward<Replacement>(replacement),
227  get<Pos + 1 + IsAfter>(std::forward<Tuple>(tuple))...};
228  }
229  } // namespace internal
230 
233  template<std::size_t Pos, typename Tuple, typename Replacement>
234  LLAMA_FN_HOST_ACC_INLINE constexpr auto tupleReplace(Tuple&& tuple, Replacement&& replacement)
235  {
236  return internal::tupleReplaceImpl<Pos>(
237  std::forward<Tuple>(tuple),
238  std::forward<Replacement>(replacement),
239  std::make_index_sequence<Pos>{},
240  std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>> - Pos - 1>{});
241  }
242 
243  namespace internal
244  {
245  template<size_t... Is, typename... Elements, typename Functor>
247  std::index_sequence<Is...>,
248  const Tuple<Elements...>& tuple,
249  const Functor& functor)
250  {
251  return Tuple{functor(get<Is>(tuple))...};
252  }
253  } // namespace internal
254 
258  template<typename... Elements, typename Functor>
259  LLAMA_FN_HOST_ACC_INLINE constexpr auto tupleTransform(const Tuple<Elements...>& tuple, const Functor& functor)
260  {
261  // note: cannot use mp11::tuple_transform since that returns a std::tuple
262  return internal::tupleTransformHelper(std::make_index_sequence<sizeof...(Elements)>{}, tuple, functor);
263  }
264 
267  template<typename... Elements>
269  {
270  return tuple.rest();
271  }
272 } // namespace llama
#define LLAMA_HOST_ACC
Definition: macros.hpp:91
#define LLAMA_EXPORT
Definition: macros.hpp:192
#define LLAMA_DECLSPEC_EMPTY_BASES
Definition: macros.hpp:164
#define LLAMA_FN_HOST_ACC_INLINE
Definition: macros.hpp:96
constexpr auto tupleReplaceImpl(Tuple &&tuple, Replacement &&replacement, std::index_sequence< IsBefore... >, std::index_sequence< IsAfter... >)
Definition: Tuple.hpp:218
constexpr auto tupleTransformHelper(std::index_sequence< Is... >, const Tuple< Elements... > &tuple, const Functor &functor)
Definition: Tuple.hpp:246
constexpr auto tupleCatImpl(const Tuple1 &t1, const Tuple2 &t2, std::index_sequence< Is1... >, std::index_sequence< Is2... >)
Definition: Tuple.hpp:189
constexpr auto areEqual(const Tuple< Elements... > &a, const Tuple< Elements... > &b, std::index_sequence< Is... >) -> bool
Definition: Tuple.hpp:157
Tuple(Elements...) -> Tuple< std::remove_cv_t< std::remove_reference_t< Elements >>... >
constexpr auto tupleCat(const Tuple1 &t1, const Tuple2 &t2)
Definition: Tuple.hpp:201
constexpr auto operator==(ArrayIndex< TA, Dim > a, ArrayIndex< TB, Dim > b) -> bool
constexpr auto operator!=(ArrayIndex< TA, Dim > a, ArrayIndex< TB, Dim > b) -> bool
constexpr auto get(Tuple< Elements... > &tuple) -> auto &
Definition: Tuple.hpp:121
constexpr auto tupleTransform(const Tuple< Elements... > &tuple, const Functor &functor)
Definition: Tuple.hpp:259
constexpr auto popFront([[maybe_unused]] Array< T, N > a)
Definition: Array.hpp:303
constexpr auto tupleReplace(Tuple &&tuple, Replacement &&replacement)
Creates a copy of a tuple with the element at position Pos replaced by replacement.
Definition: Tuple.hpp:234
constexpr auto rest() const -> const RestTuple &
Returns a tuple of all but the first element.
Definition: Tuple.hpp:109
constexpr auto rest() -> RestTuple &
Returns a tuple of all but the first element.
Definition: Tuple.hpp:103
constexpr auto first() const -> decltype(auto)
Returns the first element of the tuple.
Definition: Tuple.hpp:97
constexpr Tuple(FirstElement first, RestElements... rest)
Construct a tuple from values of the same types as the tuple stores.
Definition: Tuple.hpp:68
constexpr auto first() -> decltype(auto)
Returns the first element of the tuple.
Definition: Tuple.hpp:91
constexpr Tuple(T &&firstArg, Ts &&... restArgs)
Construct a tuple from forwarded values of potentially different types as the tuple stores.
Definition: Tuple.hpp:84
constexpr auto value() const -> T
Definition: Tuple.hpp:38
constexpr auto value() const -> const T &
Definition: Tuple.hpp:23
constexpr auto value() -> T &
Definition: Tuple.hpp:18
boost::mp11::mp_at_c< llama::Tuple< Elements... >, I > type
Definition: Tuple.hpp:149