dune-common  2.11
hybridmultiindex.hh
Go to the documentation of this file.
1 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=8 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
5 
6 #ifndef DUNE_COMMON_HYBRIDMULTIINDEX_HH
7 #define DUNE_COMMON_HYBRIDMULTIINDEX_HH
8 
9 #include <cstddef>
10 #include <cassert>
11 #include <iostream>
12 #include <type_traits>
13 
15 #include <dune/common/indices.hh>
17 
18 namespace Dune {
19 
20  // The Impl namespace collects some free standing functions helper functions
21  namespace Impl {
22 
23  template<class T>
24  constexpr bool isHybridSizeT()
25  {
26  if constexpr (std::is_same_v<T, std::size_t>)
27  return true;
28  else
29  {
30  if constexpr (requires { T::value; })
31  return std::is_same_v<T, std::integral_constant<std::size_t, T::value>>;
32  else
33  return false;
34  }
35  }
36 
37  template<class T>
38  constexpr auto castToHybridSizeT(T t)
39  {
41  {
42  using VT = typename T::value_type;
43  static_assert(
44  std::is_convertible_v<VT,std::size_t> &&
45  std::is_integral_v<VT> &&
46  T::value >= 0,
47  "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
48  return std::integral_constant<std::size_t, T::value>{};
49  }
50  if constexpr (std::is_integral_v<T>)
51  {
52  static_assert(
53  std::is_convertible_v<T,std::size_t> &&
54  std::is_integral_v<T>,
55  "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
56  assert(t >= 0 &&
57  "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
58  return std::size_t(t);
59  }
60  if constexpr (not (Dune::IsIntegralConstant<T>::value or std::is_integral_v<T>))
61  {
62  return std::size_t(0);
63  }
64  }
65 
66  }
67 
79  template<typename... T>
81  {
82 
83  // make sure that all indices use std::size_t as the underlying number type
84  static_assert((... && Impl::isHybridSizeT<T>()),
85  "HybridMultiIndex index storage must be std::size_t or std::integral_constant<std::size_t,v>");
86 
87  public:
88 
90  using index_sequence = std::index_sequence_for<T...>;
91 
92  constexpr HybridMultiIndex() = default;
93 
94  constexpr HybridMultiIndex(const HybridMultiIndex& tp) = default;
95 
96  constexpr HybridMultiIndex(HybridMultiIndex&& tp) = default;
97 
98  constexpr HybridMultiIndex& operator=(const HybridMultiIndex& tp) = default;
99 
100  constexpr HybridMultiIndex& operator=(HybridMultiIndex&& tp) = default;
101 
103  explicit constexpr HybridMultiIndex(std::tuple<T...> t)
104  : _data(t)
105  {}
106 
108  template<typename... I>
109  requires ((sizeof...(T) > 0 && sizeof...(I) == sizeof...(T))
110  and ((std::is_integral_v<I> or Dune::IsIntegralConstant<I>::value) && ...))
111  explicit constexpr HybridMultiIndex(I... i)
112  : _data(Impl::castToHybridSizeT(i)...) // we assume that all arguments are convertible to the types T...
113  {}
114 
116  [[nodiscard]] constexpr static index_sequence enumerate()
117  {
118  return {};
119  }
120 
122  [[nodiscard]] constexpr static std::size_t size()
123  {
124  return sizeof...(T);
125  }
126 
128  [[nodiscard]] constexpr static std::size_t max_size()
129  {
130  return size();
131  }
132 
139  template<std::size_t i>
140  requires (sizeof...(T) > i)
141  [[nodiscard]] constexpr auto get() const
142  {
143  return std::get<i>(_data);
144  }
145 
147  template<std::size_t i>
148  requires (sizeof...(T) > i)
149  [[nodiscard]] constexpr auto operator[](Dune::index_constant<i>) const
150  {
151  return std::get<i>(_data);
152  }
153 
155  [[nodiscard]] constexpr std::size_t operator[](std::size_t pos) const
156  {
157  std::size_t entry = 0;
158  Dune::Hybrid::forEach(enumerate(), [&] (auto i) {
159  if (i==pos)
160  entry = (*this)[i];
161  });
162  return entry;
163  }
164 
166  template<std::size_t i>
167  requires (sizeof...(T) > i)
168  [[deprecated("Method will be removed after Dune 2.11. Use operator[] instead.")]]
169  [[nodiscard]] constexpr auto element(Dune::index_constant<i> pos = {}) const
170  {
171  return std::get<i>(_data);
172  }
173 
175  [[deprecated("Method will be removed after Dune 2.11. Use operator[] instead.")]]
176  [[nodiscard]] constexpr std::size_t element(std::size_t pos) const
177  {
178  std::size_t entry = 0;
179  Dune::Hybrid::forEach(enumerate(), [&] (auto i) {
180  if (i==pos)
181  entry = (*this)[i];
182  });
183  return entry;
184  }
185 
187  template<std::size_t n = sizeof...(T)>
188  requires (n > 0 && n == sizeof...(T))
189  [[nodiscard]] constexpr auto front() const
190  {
191  return std::get<0>(_data);
192  }
193 
195  template<std::size_t n = sizeof...(T)>
196  requires (n > 0 && n == sizeof...(T))
197  [[nodiscard]] constexpr auto back() const
198  {
199  return std::get<n-1>(_data);
200  }
201 
202  private:
203 
204  template<class... Head, class... Other>
205  friend constexpr auto join(const HybridMultiIndex<Head...>&, const Other&...);
206 
207  std::tuple<T...> _data;
208 
209  };
210 
211  template<typename... I>
212  requires (((std::is_integral_v<I> or Dune::IsIntegralConstant<I>::value) && ...))
213  HybridMultiIndex(I... i) -> HybridMultiIndex<decltype(Impl::castToHybridSizeT(i))...>;
214 
215  template<typename... I>
216  HybridMultiIndex(std::tuple<I...>) -> HybridMultiIndex<I...>;
217 
219 
224  template<typename... T>
225  [[nodiscard]] constexpr auto back(const HybridMultiIndex<T...>& tp)
226  -> decltype(tp.back())
227  {
228  return tp.back();
229  }
230 
232 
237  template<typename... T>
238  [[nodiscard]] constexpr auto front(const HybridMultiIndex<T...>& tp)
239  -> decltype(tp.front())
240  {
241  return tp.front();
242  }
243 
245 
248  template<typename... T>
249  [[nodiscard]] constexpr HybridMultiIndex<T...,std::size_t> push_back(const HybridMultiIndex<T...>& tp, std::size_t i)
250  {
251  return unpackIntegerSequence([&](auto... j){
252  return HybridMultiIndex(tp[j] ..., i);
253  }, tp.enumerate());
254  }
255 
257 
271  template<std::size_t i, typename... T>
272  [[nodiscard]] constexpr HybridMultiIndex<T...,index_constant<i>> push_back(const HybridMultiIndex<T...>& tp, index_constant<i> iConstant = {})
273  {
274  return unpackIntegerSequence([&](auto... j){
275  return HybridMultiIndex(tp[j] ..., iConstant);
276  }, tp.enumerate());
277  }
278 
280 
283  template<typename... T>
284  [[nodiscard]] constexpr HybridMultiIndex<std::size_t,T...> push_front(const HybridMultiIndex<T...>& tp, std::size_t i)
285  {
286  return unpackIntegerSequence([&](auto... j){
287  return HybridMultiIndex(i, tp[j] ...);
288  }, tp.enumerate());
289  }
290 
292 
306  template<std::size_t i, typename... T>
307  [[nodiscard]] constexpr HybridMultiIndex<index_constant<i>,T...> push_front(const HybridMultiIndex<T...>& tp, index_constant<i> iConstant = {})
308  {
309  return unpackIntegerSequence([&](auto... j){
310  return HybridMultiIndex(iConstant, tp[j] ...);
311  }, tp.enumerate());
312  }
313 
315 
326  template<typename I, typename... T>
327  requires (sizeof...(T) > 0)
328  [[nodiscard]] constexpr auto accumulate_back(const HybridMultiIndex<T...>& tp, I i) {
330  return push_back(pop_back(tp), plus(back(tp), i));
331  }
332 
333 
335 
346  template<typename I, typename... T>
347  requires (sizeof...(T) > 0)
348  [[nodiscard]] constexpr auto accumulate_front(const HybridMultiIndex<T...>& tp, I i) {
350  return push_front(pop_front(tp), plus(front(tp), i));
351  }
352 
354  template<class... Head, class... Other>
355  [[nodiscard]] constexpr auto join(const HybridMultiIndex<Head...>& head, const Other&... tail) {
356  return Dune::HybridMultiIndex{std::tuple_cat(head._data, tail._data...)};
357  }
358 
360  template<class... T>
361  [[nodiscard]] constexpr auto reverse(const HybridMultiIndex<T...>& tp) {
362  constexpr std::size_t size = sizeof...(T);
363  return unpackIntegerSequence([&](auto... i){
364  return HybridMultiIndex(tp[index_constant<size-i-1>{}] ...);
365  }, std::make_index_sequence<size>{});
366  }
367 
369 
372  template <class... T>
373  requires (sizeof...(T) > 0)
374  [[nodiscard]] constexpr auto pop_front(const HybridMultiIndex<T...>& tp)
375  {
376  return unpackIntegerSequence([&](auto... i){
377  return HybridMultiIndex{std::make_tuple(tp[Dune::index_constant<i+1>{}]...)};
378  }, std::make_index_sequence<(sizeof...(T) - 1)>{});
379  }
380 
382 
385  template <class... T>
386  requires (sizeof...(T) > 0)
387  [[nodiscard]] constexpr auto pop_back(const HybridMultiIndex<T...>& tp)
388  {
389  return unpackIntegerSequence([&](auto... i){
390  return HybridMultiIndex{std::make_tuple(tp[i]...)};
391  }, std::make_index_sequence<(sizeof...(T) - 1)>{});
392  }
393 
395 
403  template <class... S, class... T>
404  [[nodiscard]] constexpr bool operator==(
405  const HybridMultiIndex<S...>& lhs,
406  const HybridMultiIndex<T...>& rhs)
407  {
408  if constexpr (sizeof...(S) == sizeof...(T)) {
409  if constexpr ((Dune::IsInteroperable<S,T>::value &&...)) {
410  return unpackIntegerSequence([&](auto... i){
411  return ((lhs[i] == rhs[i]) &&...);
412  }, lhs.enumerate());
413  } else {
414  return false;
415  }
416  } else {
417  return false;
418  }
419  }
420 
422 
427  template <class S, S... lhs, class T, T... rhs>
428  [[nodiscard]] constexpr auto operator==(
429  const HybridMultiIndex<std::integral_constant<S,lhs>...>&,
430  const HybridMultiIndex<std::integral_constant<T,rhs>...>&)
431  {
432  // If we directly put the expression into std::bool_constant,
433  // gcc-10 deduced the return type of this method as `HybridMultiIndex<>.
434  constexpr auto result = (HybridMultiIndex(lhs...) == HybridMultiIndex(rhs...));
435  return std::bool_constant<result>{};
436  }
437 
438 
440  template <class... S, class... T>
441  [[nodiscard]] constexpr auto operator!=(
442  const HybridMultiIndex<S...>& lhs,
443  const HybridMultiIndex<T...>& rhs)
444  {
445  return !(lhs == rhs);
446  }
447 
449  template <class S, S... lhs, class T, T... rhs>
450  [[nodiscard]] constexpr auto operator!=(
451  const HybridMultiIndex<std::integral_constant<S,lhs>...>&,
452  const HybridMultiIndex<std::integral_constant<T,rhs>...>&)
453  {
454  // If we directly put the expression into std::bool_constant,
455  // gcc-10 deduced the return type of this method as `HybridMultiIndex<>.
456  constexpr auto result = (HybridMultiIndex(lhs...) != HybridMultiIndex(rhs...));
457  return std::bool_constant<result>{};
458  }
459 
461  template<typename... T>
462  std::ostream& operator<<(std::ostream& os, const HybridMultiIndex<T...>& tp)
463  {
464  os << "HybridMultiIndex< ";
465  Dune::Hybrid::forEach(tp, [&] (auto tp_i) {
466  os << tp_i << " ";
467  });
468  os << ">";
469  return os;
470  }
471 
472 } //namespace Dune
473 
474 
475 
476 // Implement the tuple-protocol for HybridMultiIndex
477 namespace std {
478 
479  template<typename... T>
480  struct tuple_size<Dune::HybridMultiIndex<T...>> : public std::integral_constant<std::size_t,sizeof...(T)> {};
481 
482  template <size_t i, typename... T>
483  struct tuple_element<i, Dune::HybridMultiIndex<T...> >
484  {
485  using type = std::tuple_element_t<i, std::tuple<T...> >;
486  };
487 
488 }
489 
490 
491 #endif // DUNE_COMMON_HYBRIDMULTIINDEX_HH
std::ostream & operator<<(std::ostream &s, const bigunsignedint< k > &x)
Definition: bigunsignedint.hh:301
constexpr auto back(const HybridMultiIndex< T... > &tp) -> decltype(tp.back())
Returns a copy of the last element of the HybridMultiIndex.
Definition: hybridmultiindex.hh:225
constexpr HybridMultiIndex()=default
requires(((std::is_integral_v< I > or Dune::IsIntegralConstant< I >::value) &&...)) HybridMultiIndex(I... i) -> HybridMultiIndex< decltype(Impl::castToHybridSizeT(i))... >
constexpr auto reverse(const HybridMultiIndex< T... > &tp)
Reverses the order of the elements in the multi-index.
Definition: hybridmultiindex.hh:361
decltype(auto) constexpr unpackIntegerSequence(F &&f, [[maybe_unused]] std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:124
HybridMultiIndex(std::tuple< I... >) -> HybridMultiIndex< I... >
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
constexpr auto front(const HybridMultiIndex< T... > &tp) -> decltype(tp.front())
Returns a copy of the first element of the HybridMultiIndex.
Definition: hybridmultiindex.hh:238
std::index_sequence_for< T... > index_sequence
An index_sequence for the entries in this HybridMultiIndex.
Definition: hybridmultiindex.hh:90
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
constexpr HybridMultiIndex(std::tuple< T... > t)
Constructor from a std::tuple
Definition: hybridmultiindex.hh:103
constexpr auto plus
Function object for performing addition.
Definition: hybridutilities.hh:533
constexpr HybridMultiIndex< std::size_t, T... > push_front(const HybridMultiIndex< T... > &tp, std::size_t i)
Prepends a run time index to a HybridMultiIndex.
Definition: hybridmultiindex.hh:284
I i
Definition: hybridmultiindex.hh:328
Dune namespace
Definition: alignedallocator.hh:12
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:383
static constexpr index_sequence enumerate()
Returns an index_sequence for enumerating the components of this HybridMultiIndex.
Definition: hybridmultiindex.hh:116
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition: integersequence.hh:22
constexpr std::integral_constant< T, I0 > head(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the single head element.
Definition: integersequence.hh:53
std::tuple_element_t< i, std::tuple< T... > > type
Definition: hybridmultiindex.hh:485
Checks whether two types are interoperable.
Definition: typetraits.hh:64
constexpr auto operator!=(const HybridMultiIndex< S... > &lhs, const HybridMultiIndex< T... > &rhs)
Compare two HybridMultiIndexs for inequality.
Definition: hybridmultiindex.hh:441
static constexpr std::size_t max_size()
Get the size (length) of this multi-index.
Definition: hybridmultiindex.hh:128
requires(sizeof...(T) > i) const expr auto get() const
Get the index value at position pos.
Definition: hybridmultiindex.hh:140
constexpr auto join(const HybridMultiIndex< Head... > &head, const Other &... tail)
Join two hybrid multi-indices into one.
Definition: hybridmultiindex.hh:355
requires((sizeof...(T) > 0 &&sizeof...(I)==sizeof...(T)) and((std::is_integral_v< I > or Dune::IsIntegralConstant< I >::value) &&...)) explicit const expr HybridMultiIndex(I... i)
Constructor from arguments.
Definition: hybridmultiindex.hh:109
constexpr bool operator==(const HybridMultiIndex< S... > &lhs, const HybridMultiIndex< T... > &rhs)
Compare two HybridMultiIndexs for value equality.
Definition: hybridmultiindex.hh:404
requires(sizeof...(T) > i) const expr auto operator[](Dune std::tuple< T... > _data
Get the index value at position pos.
Definition: hybridmultiindex.hh:148
A hybrid multi-index class that supports both compile time and run time indices.
Definition: hybridmultiindex.hh:80
STL namespace.
static constexpr std::size_t size()
Get the size (length) of this multi-index.
Definition: hybridmultiindex.hh:122
constexpr std::integer_sequence< T, II... > tail(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the tail sequence.
Definition: integersequence.hh:58
Traits for type conversions and type information.
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:261
constexpr HybridMultiIndex & operator=(const HybridMultiIndex &tp)=default
constexpr HybridMultiIndex< T..., std::size_t > push_back(const HybridMultiIndex< T... > &tp, std::size_t i)
Appends a run time index to a HybridMultiIndex.
Definition: hybridmultiindex.hh:249