Dune Core Modules (unstable)

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/no_unique_address.hh>
18#include <dune/common/std/span.hh>
19#include <dune/common/std/impl/fwd_layouts.hh>
20
21namespace Dune::Std {
22namespace Impl {
23
24template <class IndexType, std::size_t n>
25struct DynamicExtentsArray
26{
27 using type = std::array<IndexType,n>;
28};
29
30template <class IndexType>
31struct DynamicExtentsArray<IndexType,0>
32{
33 // empty type with minimal array-like interface
34 struct type {
35 IndexType operator[](std::size_t /*i*/) const { return 0; }
36 };
37};
38
39} // end namespace Impl
40
41
53template <class IndexType, std::size_t... exts>
55{
56 static_assert(std::is_integral_v<IndexType>);
57
58private:
59 static constexpr std::size_t rank_ = sizeof...(exts);
60 static constexpr std::size_t rank_dynamic_ = ((exts == Std::dynamic_extent) + ... + 0);
61
62 // this type is used internally to extract the static extents by index
63 using array_type = std::array<std::size_t,rank_>;
64
65 // store at position i how many extents in {exts[0],...,exts[i]} are dynamic_extent
66 static constexpr std::array<std::size_t,rank_+1> make_dynamic_index()
67 {
68 std::array<std::size_t,rank_+1> di{{}};
69 for (std::size_t i = 0; i < rank_; ++i)
70 di[i+1] = di[i] + (array_type{exts...}[i] == Std::dynamic_extent);
71 return di;
72 }
73
74 // An index mapping computed by `make_dynamic_index()` to get the position of a dynamic
75 // extent in {exts...} within the array dynamic_extents.
76 static constexpr std::array<std::size_t,rank_+1> dynamic_index_{make_dynamic_index()};
77
78public:
79 using rank_type = std::size_t;
80 using index_type = IndexType;
81 using size_type = std::make_unsigned_t<index_type>;
82
86
88 static constexpr rank_type rank () noexcept { return rank_; }
89
91 static constexpr rank_type rank_dynamic () noexcept { return rank_dynamic_; }
92
94 static constexpr std::size_t static_extent (rank_type r) noexcept
95 {
96 assert(rank() > 0 && r < rank());
97 return array_type{exts...}[r];
98 }
99
101 constexpr index_type extent (rank_type r) const noexcept
102 {
103 assert(rank() > 0 && r < rank());
104 if (std::size_t e = static_extent(r); e != Std::dynamic_extent)
105 return index_type(e);
106 else
107 return dynamic_extents_[dynamic_index_[r]];
108 }
109
111
112public:
115
117 constexpr extents () noexcept = default;
118
121 template <class... IndexTypes,
122 std::enable_if_t<(... && std::is_convertible_v<IndexTypes,index_type>), int> = 0,
123 std::enable_if_t<(sizeof...(IndexTypes) == rank() || sizeof...(IndexTypes) == rank_dynamic()), int> = 0,
124 std::enable_if_t<(... && std::is_nothrow_constructible_v<index_type, IndexTypes>), int> = 0>
125 constexpr explicit extents (IndexTypes... e) noexcept
126 {
127 init_dynamic_extents<sizeof...(e)>(std::array<index_type,sizeof...(e)>{index_type(e)...});
128 }
129
132 template <class I, std::size_t N,
133 std::enable_if_t<std::is_convertible_v<I, index_type>, int> = 0,
134 std::enable_if_t<(N == rank() || N == rank_dynamic()), int> = 0>
135 #if __cpp_conditional_explicit >= 201806L
136 explicit(N != rank_dynamic())
137 #endif
138 constexpr extents (const std::array<I,N>& e) noexcept
139 {
140 init_dynamic_extents<N>(e);
141 }
142
145 template <class I, std::size_t N,
146 std::enable_if_t<std::is_convertible_v<I, index_type>, int> = 0,
147 std::enable_if_t<(N == rank() || N == rank_dynamic()), int> = 0,
148 std::enable_if_t<std::is_nothrow_constructible_v<index_type, const I&>, int> = 0>
149 #if __cpp_conditional_explicit >= 201806L
150 explicit(N != rank_dynamic())
151 #endif
152 constexpr extents (Std::span<I,N> e) noexcept
153 {
154 init_dynamic_extents<N>(e);
155 }
156
157 template <class I, std::size_t... e,
158 std::enable_if_t<(sizeof...(e) == rank()), int> = 0,
159 std::enable_if_t<((e == Std::dynamic_extent || exts == Std::dynamic_extent || e == exts) &&...), int> = 0>
160 #if __cpp_conditional_explicit >= 201806L
161 explicit(
162 (( (exts != Std::dynamic_extent) && (e == Std::dynamic_extent)) || ... ) ||
164 #endif
165 constexpr extents (const extents<I,e...>& other) noexcept
166 {
167 init_dynamic_extents<sizeof...(e)>(as_array(other));
168 }
169
171
172
174 template <class OtherIndexType, std::size_t... otherExts>
175 friend constexpr bool operator== (const extents& a, const extents<OtherIndexType, otherExts...>& b) noexcept
176 {
177 if (a.rank() != b.rank())
178 return false;
179 using I = std::common_type_t<index_type, OtherIndexType>;
180 for (rank_type i = 0; i < rank(); ++i)
181 if (I(a.extent(i)) != I(b.extent(i)))
182 return false;
183 return true;
184 }
185
186private:
187#ifndef DOXYGEN
188 // The product of all extents
189 constexpr size_type product () const noexcept
190 {
191 size_type prod = 1;
192 for (rank_type i = 0; i < rank(); ++i)
193 prod *= extent(i);
194 return prod;
195 }
196
197 // A representation of all extents as an array
198 template <class OtherIndexType, std::size_t... otherExts>
199 static constexpr std::array<index_type,sizeof...(otherExts)>
200 as_array (const Std::extents<OtherIndexType,otherExts...>& e) noexcept
201 {
202 return unpackIntegerSequence([&](auto... ii) {
203 return std::array<index_type,sizeof...(otherExts)>{index_type(e.extent(ii))...}; },
204 std::make_index_sequence<sizeof...(otherExts)>{});
205 }
206
207 // Copy only the dynamic extents from the container `e` into the `dynamic_extents_` storage
208 template <std::size_t N, class Container>
209 constexpr void init_dynamic_extents (const Container& e) noexcept
210 {
211 if constexpr(rank_dynamic() > 0) {
212 if constexpr(N == rank_dynamic()) {
213 assert(e.size() == rank_dynamic());
214 for (rank_type i = 0; i < rank_dynamic(); ++i)
215 dynamic_extents_[i] = e[i];
216 } else {
217 assert(e.size() == rank());
218 for (rank_type i = 0, j = 0; i < rank(); ++i) {
220 dynamic_extents_[j++] = e[i];
221 }
222 }
223 }
224 }
225#endif // DOXYGEN
226
227private:
228 using dynamic_extents_type = typename Impl::DynamicExtentsArray<index_type,rank_dynamic()>::type;
229 DUNE_NO_UNIQUE_ADDRESS dynamic_extents_type dynamic_extents_;
230
231 template <class, std::size_t...> friend class extents;
232 friend struct layout_left;
233 friend struct layout_right;
234 friend struct layout_stride;
235};
236
237
238namespace Impl {
239
240template <class IndexType, class Seq>
241struct DExtentsImpl;
242
243template <class IndexType, std::size_t... I>
244struct DExtentsImpl<IndexType, std::integer_sequence<std::size_t,I...>>
245{
246 using type = Std::extents<IndexType, (void(I), Std::dynamic_extent)...>;
247};
248
249} // end namespace Impl
250
251
257template <class IndexType, std::size_t R>
258using dextents = typename Impl::DExtentsImpl<IndexType, std::make_integer_sequence<std::size_t,R>>::type;
259
260} // end namespace Dune::Std
261
262#endif // DUNE_COMMON_STD_EXTENTS_HH
Multidimensional index space with dynamic and static extents.
Definition: extents.hh:55
static constexpr rank_type rank_dynamic() noexcept
The number of dimensions with dynamic extent.
Definition: extents.hh:91
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:88
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:175
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:94
constexpr index_type extent(rank_type r) const noexcept
Return the extent of dimension i
Definition: extents.hh:101
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:258
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 (Dec 21, 23:30, 2024)