dune-common  2.11
extents.hh
Go to the documentation of this file.
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 <span>
12 #include <type_traits>
13 #if __has_include(<version>)
14  #include <version>
15 #endif
16 
17 #include <dune/common/indices.hh>
20 
21 namespace Dune::Std {
22 namespace Impl {
23 
24 template <class IndexType, std::size_t n>
25 struct DynamicExtentsArray
26 {
27  using type = std::array<IndexType,n>;
28 };
29 
30 template <class IndexType>
31 struct 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 
53 template <class IndexType, std::size_t... exts>
54 class extents
55 {
56  static_assert(std::is_integral_v<IndexType>);
57 
58 private:
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 
78 public:
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 
112 public:
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 
186 private:
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 
227 private:
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 
238 namespace Impl {
239 
240 template <class IndexType, class Seq>
241 struct DExtentsImpl;
242 
243 template <class IndexType, std::size_t... I>
244 struct 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 
257 template <class IndexType, std::size_t R>
258 using 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
Namespace for features backported from new C++ standards.
Definition: algorithm.hh:19
friend struct layout_stride
Definition: extents.hh:234
std::size_t rank_type
Definition: extents.hh:79
std::make_unsigned_t< index_type > size_type
Definition: extents.hh:81
constexpr index_type extent(rank_type r) const noexcept
Return the extent of dimension i
Definition: extents.hh:101
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
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
friend class extents
Definition: extents.hh:231
#define DUNE_NO_UNIQUE_ADDRESS
Definition: no_unique_address.hh:24
constexpr extents() noexcept=default
The default constructor requires that all exts are not std::dynamic_extent.
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
friend struct layout_right
Definition: extents.hh:233
static constexpr rank_type rank_dynamic() noexcept
The number of dimensions with dynamic extent.
Definition: extents.hh:91
static constexpr rank_type rank() noexcept
The total number of dimensions.
Definition: extents.hh:88
Multidimensional index space with dynamic and static extents.This class template represents a multidi...
Definition: extents.hh:54
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
friend struct layout_left
Definition: extents.hh:232
I i
Definition: hybridmultiindex.hh:328
IndexType index_type
Definition: extents.hh:80
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 extents(const extents< I, e... > &other) noexcept
Definition: extents.hh:165
STL namespace.
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:29