Dune Core Modules (unstable)

hybridmultiindex.hh
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>
16#include <dune/common/hybridutilities.hh>
17
18namespace Dune {
19
24 // The Impl namespace collects some free standing functions helper functions
25 namespace Impl {
26
27 template<class T>
28 constexpr bool isHybridSizeT()
29 {
30 if constexpr (std::is_same_v<T, std::size_t>)
31 return true;
32 else
33 {
34 if constexpr (requires { T::value; })
35 return std::is_same_v<T, std::integral_constant<std::size_t, T::value>>;
36 else
37 return false;
38 }
39 }
40
41 template<class T>
42 constexpr auto castToHybridSizeT(T t)
43 {
45 {
46 using VT = typename T::value_type;
47 static_assert(
48 std::is_convertible_v<VT,std::size_t> &&
49 std::is_integral_v<VT> &&
50 T::value >= 0,
51 "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
52 return std::integral_constant<std::size_t, T::value>{};
53 }
54 if constexpr (std::is_integral_v<T>)
55 {
56 static_assert(
57 std::is_convertible_v<T,std::size_t> &&
58 std::is_integral_v<T>,
59 "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
60 assert(t >= 0 &&
61 "HybridMultiIndex indices must be convertible to std::size_t or std::integral_constant<std::size_t,v>");
62 return std::size_t(t);
63 }
64 if constexpr (not (Dune::IsIntegralConstant<T>::value or std::is_integral_v<T>))
65 {
66 return std::size_t(0);
67 }
68 }
69
70 }
71
83 template<typename... T>
85 {
86
87 // make sure that all indices use std::size_t as the underlying number type
88 static_assert((... && Impl::isHybridSizeT<T>()),
89 "HybridMultiIndex index storage must be std::size_t or std::integral_constant<std::size_t,v>");
90
91 public:
92
94 using index_sequence = std::index_sequence_for<T...>;
95
96 constexpr HybridMultiIndex() = default;
97
98 constexpr HybridMultiIndex(const HybridMultiIndex& tp) = default;
99
100 constexpr HybridMultiIndex(HybridMultiIndex&& tp) = default;
101
102 constexpr HybridMultiIndex& operator=(const HybridMultiIndex& tp) = default;
103
104 constexpr HybridMultiIndex& operator=(HybridMultiIndex&& tp) = default;
105
107 explicit constexpr HybridMultiIndex(std::tuple<T...> t)
108 : _data(t)
109 {}
110
112 template<typename... I>
113 requires ((sizeof...(T) > 0 && sizeof...(I) == sizeof...(T))
114 and ((std::is_integral_v<I> or Dune::IsIntegralConstant<I>::value) && ...))
115 explicit constexpr HybridMultiIndex(I... i)
116 : _data(Impl::castToHybridSizeT(i)...) // we assume that all arguments are convertible to the types T...
117 {}
118
120 [[nodiscard]] constexpr static index_sequence enumerate()
121 {
122 return {};
123 }
124
126 [[nodiscard]] constexpr static std::size_t size()
127 {
128 return sizeof...(T);
129 }
130
132 [[nodiscard]] constexpr static std::size_t max_size()
133 {
134 return size();
135 }
136
143 template<std::size_t i>
144 requires (sizeof...(T) > i)
145 [[nodiscard]] constexpr auto get() const
146 {
147 return std::get<i>(_data);
148 }
149
151 template<std::size_t i>
152 requires (sizeof...(T) > i)
153 [[nodiscard]] constexpr auto operator[](Dune::index_constant<i>) const
154 {
155 return std::get<i>(_data);
156 }
157
159 [[nodiscard]] constexpr std::size_t operator[](std::size_t pos) const
160 {
161 std::size_t entry = 0;
162 Dune::Hybrid::forEach(enumerate(), [&] (auto i) {
163 if (i==pos)
164 entry = (*this)[i];
165 });
166 return entry;
167 }
168
170 template<std::size_t n = sizeof...(T)>
171 requires (n > 0 && n == sizeof...(T))
172 [[nodiscard]] constexpr auto front() const
173 {
174 return std::get<0>(_data);
175 }
176
178 template<std::size_t n = sizeof...(T)>
179 requires (n > 0 && n == sizeof...(T))
180 [[nodiscard]] constexpr auto back() const
181 {
182 return std::get<n-1>(_data);
183 }
184
185 private:
186
187 template<class... Head, class... Other>
188 friend constexpr auto join(const HybridMultiIndex<Head...>&, const Other&...);
189
190 std::tuple<T...> _data;
191
192 };
193
194 template<typename... I>
195 requires (((std::is_integral_v<I> or Dune::IsIntegralConstant<I>::value) && ...))
196 HybridMultiIndex(I... i) -> HybridMultiIndex<decltype(Impl::castToHybridSizeT(i))...>;
197
198 template<typename... I>
199 HybridMultiIndex(std::tuple<I...>) -> HybridMultiIndex<I...>;
200
202
209 template<typename... T>
210 [[nodiscard]] constexpr auto back(const HybridMultiIndex<T...>& tp)
211 -> decltype(tp.back())
212 {
213 return tp.back();
214 }
215
217
224 template<typename... T>
225 [[nodiscard]] constexpr auto front(const HybridMultiIndex<T...>& tp)
226 -> decltype(tp.front())
227 {
228 return tp.front();
229 }
230
232
237 template<typename... T>
238 [[nodiscard]] constexpr HybridMultiIndex<T...,std::size_t> push_back(const HybridMultiIndex<T...>& tp, std::size_t i)
239 {
240 return unpackIntegerSequence([&](auto... j){
241 return HybridMultiIndex(tp[j] ..., i);
242 }, tp.enumerate());
243 }
244
246
261 template<std::size_t i, typename... T>
262 [[nodiscard]] constexpr HybridMultiIndex<T...,index_constant<i>> push_back(const HybridMultiIndex<T...>& tp, index_constant<i> iConstant = {})
263 {
264 return unpackIntegerSequence([&](auto... j){
265 return HybridMultiIndex(tp[j] ..., iConstant);
266 }, tp.enumerate());
267 }
268
270
275 template<typename... T>
276 [[nodiscard]] constexpr HybridMultiIndex<std::size_t,T...> push_front(const HybridMultiIndex<T...>& tp, std::size_t i)
277 {
278 return unpackIntegerSequence([&](auto... j){
279 return HybridMultiIndex(i, tp[j] ...);
280 }, tp.enumerate());
281 }
282
284
299 template<std::size_t i, typename... T>
300 [[nodiscard]] constexpr HybridMultiIndex<index_constant<i>,T...> push_front(const HybridMultiIndex<T...>& tp, index_constant<i> iConstant = {})
301 {
302 return unpackIntegerSequence([&](auto... j){
303 return HybridMultiIndex(iConstant, tp[j] ...);
304 }, tp.enumerate());
305 }
306
308
321 template<typename I, typename... T>
322 requires (sizeof...(T) > 0)
323 [[nodiscard]] constexpr auto accumulate_back(const HybridMultiIndex<T...>& tp, I i) {
325 return push_back(pop_back(tp), plus(back(tp), i));
326 }
327
328
330
343 template<typename I, typename... T>
344 requires (sizeof...(T) > 0)
345 [[nodiscard]] constexpr auto accumulate_front(const HybridMultiIndex<T...>& tp, I i) {
347 return push_front(pop_front(tp), plus(front(tp), i));
348 }
349
351
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
363 template<class... T>
364 [[nodiscard]] constexpr auto reverse(const HybridMultiIndex<T...>& tp) {
365 constexpr std::size_t size = sizeof...(T);
366 return unpackIntegerSequence([&](auto... i){
368 }, std::make_index_sequence<size>{});
369 }
370
372
377 template <class... T>
378 requires (sizeof...(T) > 0)
379 [[nodiscard]] constexpr auto pop_front(const HybridMultiIndex<T...>& tp)
380 {
381 return unpackIntegerSequence([&](auto... i){
382 return HybridMultiIndex{std::make_tuple(tp[Dune::index_constant<i+1>{}]...)};
383 }, std::make_index_sequence<(sizeof...(T) - 1)>{});
384 }
385
387
392 template <class... T>
393 requires (sizeof...(T) > 0)
394 [[nodiscard]] constexpr auto pop_back(const HybridMultiIndex<T...>& tp)
395 {
396 return unpackIntegerSequence([&](auto... i){
397 return HybridMultiIndex{std::make_tuple(tp[i]...)};
398 }, std::make_index_sequence<(sizeof...(T) - 1)>{});
399 }
400
402
412 template <class... S, class... T>
413 [[nodiscard]] constexpr bool operator==(
414 const HybridMultiIndex<S...>& lhs,
415 const HybridMultiIndex<T...>& rhs)
416 {
417 if constexpr (sizeof...(S) == sizeof...(T)) {
418 if constexpr ((Dune::IsInteroperable<S,T>::value &&...)) {
419 return unpackIntegerSequence([&](auto... i){
420 return ((lhs[i] == rhs[i]) &&...);
421 }, lhs.enumerate());
422 } else {
423 return false;
424 }
425 } else {
426 return false;
427 }
428 }
429
431
438 template <class S, S... lhs, class T, T... rhs>
439 [[nodiscard]] constexpr auto operator==(
440 const HybridMultiIndex<std::integral_constant<S,lhs>...>&,
441 const HybridMultiIndex<std::integral_constant<T,rhs>...>&)
442 {
443 // If we directly put the expression into std::bool_constant,
444 // gcc-10 deduced the return type of this method as `HybridMultiIndex<>.
445 constexpr auto result = (HybridMultiIndex(lhs...) == HybridMultiIndex(rhs...));
446 return std::bool_constant<result>{};
447 }
448
449
451
454 template <class... S, class... T>
455 [[nodiscard]] constexpr auto operator!=(
456 const HybridMultiIndex<S...>& lhs,
457 const HybridMultiIndex<T...>& rhs)
458 {
459 return !(lhs == rhs);
460 }
461
463
466 template <class S, S... lhs, class T, T... rhs>
467 [[nodiscard]] constexpr auto operator!=(
468 const HybridMultiIndex<std::integral_constant<S,lhs>...>&,
469 const HybridMultiIndex<std::integral_constant<T,rhs>...>&)
470 {
471 // If we directly put the expression into std::bool_constant,
472 // gcc-10 deduced the return type of this method as `HybridMultiIndex<>.
473 constexpr auto result = (HybridMultiIndex(lhs...) != HybridMultiIndex(rhs...));
474 return std::bool_constant<result>{};
475 }
476
478
481 template<typename... T>
482 std::ostream& operator<<(std::ostream& os, const HybridMultiIndex<T...>& tp)
483 {
484 os << "HybridMultiIndex< ";
485 Dune::Hybrid::forEach(tp, [&] (auto tp_i) {
486 os << tp_i << " ";
487 });
488 os << ">";
489 return os;
490 }
491
495} //namespace Dune
496
497
498
499// Implement the tuple-protocol for HybridMultiIndex
500namespace std {
501
502 template<typename... T>
503 struct tuple_size<Dune::HybridMultiIndex<T...>> : public std::integral_constant<std::size_t,sizeof...(T)> {};
504
505 template <size_t i, typename... T>
506 struct tuple_element<i, Dune::HybridMultiIndex<T...> >
507 {
508 using type = std::tuple_element_t<i, std::tuple<T...> >;
509 };
510
511}
512
513
514#endif // DUNE_COMMON_HYBRIDMULTIINDEX_HH
A hybrid multi-index class that supports both compile time and run time indices.
Definition: hybridmultiindex.hh:85
static constexpr std::size_t size()
Get the size (length) of this multi-index.
Definition: hybridmultiindex.hh:126
constexpr auto operator[](Dune::index_constant< i >) const
Get the index value at position pos.
Definition: hybridmultiindex.hh:153
static constexpr std::size_t max_size()
Get the size (length) of this multi-index.
Definition: hybridmultiindex.hh:132
constexpr auto front() const
Get the first index value. Only available in non-empty multi-indices.
Definition: hybridmultiindex.hh:172
static constexpr index_sequence enumerate()
Returns an index_sequence for enumerating the components of this HybridMultiIndex.
Definition: hybridmultiindex.hh:120
constexpr auto get() const
Get the index value at position pos.
Definition: hybridmultiindex.hh:145
constexpr HybridMultiIndex(std::tuple< T... > t)
Constructor from a std::tuple
Definition: hybridmultiindex.hh:107
constexpr auto back() const
Get the last index value. Only available in non-empty multi-indices.
Definition: hybridmultiindex.hh:180
std::index_sequence_for< T... > index_sequence
An index_sequence for the entries in this HybridMultiIndex.
Definition: hybridmultiindex.hh:94
constexpr std::size_t operator[](std::size_t pos) const
Get the index value at position pos.
Definition: hybridmultiindex.hh:159
constexpr HybridMultiIndex(I... i)
Constructor from arguments.
Definition: hybridmultiindex.hh:115
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:261
constexpr auto plus
Function object for performing addition.
Definition: hybridutilities.hh:533
constexpr auto reverse(const HybridMultiIndex< T... > &tp)
Reverses the order of the elements in the multi-index.
Definition: hybridmultiindex.hh:364
constexpr auto back(const HybridMultiIndex< T... > &tp) -> decltype(tp.back())
Returns a copy of the last element of the HybridMultiIndex.
Definition: hybridmultiindex.hh:210
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:276
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:238
constexpr bool operator==(const HybridMultiIndex< S... > &lhs, const HybridMultiIndex< T... > &rhs)
Compare two HybridMultiIndexs for value equality.
Definition: hybridmultiindex.hh:413
std::ostream & operator<<(std::ostream &os, const HybridMultiIndex< T... > &tp)
Dumps a HybridMultiIndex to a stream.
Definition: hybridmultiindex.hh:482
constexpr auto accumulate_front(const HybridMultiIndex< T... > &tp, I i)
Hybrid utility that accumulates to the front of a multi-index.
Definition: hybridmultiindex.hh:345
constexpr auto pop_back(const HybridMultiIndex< T... > &tp)
Removes last index on a HybridMultiIndex.
Definition: hybridmultiindex.hh:394
constexpr auto accumulate_back(const HybridMultiIndex< T... > &tp, I i)
Hybrid utility that accumulates to the back of a multi-index.
Definition: hybridmultiindex.hh:323
constexpr auto front(const HybridMultiIndex< T... > &tp) -> decltype(tp.front())
Returns a copy of the first element of the HybridMultiIndex.
Definition: hybridmultiindex.hh:225
decltype(auto) constexpr unpackIntegerSequence(F &&f, std::integer_sequence< I, i... > sequence)
Unpack an std::integer_sequence<I,i...> to std::integral_constant<I,i>...
Definition: indices.hh:124
constexpr HybridMultiIndex< T..., index_constant< i > > push_back(const HybridMultiIndex< T... > &tp, index_constant< i > iConstant={})
Appends a compile time index to a HybridMultiIndex.
Definition: hybridmultiindex.hh:262
constexpr auto join(const HybridMultiIndex< Head... > &head, const Other &... tail)
Join two hybrid multi-indices into one.
Definition: hybridmultiindex.hh:355
constexpr auto operator!=(const HybridMultiIndex< std::integral_constant< S, lhs >... > &, const HybridMultiIndex< std::integral_constant< T, rhs >... > &)
Compare two static HybridMultiIndexs for inequality.
Definition: hybridmultiindex.hh:467
constexpr auto operator==(const HybridMultiIndex< std::integral_constant< S, lhs >... > &, const HybridMultiIndex< std::integral_constant< T, rhs >... > &)
Overload for purely static HybridMultiIndexs.
Definition: hybridmultiindex.hh:439
constexpr HybridMultiIndex< index_constant< i >, T... > push_front(const HybridMultiIndex< T... > &tp, index_constant< i > iConstant={})
Prepends a compile time index to a HybridMultiIndex.
Definition: hybridmultiindex.hh:300
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
constexpr auto operator!=(const HybridMultiIndex< S... > &lhs, const HybridMultiIndex< T... > &rhs)
Compare two HybridMultiIndexs for inequality.
Definition: hybridmultiindex.hh:455
constexpr auto pop_front(const HybridMultiIndex< T... > &tp)
Removes first index on a HybridMultiIndex.
Definition: hybridmultiindex.hh:379
Dune namespace
Definition: alignedallocator.hh:13
constexpr std::integer_sequence< T, II..., T(IN)> push_back(std::integer_sequence< T, II... >, std::integral_constant< T, IN >={})
Append an index IN to the back of the sequence.
Definition: integersequence.hh:69
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 std::integer_sequence< T, T(I0), II... > push_front(std::integer_sequence< T, II... >, std::integral_constant< T, I0 >={})
Append an index I0 to the front of the sequence.
Definition: integersequence.hh:64
constexpr std::integral_constant< T, I0 > front(std::integer_sequence< T, I0, II... >)
Return the first entry of the sequence.
Definition: integersequence.hh:39
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
constexpr auto back(std::integer_sequence< T, II... > seq)
Return the last entry of the sequence.
Definition: integersequence.hh:44
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
STL namespace.
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:384
Checks whether two types are interoperable.
Definition: typetraits.hh:65
Traits for type conversions and type information.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jun 2, 23:00, 2026)