Dune Core Modules (unstable)

layout_stride.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_LAYOUT_STRIDE_HH
6#define DUNE_COMMON_STD_LAYOUT_STRIDE_HH
7
8#include <array>
9#include <type_traits>
10
11#include <dune/common/indices.hh>
12#include <dune/common/std/no_unique_address.hh>
13#include <dune/common/std/impl/fwd_layouts.hh>
14
15namespace Dune::Std {
16
18template <class Extents>
20{
21 template <class> friend class mapping;
22 static constexpr typename Extents::rank_type rank_ = Extents::rank();
23
24public:
25 using extents_type = Extents;
26 using index_type = typename extents_type::index_type;
27 using size_type = typename extents_type::size_type;
28 using rank_type = typename extents_type::rank_type;
30
31private:
32 using strides_type = std::array<index_type,rank_>;
33
34public:
35
37 constexpr mapping () noexcept
38 : mapping(layout_right::template mapping<extents_type>{})
39 {}
40
42 constexpr mapping (const mapping&) noexcept = default;
43
45 template <class OtherIndexType,
46 std::enable_if_t<std::is_convertible_v<const OtherIndexType&, index_type>, int> = 0,
47 std::enable_if_t<std::is_nothrow_constructible_v<index_type, const OtherIndexType&>, int> = 0>
48 constexpr mapping (const extents_type& e, const std::array<OtherIndexType,rank_>& s) noexcept
49 : extents_(e)
50 , strides_{}
51 {
52 for (rank_type r = 0; r < rank_; ++r)
53 strides_[r] = s[r];
54 }
55
57 template <class OtherIndexType,
58 std::enable_if_t<std::is_convertible_v<const OtherIndexType&, index_type>, int> = 0,
59 std::enable_if_t<std::is_nothrow_constructible_v<index_type, const OtherIndexType&>, int> = 0>
60 constexpr mapping (const extents_type& e, const span<OtherIndexType,rank_>& s) noexcept
61 : extents_(e)
62 , strides_{}
63 {
64 for (rank_type r = 0; r < rank_; ++r)
65 strides_[r] = s[r];
66 }
67
69 template <class M,
70 std::enable_if_t<(M::extents_type::rank() == extents_type::rank()), int> = 0,
71 std::enable_if_t<(M::is_always_unique()), int> = 0,
72 std::enable_if_t<(M::is_always_strided()), int> = 0,
73 decltype(std::declval<M>().extents(), bool{}) = true,
74 decltype(std::declval<M>().stride(std::declval<rank_type>()), bool{}) = true>
75 constexpr mapping (const M& m) noexcept
76 : extents_(m.extents())
77 , strides_{}
78 {
79 for (rank_type r = 0; r < rank_; ++r)
80 strides_[r] = m.stride(r);
81 }
82
84 constexpr mapping& operator= (const mapping&) noexcept = default;
85
86 constexpr const extents_type& extents () const noexcept { return extents_; }
87
89 constexpr index_type required_span_size () const noexcept
90 {
91 return size(extents_,strides_);
92 }
93
95 template <class... Indices,
96 std::enable_if_t<(sizeof...(Indices) == rank_), int> = 0,
97 std::enable_if_t<(std::is_convertible_v<Indices, index_type> && ...), int> = 0,
98 std::enable_if_t<(std::is_nothrow_constructible_v<index_type, Indices> && ...), int> = 0>
99 constexpr index_type operator() (Indices... ii) const noexcept
100 {
101 return unpackIntegerSequence([&](auto... r) {
102 return ((static_cast<index_type>(ii)*strides_[r]) + ... + 0); },
103 std::make_index_sequence<rank_>{});
104 }
105
107 constexpr index_type operator() () const noexcept
108 {
109 return 0;
110 }
111
112 static constexpr bool is_always_unique () noexcept { return true; }
113 static constexpr bool is_always_exhaustive () noexcept { return false; }
114 static constexpr bool is_always_strided () noexcept { return true; }
115
116 static constexpr bool is_unique () noexcept { return true; }
117 static constexpr bool is_strided () noexcept { return true; }
118
119 constexpr bool is_exhaustive () const noexcept
120 {
121 // Actually this could be improved. A strided layout can still be exhaustive.
122 // This test is more complicated to implement, though. See §24.7.3.4.7.4 line (5.2)
123 // in the C++ standard document N4971
124 return extents_type::rank() == 0 || (required_span_size() > 0 && required_span_size() == extents().product());
125 }
126
128 constexpr const strides_type& strides () const noexcept
129 {
130 return strides_;
131 }
132
134 template <class E = extents_type,
135 std::enable_if_t<(E::rank() > 0), int> = 0>
136 constexpr index_type stride (rank_type i) const noexcept
137 {
138 return strides_[i];
139 }
140
141 template <class OtherMapping,
142 std::enable_if_t<(OtherMapping::extents_type::rank() == extents_type::rank()), int> = 0,
143 std::enable_if_t<(OtherMapping::is_always_strided()), int> = 0>
144 friend constexpr bool operator== (const mapping& a, const OtherMapping& b) noexcept
145 {
146 if (offset(b))
147 return false;
148 if constexpr(extents_type::rank() == 0)
149 return true;
150 return a.extents_ == b.extents_ && a.strides_ == b.strides_;
151 }
152
153private:
154 template <class E, class S>
155 static constexpr index_type size (const E& extents, const S& strides) noexcept
156 {
157 if constexpr (E::rank() == 0)
158 return 1;
159 else {
160 if (extents.product() == 0)
161 return 0;
162 else {
163 index_type result = 1;
164 for (rank_type r = 0; r < E::rank(); ++r)
165 result += (extents.extent(r)-1) * strides[r];
166 return result;
167 }
168 }
169 }
170
171 template <class M>
172 static constexpr size_type offset (const M& m) noexcept
173 {
174 if constexpr (M::extents_type::rank() == 0)
175 return m();
176 else {
177 if (m.required_span_size() == 0)
178 return 0;
179 else {
180 return unpackIntegerSequence([&](auto... r) {
181 return m((r,0)...); }, // map the index tuple (0,0...)
182 std::make_index_sequence<M::extents_type::rank()>{});
183 }
184 }
185 }
186
187private:
188 DUNE_NO_UNIQUE_ADDRESS extents_type extents_;
189 strides_type strides_;
190};
191
192} // end namespace Dune::Std
193
194#endif // DUNE_COMMON_STD_LAYOUT_STRIDE_HH
Multidimensional index space with dynamic and static extents.
Definition: extents.hh:55
constexpr index_type extent(rank_type r) const noexcept
Return the extent of dimension i
Definition: extents.hh:101
A layout mapping where the strides are user-defined.
Definition: layout_stride.hh:20
constexpr mapping(const extents_type &e, const span< OtherIndexType, rank_ > &s) noexcept
Construct the mapping from given extents and strides.
Definition: layout_stride.hh:60
constexpr mapping & operator=(const mapping &) noexcept=default
Copy-assignment for the mapping.
constexpr mapping() noexcept
The default construction initializes the strides from layout_right.
Definition: layout_stride.hh:37
constexpr mapping(const extents_type &e, const std::array< OtherIndexType, rank_ > &s) noexcept
Construct the mapping from given extents and strides.
Definition: layout_stride.hh:48
constexpr index_type stride(rank_type i) const noexcept
Get the single stride i
Definition: layout_stride.hh:136
constexpr index_type required_span_size() const noexcept
Return the sum 1 + (E(0)-1)*S(0) + (E(1)-1)*S(1) + ...
Definition: layout_stride.hh:89
constexpr const strides_type & strides() const noexcept
Get the array of all strides.
Definition: layout_stride.hh:128
constexpr mapping(const mapping &) noexcept=default
Copy constructor for the mapping.
constexpr index_type operator()() const noexcept
The default offset for rank-0 tensors is 0.
Definition: layout_stride.hh:107
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
Namespace for features backported from new C++ standards.
Definition: default_accessor.hh:10
A layout where the rightmost extent has stride 1, and strides increase right-to-left as the product o...
Definition: fwd_layouts.hh:30
A layout mapping where the strides are user-defined.
Definition: fwd_layouts.hh:40
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Dec 21, 23:30, 2024)