DUNE PDELab (git)

extents.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 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
5#ifndef DUNE_COMMON_STD_EXTENTS_HH
6#define DUNE_COMMON_STD_EXTENTS_HH
7
8#include <array>
9#include <cassert>
10#include <limits>
11#include <type_traits>
12#if __has_include(<version>)
13 #include <version>
14#endif
15
16#include <dune/common/indices.hh>
17#include <dune/common/std/span.hh>
18#include <dune/common/std/impl/fwd_layouts.hh>
19
20namespace Dune::Std {
21namespace Impl {
22
23template <class IndexType, std::size_t n>
24struct DynamicExtentsArray
25{
26 using type = std::array<IndexType,n>;
27};
28
29template <class IndexType>
30struct DynamicExtentsArray<IndexType,0>
31{
32 // empty type with minimal array-like interface
33 struct type {
34 IndexType operator[](std::size_t /*i*/) const { return 0; }
35 };
36};
37
38} // end namespace Impl
39
40
52template <class IndexType, std::size_t... exts>
54{
55 static_assert(std::is_integral_v<IndexType>);
56
57private:
58 static constexpr std::size_t rank_ = sizeof...(exts);
59 static constexpr std::size_t rank_dynamic_ = ((exts == Std::dynamic_extent) + ... + 0);
60
61 // this type is used internally to extract the static extents by index
62 using array_type = std::array<std::size_t,rank_>;
63
64 // store at position i how many extents in {exts[0],...,exts[i]} are dynamic_extent
65 static constexpr std::array<std::size_t,rank_+1> make_dynamic_index()
66 {
67 std::array<std::size_t,rank_+1> di{{}};
68 for (std::size_t i = 0; i < rank_; ++i)
69 di[i+1] = di[i] + (array_type{exts...}[i] == Std::dynamic_extent);
70 return di;
71 }
72
73 // An index mapping computed by `make_dynamic_index()` to get the position of a dynamic
74 // extent in {exts...} within the array dynamic_extents.
75 static constexpr std::array<std::size_t,rank_+1> dynamic_index_{make_dynamic_index()};
76
77public:
78 using rank_type = std::size_t;
79 using index_type = IndexType;
80 using size_type = std::make_unsigned_t<index_type>;
81
85
87 static constexpr rank_type rank () noexcept { return rank_; }
88
90 static constexpr rank_type rank_dynamic () noexcept { return rank_dynamic_; }
91
93 static constexpr std::size_t static_extent (rank_type r) noexcept
94 {
95 assert(rank() > 0 && r < rank());
96 return array_type{exts...}[r];
97 }
98
100 constexpr index_type extent (rank_type r) const noexcept
101 {
102 assert(rank() > 0 && r < rank());
103 if (std::size_t e = static_extent(r); e != Std::dynamic_extent)
104 return index_type(e);
105 else
106 return dynamic_extents_[dynamic_index_[r]];
107 }
108
110
111public:
114
116 constexpr extents () noexcept = default;
117
120 template <class... IndexTypes,
121 std::enable_if_t<(... && std::is_convertible_v<IndexTypes,index_type>), int> = 0,
122 std::enable_if_t<(sizeof...(IndexTypes) == rank() || sizeof...(IndexTypes) == rank_dynamic()), int> = 0,
123 std::enable_if_t<(... && std::is_nothrow_constructible_v<index_type, IndexTypes>), int> = 0>
124 constexpr explicit extents (IndexTypes... e) noexcept
125 {
126 init_dynamic_extents<sizeof...(e)>(std::array<index_type,sizeof...(e)>{index_type(e)...});
127 }
128
131 template <class I, std::size_t N,
132 std::enable_if_t<std::is_convertible_v<I, index_type>, int> = 0,
133 std::enable_if_t<(N == rank() || N == rank_dynamic()), int> = 0>
134 #if __cpp_conditional_explicit >= 201806L
135 explicit(N != rank_dynamic())
136 #endif
137 constexpr extents (const std::array<I,N>& e) noexcept
138 {
139 init_dynamic_extents<N>(e);
140 }
141
144 template <class I, std::size_t N,
145 std::enable_if_t<std::is_convertible_v<I, index_type>, int> = 0,
146 std::enable_if_t<(N == rank() || N == rank_dynamic()), int> = 0,
147 std::enable_if_t<std::is_nothrow_constructible_v<index_type, const I&>, int> = 0>
148 #if __cpp_conditional_explicit >= 201806L
149 explicit(N != rank_dynamic())
150 #endif
151 constexpr extents (Std::span<I,N> e) noexcept
152 {
153 init_dynamic_extents<N>(e);
154 }
155
156 template <class I, std::size_t... e,
157 std::enable_if_t<(sizeof...(e) == rank()), int> = 0,
158 std::enable_if_t<((e == Std::dynamic_extent || exts == Std::dynamic_extent || e == exts) &&...), int> = 0>
159 #if __cpp_conditional_explicit >= 201806L
160 explicit(
161 (( (exts != Std::dynamic_extent) && (e == Std::dynamic_extent)) || ... ) ||
163 #endif
164 constexpr extents (const extents<I,e...>& other) noexcept
165 {
166 init_dynamic_extents<sizeof...(e)>(as_array(other));
167 }
168
170
171
173 template <class OtherIndexType, std::size_t... otherExts>
174 friend constexpr bool operator== (const extents& a, const extents<OtherIndexType, otherExts...>& b) noexcept
175 {
176 if (a.rank() != b.rank())
177 return false;
178 using I = std::common_type_t<index_type, OtherIndexType>;
179 for (rank_type i = 0; i < rank(); ++i)
180 if (I(a.extent(i)) != I(b.extent(i)))
181 return false;
182 return true;
183 }
184
185private:
186#ifndef DOXYGEN
187 // The product of all extents
188 constexpr size_type product () const noexcept
189 {
190 size_type prod = 1;
191 for (rank_type i = 0; i < rank(); ++i)
192 prod *= extent(i);
193 return prod;
194 }
195
196 // A representation of all extents as an array
197 template <class OtherIndexType, std::size_t... otherExts>
198 static constexpr std::array<index_type,sizeof...(otherExts)>
199 as_array (const Std::extents<OtherIndexType,otherExts...>& e) noexcept
200 {
201 return unpackIntegerSequence([&](auto... ii) {
202 return std::array<index_type,sizeof...(otherExts)>{index_type(e.extent(ii))...}; },
203 std::make_index_sequence<sizeof...(otherExts)>{});
204 }
205
206 // Copy only the dynamic extents from the container `e` into the `dynamic_extents_` storage
207 template <std::size_t N, class Container>
208 constexpr void init_dynamic_extents (const Container& e) noexcept
209 {
210 if constexpr(rank_dynamic() > 0) {
211 if constexpr(N == rank_dynamic()) {
212 assert(e.size() == rank_dynamic());
213 for (rank_type i = 0; i < rank_dynamic(); ++i)
214 dynamic_extents_[i] = e[i];
215 } else {
216 assert(e.size() == rank());
217 for (rank_type i = 0, j = 0; i < rank(); ++i) {
219 dynamic_extents_[j++] = e[i];
220 }
221 }
222 }
223 }
224#endif // DOXYGEN
225
226private:
227 using dynamic_extents_type = typename Impl::DynamicExtentsArray<index_type,rank_dynamic()>::type;
228 [[no_unique_address]] dynamic_extents_type dynamic_extents_;
229
230 template <class, std::size_t...> friend class extents;
231 friend struct layout_left;
232 friend struct layout_right;
233 friend struct layout_stride;
234};
235
236
237namespace Impl {
238
239template <class IndexType, class Seq>
240struct DExtentsImpl;
241
242template <class IndexType, std::size_t... I>
243struct DExtentsImpl<IndexType, std::integer_sequence<std::size_t,I...>>
244{
245 template <std::size_t>
246 using dynamic = std::integral_constant<std::size_t,Std::dynamic_extent>;
247 using type = Std::extents<IndexType, dynamic<I>::value...>;
248};
249
250} // end namespace Impl
251
252
258template <class IndexType, std::size_t R>
259using dextents = typename Impl::DExtentsImpl<IndexType, std::make_integer_sequence<std::size_t,R>>::type;
260
261} // end namespace Dune::Std
262
263#endif // DUNE_COMMON_STD_EXTENTS_HH
Multidimensional index space with dynamic and static extents.
Definition: extents.hh:54
static constexpr rank_type rank_dynamic() noexcept
The number of dimensions with dynamic extent.
Definition: extents.hh:90
constexpr extents() noexcept=default
The default constructor requires that all exts are not Std::dynamic_extent.
static constexpr rank_type rank() noexcept
The total number of dimensions.
Definition: extents.hh:87
friend constexpr bool operator==(const extents &a, const extents< OtherIndexType, otherExts... > &b) noexcept
Compare two extents by their rank and all individual extents.
Definition: extents.hh:174
static constexpr std::size_t static_extent(rank_type r) noexcept
Return the static extent of dimension r or Std::dynamic_extent
Definition: extents.hh:93
constexpr index_type extent(rank_type r) const noexcept
Return the extent of dimension i
Definition: extents.hh:100
A contiguous sequence of elements with static or dynamic extent.
Definition: span.hh:126
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
typename Impl::DExtentsImpl< IndexType, std::make_integer_sequence< std::size_t, R > >::type dextents
Alias of extents of given rank R and purely dynamic extents. See [mdspan.extents.dextents].
Definition: extents.hh:259
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
Namespace for features backported from new C++ standards.
Definition: default_accessor.hh:10
constexpr std::size_t dynamic_extent
A constant of type std::size_t that is used to differentiate std::span of static and dynamic extent.
Definition: span.hh:26
STL namespace.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)