dune-common  2.11
mdspan.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_MDSPAN_HH
6 #define DUNE_COMMON_STD_MDSPAN_HH
7 
8 #include <array>
9 #include <span>
10 #include <type_traits>
11 #include <utility>
12 #if __has_include(<version>)
13  #include <version>
14 #endif
15 
16 #include <dune/common/indices.hh>
21 
22 namespace Dune::Std {
23 
62 template <class Element, class Extents, class LayoutPolicy = Std::layout_right,
63  class AccessorPolicy = Std::default_accessor<Element>>
64 class mdspan
65 {
66  static_assert(std::is_object_v<Element>);
67  static_assert(!std::is_abstract_v<Element>);
68  static_assert(!std::is_array_v<Element>);
69  static_assert(std::is_same_v<Element, typename AccessorPolicy::element_type>);
70 
71 public:
72  using element_type = Element;
73  using extents_type = Extents;
74  using layout_type = LayoutPolicy;
75  using accessor_type = AccessorPolicy;
76 
77  using value_type = std::remove_cv_t<Element>;
78  using mapping_type = typename layout_type::template mapping<extents_type>;
79  using index_type = typename extents_type::index_type;
80  using size_type = typename extents_type::size_type;
81  using rank_type = typename extents_type::rank_type;
82  using data_handle_type = typename accessor_type::data_handle_type;
83  using reference = typename accessor_type::reference;
84 
85 private:
86  // [mdspan.layout.reqmts]
87  static_assert(std::is_nothrow_move_constructible_v<mapping_type>);
88  static_assert(std::is_nothrow_move_assignable_v<mapping_type>);
89  static_assert(std::is_nothrow_swappable_v<mapping_type>);
90 
91  // [mdspan.accessor.reqmts]
92  static_assert(std::is_nothrow_move_constructible_v<accessor_type>);
93  static_assert(std::is_nothrow_move_assignable_v<accessor_type>);
94  static_assert(std::is_nothrow_swappable_v<accessor_type>);
95 
96 public:
99 
101  template <class E = extents_type, class D = data_handle_type, class M = mapping_type, class A = accessor_type,
102  std::enable_if_t<(E::rank_dynamic() > 0), int> = 0,
103  std::enable_if_t<std::is_default_constructible_v<D>, int> = 0,
104  std::enable_if_t<std::is_default_constructible_v<M>, int> = 0,
105  std::enable_if_t<std::is_default_constructible_v<A>, int> = 0>
106  constexpr mdspan ()
107  : data_handle_{}
108  , mapping_{}
109  , accessor_{}
110  {}
111 
113  template <class... IndexTypes,
114  class E = extents_type, class M = mapping_type, class A = accessor_type,
115  std::enable_if_t<(sizeof...(IndexTypes) == E::rank() || sizeof...(IndexTypes) == E::rank_dynamic()), int> = 0,
116  std::enable_if_t<(... && std::is_convertible_v<IndexTypes, index_type>), int> = 0,
117  std::enable_if_t<(... && std::is_nothrow_constructible_v<index_type, IndexTypes>), int> = 0,
118  std::enable_if_t<std::is_constructible_v<M, E>, int> = 0,
119  std::enable_if_t<std::is_default_constructible_v<A>, int> = 0>
120  explicit constexpr mdspan (data_handle_type p, IndexTypes... exts)
121  : mdspan(std::move(p), extents_type(index_type(std::move(exts))...))
122  {}
123 
125  template <class IndexType, std::size_t N,
126  std::enable_if_t<std::is_convertible_v<const IndexType&, index_type>, int> = 0,
127  std::enable_if_t<std::is_nothrow_constructible_v<index_type,const IndexType&>, int> = 0,
128  std::enable_if_t<(N == extents_type::rank_dynamic() || N == extents_type::rank()), int> = 0>
129  #if __cpp_conditional_explicit >= 201806L
130  explicit(N != extents_type::rank_dynamic())
131  #endif
132  constexpr mdspan (data_handle_type p, std::span<IndexType,N> exts)
133  : mdspan(std::move(p), extents_type(exts))
134  {}
135 
137  template <class IndexType, std::size_t N,
138  std::enable_if_t<std::is_convertible_v<IndexType, index_type>, int> = 0,
139  std::enable_if_t<(N == extents_type::rank_dynamic() || N == extents_type::rank()), int> = 0>
140  #if __cpp_conditional_explicit >= 201806L
141  explicit(N != extents_type::rank_dynamic())
142  #endif
143  constexpr mdspan (data_handle_type p, const std::array<IndexType,N>& exts)
144  : mdspan(std::move(p), extents_type(exts))
145  {}
146 
148  template <class M = mapping_type,
149  std::enable_if_t<std::is_constructible_v<M, const extents_type&>, int> = 0>
150  constexpr mdspan (data_handle_type p, const extents_type& e)
151  : mdspan(std::move(p), mapping_type(e))
152  {}
153 
155  template <class A = accessor_type,
156  std::enable_if_t<std::is_default_constructible_v<A>, int> = 0>
157  constexpr mdspan (data_handle_type p, const mapping_type& m)
158  : mdspan(std::move(p), m, accessor_type{})
159  {}
160 
162  constexpr mdspan (data_handle_type p, const mapping_type& m, const accessor_type& a)
163  : data_handle_(std::move(p))
164  , mapping_(m)
165  , accessor_(a)
166  {}
167 
168 
170  template <class OtherElementType, class OtherExtends, class OtherLayoutPolicy, class OtherAccessor,
171  std::enable_if_t<std::is_constructible_v<mapping_type, const typename OtherLayoutPolicy::template mapping<OtherExtends>&>, int> = 0,
172  std::enable_if_t<std::is_constructible_v<accessor_type, const OtherAccessor&>, int> = 0>
173  #if __cpp_conditional_explicit >= 201806L
174  explicit(!std::is_convertible_v<const typename OtherLayoutPolicy::template mapping<OtherExtends>&, mapping_type>
175  || !std::is_convertible_v<const OtherAccessor&, accessor_type>)
176  #endif
179  accessor_type(other.accessor()))
180  {}
181 
183 
184 
187 
192  template <class... Indices,
193  std::enable_if_t<(sizeof...(Indices) == extents_type::rank()), int> = 0,
194  std::enable_if_t<(... && std::is_convertible_v<Indices, index_type>), int> = 0,
195  std::enable_if_t<(... && std::is_nothrow_constructible_v<index_type,Indices>), int> = 0>
196  constexpr reference operator() (Indices... indices) const
197  {
198  return accessor_.access(data_handle_, mapping_(index_type(std::move(indices))...));
199  }
200 
201 #if __cpp_multidimensional_subscript >= 202110L
202 
204  template <class... Indices,
205  std::enable_if_t<(sizeof...(Indices) == extents_type::rank()), int> = 0,
206  std::enable_if_t<(... && std::is_convertible_v<Indices, index_type>), int> = 0,
207  std::enable_if_t<(... && std::is_nothrow_constructible_v<index_type,Indices>), int> = 0>
208  constexpr reference operator[] (Indices... indices) const
209  {
210  return accessor_.access(data_handle_, mapping_(index_type(std::move(indices))...));
211  }
212 
213 #else // __cpp_multidimensional_subscript
214 
217  template <class Index, class E = extents_type,
218  std::enable_if_t<std::is_convertible_v<Index,index_type>, int> = 0,
219  std::enable_if_t<(E::rank() == 1), int> = 0>
220  constexpr reference operator[] (Index index) const
221  {
222  return accessor_.access(data_handle_, mapping_(index_type(std::move(index))));
223  }
224 
225 #endif // __cpp_multidimensional_subscript
226 
228  template <class Index,
229  std::enable_if_t<std::is_convertible_v<const Index&, index_type>, int> = 0,
230  std::enable_if_t<std::is_nothrow_constructible_v<index_type, const Index&>, int> = 0>
231  constexpr reference operator[] (std::span<Index,extents_type::rank()> indices) const
232  {
233  return unpackIntegerSequence([&](auto... ii) -> reference {
234  return accessor_.access(data_handle_, mapping_(index_type(indices[ii])...)); },
235  std::make_index_sequence<extents_type::rank()>{});
236  }
237 
239  template <class Index,
240  std::enable_if_t<std::is_convertible_v<const Index&, index_type>, int> = 0,
241  std::enable_if_t<std::is_nothrow_constructible_v<index_type, const Index&>, int> = 0>
242  constexpr reference operator[] (const std::array<Index,extents_type::rank()>& indices) const
243  {
244  return std::apply([&](auto... ii) -> reference {
245  return accessor_.access(data_handle_, mapping_(index_type(ii)...)); }, indices);
246  }
247 
249 
251  constexpr const extents_type& extents () const noexcept { return mapping_.extents(); }
252 
254  constexpr const mapping_type& mapping () const noexcept { return mapping_; }
255 
257  constexpr const accessor_type& accessor () const noexcept { return accessor_; }
258 
260  constexpr const data_handle_type& data_handle () const noexcept { return data_handle_; };
261 
262 
265 
267  static constexpr rank_type rank () noexcept { return extents_type::rank(); }
268 
270  static constexpr rank_type rank_dynamic () noexcept { return extents_type::rank_dynamic(); }
271 
273  static constexpr std::size_t static_extent (rank_type r) noexcept { return extents_type::static_extent(r); }
274 
276  constexpr index_type extent (rank_type r) const noexcept { return extents().extent(r); }
277 
279  constexpr size_type size () const noexcept
280  {
281  size_type s = 1;
282  for (rank_type r = 0; r < rank(); ++r)
283  s *= extent(r);
284  return s;
285  }
286 
288  [[nodiscard]] constexpr bool empty () const noexcept { return size() == 0; }
289 
291 
292 
294  static constexpr bool is_always_unique () { return mapping_type::is_always_unique(); }
295 
297  static constexpr bool is_always_exhaustive () { return mapping_type::is_always_exhaustive(); }
298 
300  static constexpr bool is_always_strided () { return mapping_type::is_always_strided(); }
301 
303  constexpr bool is_unique () const { return mapping_.is_unique(); }
304 
307  constexpr bool is_exhaustive () const { return mapping_.is_exhaustive(); }
308 
314  constexpr bool is_strided () const { return mapping_.is_strided(); }
315 
317  constexpr index_type stride (rank_type r) const { return mapping_.stride(r); }
318 
319 
321  friend constexpr void swap (mdspan& x, mdspan& y) noexcept
322  {
323  using std::swap;
324  swap(x.data_handle_, y.data_handle_);
325  swap(x.mapping_, y.mapping_);
326  swap(x.accessor_, y.accessor_);
327  }
328 
329 
330 private:
331  data_handle_type data_handle_;
334 };
335 
336 // deduction guides
337 // @{
338 
339 template <class CArray,
340  std::enable_if_t<std::is_array_v<CArray>, int> = 0,
341  std::enable_if_t<(std::rank_v<CArray> == 1), int> = 0>
342 mdspan (CArray&)
343  -> mdspan<std::remove_all_extents_t<CArray>, Std::extents<std::size_t, std::extent_v<CArray,0>>>;
344 
345 template <class Pointer,
346  std::enable_if_t<std::is_pointer_v<std::remove_reference_t<Pointer>>, int> = 0>
347 mdspan (Pointer&&)
348  -> mdspan<std::remove_pointer_t<std::remove_reference_t<Pointer>>, Std::extents<std::size_t>>;
349 
350 template <class ElementType, class... II,
351  std::enable_if_t<(... && std::is_convertible_v<II,std::size_t>), int> = 0,
352  std::enable_if_t<(sizeof...(II) > 0), int> = 0>
353 mdspan (ElementType*, II...)
354  -> mdspan<ElementType, Std::dextents<std::size_t, sizeof...(II)>>;
355 
356 template <class ElementType, class SizeType, std::size_t N>
357 mdspan (ElementType*, std::span<SizeType,N>)
358  -> mdspan<ElementType, Std::dextents<std::size_t, N>>;
359 
360 template <class ElementType, class SizeType, std::size_t N>
361 mdspan (ElementType*, const std::array<SizeType,N>&)
362  -> mdspan<ElementType, Std::dextents<std::size_t, N>>;
363 
364 template <class ElementType, class IndexType, std::size_t... exts>
365 mdspan (ElementType*, const Std::extents<IndexType,exts...>&)
366  -> mdspan<ElementType, Std::extents<IndexType,exts...>>;
367 
368 template <class ElementType, class Mapping,
369  class Extents = typename Mapping::extents_type,
370  class Layout = typename Mapping::layout_type>
371 mdspan (ElementType*, const Mapping&)
372  -> mdspan<ElementType, Extents, Layout>;
373 
374 template <class Mapping, class Accessor,
375  class DataHandle = typename Accessor::data_handle_type,
376  class Element = typename Accessor::element_type,
377  class Extents = typename Mapping::extents_type,
378  class Layout = typename Mapping::layout_type>
379 mdspan (const DataHandle&, const Mapping&, const Accessor&)
380  -> mdspan<Element, Extents, Layout, Accessor>;
381 
382 // @}
383 
384 } // end namespace Dune::Std
385 
386 #endif // DUNE_COMMON_STD_MDSPAN_HH
Namespace for features backported from new C++ standards.
Definition: algorithm.hh:19
AccessorPolicy accessor_type
Definition: mdspan.hh:75
constexpr bool empty() const noexcept
Checks if the size of the index space is zero.
Definition: mdspan.hh:288
static constexpr bool is_always_strided()
Return true only if for every rank index r of extents there exists an integer sr such that...
Definition: mdspan.hh:300
A multi-dimensional non-owning array view.
Definition: mdspan.hh:64
constexpr const extents_type & extents() const noexcept
Number of elements in all dimensions of the tensor,.
Definition: mdspan.hh:251
friend constexpr void swap(mdspan &x, mdspan &y) noexcept
Overloads the std::swap algorithm for std::mdspan. Exchanges the state of x with that of y...
Definition: mdspan.hh:321
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
Element element_type
Definition: mdspan.hh:72
#define DUNE_NO_UNIQUE_ADDRESS
Definition: no_unique_address.hh:24
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
typename extents_type::size_type size_type
Definition: mdspan.hh:80
constexpr mdspan()
Default constructor value-initializes all members.
Definition: mdspan.hh:106
constexpr bool is_strided() const
Return true only if for every rank index r of extents there exists an integer sr such that...
Definition: mdspan.hh:314
LayoutPolicy layout_type
Definition: mdspan.hh:74
typename accessor_type::data_handle_type data_handle_type
Definition: mdspan.hh:82
Multidimensional index space with dynamic and static extents.This class template represents a multidi...
Definition: extents.hh:54
typename layout_type::template mapping< extents_type > mapping_type
Definition: mdspan.hh:78
constexpr bool is_unique() const
Return true only if for every i and j where (i != j || ...) => mapping(i...) != mapping(j...).
Definition: mdspan.hh:303
constexpr mdspan(data_handle_type p, const mapping_type &m)
Construct from the pointer to the data of the tensor and an index mapping.
Definition: mdspan.hh:157
constexpr reference operator[](Index index) const
Access specified element at position [i0] For a rank one mdspan, the operator[i] is added to support ...
Definition: mdspan.hh:220
static constexpr rank_type rank() noexcept
Number of dimensions of the tensor.
Definition: mdspan.hh:267
static constexpr bool is_always_unique()
Return true only if for every i and j where (i != j || ...) => mapping(i...) != mapping(j...).
Definition: mdspan.hh:294
constexpr index_type stride(rank_type r) const
The stride along the specified dimension.
Definition: mdspan.hh:317
static constexpr bool is_always_exhaustive()
Return true only if for all k in the range [0, mapping.required_span_size() ) there exists an i such ...
Definition: mdspan.hh:297
constexpr size_type size() const noexcept
The number of elements accessible by this multi-dimensional span.
Definition: mdspan.hh:279
typename extents_type::index_type index_type
Definition: mdspan.hh:79
constexpr mdspan(data_handle_type p, const mapping_type &m, const accessor_type &a)
Construct from the pointer to the data of the tensor, an index mapping, and an accessor.
Definition: mdspan.hh:162
static constexpr std::size_t static_extent(rank_type r) noexcept
Number of elements in the r&#39;th dimension of the tensor.
Definition: mdspan.hh:273
constexpr const accessor_type & accessor() const noexcept
The accessor policy object.
Definition: mdspan.hh:257
constexpr const mapping_type & mapping() const noexcept
Index mapping of a layout policy.
Definition: mdspan.hh:254
constexpr const data_handle_type & data_handle() const noexcept
The pointer to the underlying flat sequence.
Definition: mdspan.hh:260
typename accessor_type::reference reference
Definition: mdspan.hh:83
mdspan(CArray &) -> mdspan< std::remove_all_extents_t< CArray >, Std::extents< std::size_t, std::extent_v< CArray, 0 >>>
constexpr bool is_exhaustive() const
Return true only if for all k in the range [0, mapping.required_span_size() ) there exists an i such ...
Definition: mdspan.hh:307
Extents extents_type
Definition: mdspan.hh:73
void swap(T &v1, T &v2, bool mask)
Definition: simd.hh:472
std::remove_cv_t< Element > value_type
Definition: mdspan.hh:77
typename extents_type::rank_type rank_type
Definition: mdspan.hh:81
STL namespace.
constexpr mdspan(data_handle_type p, const extents_type &e)
Construct from the pointer to the data of the tensor and its extents.
Definition: mdspan.hh:150
span(T(&)[N]) -> span< T, N >
constexpr index_type extent(rank_type r) const noexcept
Number of elements in the r&#39;th dimension of the tensor.
Definition: mdspan.hh:276
static constexpr rank_type rank_dynamic() noexcept
Number of dimensions of the tensor.
Definition: mdspan.hh:270