Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
layout_left.hpp
Go to the documentation of this file.
1// parasoft-suppress CERT_C-EXP37-a AUTOSAR-A2_8_1-a "False positive: there is no function named '()' here. Header
2// defines layout_left types"
3
4// Copyright 2026, Toyota Motor Corporation
5//
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7
8#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_MDSPAN_LAYOUT_LEFT_HPP_
9#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_MDSPAN_LAYOUT_LEFT_HPP_
10
11// IWYU pragma: no_include "arene/base/mdspan/layout.hpp"
12
13// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
14#include "arene/base/array/array.hpp"
15#include "arene/base/constraints/constraints.hpp"
16#include "arene/base/contracts/contract.hpp"
17#include "arene/base/mdspan/detail/all_valid_submdspan_slice_types_for.hpp"
18#include "arene/base/mdspan/detail/checked_math.hpp"
19#include "arene/base/mdspan/detail/is_submdspan_layout_preserving.hpp"
20#include "arene/base/mdspan/detail/layout_common.hpp" // IWYU pragma: keep
21#include "arene/base/mdspan/detail/strided_mapping_base.hpp" // IWYU pragma: keep
22#include "arene/base/mdspan/detail/submdspan_mapping_impl.hpp"
23#include "arene/base/mdspan/submdspan_subextents_type.hpp"
24#include "arene/base/stdlib_choice/enable_if.hpp"
25#include "arene/base/stdlib_choice/is_constructible.hpp"
26#include "arene/base/stdlib_choice/is_convertible.hpp"
27#include "arene/base/stdlib_choice/move.hpp"
28// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
29
30// parasoft-begin-suppress AUTOSAR-M2_10_1-a "Similar names permitted by M2-10-1 Permit #1"
31// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
32
33namespace arene {
34namespace base {
35namespace layout_detail {
36
37/// @brief Get a set of strides with the smallest stride on the left and the largest on the right
38/// @tparam Extents The type of the extents to use, deduced from @c extents
39/// @param extents An extents object
40/// @return An array of strides; the leftmost is @c 1 and each entry is the product of the extents to its left
41/// @pre Each stride entry will fit in @c Extents::index_type without wrapping, else @c ARENE_PRECONDITION violation
42template <typename Extents, constraints<std::enable_if_t<Extents::rank() != 0U>> = nullptr>
43constexpr auto left_strides(Extents const& extents) noexcept
44 -> ::arene::base::array<typename Extents::index_type, Extents::rank()> {
45 using index_type = typename Extents::index_type;
46 using rank_type = typename Extents::rank_type;
47
48 ::arene::base::array<index_type, Extents::rank()> strides{};
49 mdspan_detail::checked_math_result<index_type> current_stride{index_type{1}};
50 strides[0U] = current_stride.value;
51 for (rank_type dim{}; dim + rank_type{1} < Extents::rank(); ++dim) {
52 current_stride = mdspan_detail::checked_multiplies<index_type>(current_stride, extents.extent(dim));
53 if (current_stride.value == index_type{}) {
54 // The standard doesn't allow strides to be 0, which can be naively computed if an extent is 0.
55 // If any extents are 0, trying to use this mapping will always go out of bounds so the value doesn't matter.
56 current_stride.value = index_type{1};
57 }
58 strides[dim + rank_type{1}] = current_stride.value;
59 }
60 ARENE_PRECONDITION(!current_stride.overflowed);
61
62 return strides;
63}
64
65/// @brief Get a set of strides with the smallest stride on the left and the largest on the right
66/// @note This special overload for <c>rank == 0</c> exists entirely to make it easier to measure test coverage.
67/// @tparam Extents The type of the extents to use, deduced from the first parameter
68/// @return An array of strides; the leftmost is @c 1 and each entry is the product of the extents to its left
69template <typename Extents, constraints<std::enable_if_t<Extents::rank() == 0U>> = nullptr>
70constexpr auto left_strides(Extents const&) noexcept
71 -> ::arene::base::array<typename Extents::index_type, Extents::rank()> {
72 return {};
73}
74
75} // namespace layout_detail
76
77// parasoft-begin-suppress AUTOSAR-A2_10_1 "Base class is inherited privately so its identifiers are not visible"
78// parasoft-begin-suppress AUTOSAR-A7_3_1-a "False positive: there is no rule A7-3-1"
79// parasoft-begin-suppress AUTOSAR-A10_2_1-b "False positive: this is not a multiple inheritance hierarchy"
80// parasoft-begin-suppress AUTOSAR-A10_2_1-a "False positive: this is not a multiple inheritance hierarchy"
81/// @brief A mapping from a logical pack of indices into a single flat physical output index
82/// @tparam The extents of the space used for this mapping; must be a specialization of @c extents
83template <class Extents>
85 private:
86 /// @brief Convenience typedef referring to the base strided mapping
88
89 public:
90 using typename base_type::extents_type;
91 using typename base_type::index_type;
92 using typename base_type::rank_type;
93 using typename base_type::size_type;
94 /// @brief The tag type of the layout used by this @c mapping
96
97 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
98 /// @brief Construct a default left-strided mapping for the given extents
99 constexpr mapping() noexcept
100 : mapping(extents_type{}) {}
101 // parasoft-end-suppress AUTOSAR-A12_1_1-a
102
103 /// @brief Construct a left-strided mapping for the given extents
104 /// @param exts The extents to use
105 /// @pre The size of the index space represented by @c exts fits within <c>index_type</c>, else @c ARENE_PRECONDITION
106 /// violation
107 // NOLINTNEXTLINE(hicpp-explicit-conversions) C++23 defines this as implicit
108 constexpr mapping(extents_type const& exts) noexcept
110
111 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
112 /// @brief Converting constructor from a mapping with a different (but compatible) @c extents_type
113 /// @note This is implicit if and only if @c OtherExtents is implicitly convertible to @c extents_type
114 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
115 /// @param other The other @c layout_left::mapping
116 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
117 /// @c ARENE_PRECONDITION violation
118 template <
119 typename OtherExtents,
121 // NOLINTNEXTLINE(hicpp-explicit-conversions) C++23 defines this as implicit
124 // parasoft-end-suppress AUTOSAR-A12_1_1-a
125
126 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
127 /// @brief Converting constructor from a mapping with a different (but compatible) @c extents_type
128 /// @note This is implicit if and only if @c OtherExtents is implicitly convertible to @c extents_type
129 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
130 /// @param other The other @c layout_left::mapping
131 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
132 /// @c ARENE_PRECONDITION violation
133 template <
134 typename OtherExtents,
138 constexpr explicit mapping(mapping<OtherExtents> const& other) noexcept
140 // parasoft-end-suppress AUTOSAR-A12_1_1-a
141
142 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
143 /// @brief Converting constructor from a @c layout_right::mapping when both have 0- or 1-dimensional extents
144 /// @note This is implicit if and only if @c OtherExtents is implicitly convertible to @c extents_type
145 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
146 /// @param other The @c layout_right::mapping
147 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
148 /// @c ARENE_PRECONDITION violation
149 template <
150 typename OtherExtents,
153 std::enable_if_t<OtherExtents::rank() <= rank_type{1U}>> = nullptr>
154 // NOLINTNEXTLINE(hicpp-explicit-conversions) C++23 defines this as implicit
157 // parasoft-end-suppress AUTOSAR-A12_1_1-a
158
159 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
160 /// @brief Converting constructor from a @c layout_right::mapping when both have 0- or 1-dimensional extents
161 /// @note This is implicit if and only if @c OtherExtents is implicitly convertible to @c extents_type
162 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
163 /// @param other The @c layout_right::mapping
164 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
165 /// @c ARENE_PRECONDITION violation
166 template <
167 typename OtherExtents,
171 std::enable_if_t<OtherExtents::rank() <= rank_type{1U}>> = nullptr>
174 // parasoft-end-suppress AUTOSAR-A12_1_1-a
175
176 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
177 /// @brief Converting constructor from a @c layout_stride::mapping with a compatible @c extents_type
178 /// @note This is implicit if and only if <c>OtherExtents::rank() == 0</c>
179 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
180 /// @param other The @c layout_stride::mapping
181 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
182 /// @c ARENE_PRECONDITION violation
183 /// @pre <c>other</c>'s strides are exactly those of a @c layout_right::mapping with its <c>extents</c>, else
184 /// @c ARENE_PRECONDITION violation
185 template <
186 typename OtherExtents,
189 std::enable_if_t<OtherExtents::rank() == rank_type{0U}>> = nullptr>
190 // NOLINTNEXTLINE(hicpp-explicit-conversions) C++23 defines this as implicit
191 constexpr mapping(layout_stride::mapping<OtherExtents> const& other) noexcept
193 // The second precondition need not be checked here, because rank-0 strides are empty and so always left-strided.
194 }
195 // parasoft-end-suppress AUTOSAR-A12_1_1-a
196
197 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: this is a delegating constructor"
198 /// @brief Converting constructor from a @c layout_stride::mapping with a compatible @c extents_type
199 /// @note This is implicit if and only if <c>OtherExtents::rank() == 0</c>
200 /// @tparam OtherExtents Type of <c>other</c>'s @c extents
201 /// @param other The @c layout_stride::mapping
202 /// @pre @c other.required_span_size() can be represented as a value of *this* type's <c>index_type</c>, else
203 /// @c ARENE_PRECONDITION violation
204 /// @pre <c>other</c>'s strides are exactly those of a @c layout_right::mapping with its <c>extents</c>, else
205 /// @c ARENE_PRECONDITION violation
206 template <
207 typename OtherExtents,
210 std::enable_if_t<(OtherExtents::rank() > rank_type{0U})>> = nullptr>
211 constexpr explicit mapping(layout_stride::mapping<OtherExtents> const& other) noexcept
213 // For coverage purposes, this enforces the 2nd precondition in a separate function that doesn't depend on Extents.
215 this->strides(),
216 other.strides()
217 );
218 }
219 // parasoft-end-suppress AUTOSAR-A12_1_1-a
220
221 using base_type::extents;
223 using base_type::stride;
224 using base_type::operator();
225
228 using base_type::is_strided;
229 using base_type::is_unique;
230
231 /// @brief Return whether or not this mapping is always exhaustive, i.e. every element is reachable using some indices
232 /// @return @c true because the mapping is always computed by a simple invertible left-strided algorithm
233 /// @note In mathematical terms this asks if the mapping is always surjective/onto.
234 static constexpr auto is_always_exhaustive() noexcept -> bool { return true; }
235
236 /// @brief Return whether or not this instance is exhaustive, i.e. every element is reachable using some indices
237 /// @return @c true if every provided stride is the product of the extents corresponding to some subset of the other
238 /// strides, otherwise @c false
239 /// @note In mathematical terms this asks if the mapping is surjective/onto.
240 static constexpr auto is_exhaustive() noexcept -> bool { return true; }
241
242 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Hidden friends permitted by A11-3-1 Permit #2 v1.0.0"
243 // parasoft-begin-suppress AUTOSAR-A13_5_5-b-2 "Mixed comparisons permitted by A13-5-5 Permit #1"
244 /// @brief Compare two left-strided mappings for equality
245 /// @tparam OtherExtents The type of the extents used by the right-hand side of the comparison
246 /// @param left An instance of @c layout_left::mapping
247 /// @param right An instance of @c layout_left::mapping<OtherExtents>
248 /// @return @c true if @c left and @c right have equal extents
249 template <
250 typename OtherExtents,
252 friend constexpr auto operator==(mapping const& left, mapping<OtherExtents> const& right) noexcept -> bool {
253 return left.extents() == right.extents();
254 }
255
256 /// @brief Compare two left-strided mappings for inequality
257 /// @tparam OtherExtents The type of the extents used by the right-hand side of the comparison
258 /// @param left An instance of @c layout_left::mapping
259 /// @param right An instance of @c layout_left::mapping<OtherExtents>
260 /// @return @c true if @c left and @c right have unequal extents
261 template <
262 typename OtherExtents,
264 friend constexpr auto operator!=(mapping const& left, mapping<OtherExtents> const& right) noexcept -> bool {
265 return !(left == right);
266 }
267 // parasoft-end-suppress AUTOSAR-A13_5_5-b-2
268 // parasoft-end-suppress AUTOSAR-A11_3_1-a
269
270 private:
271 /// @brief obtain a check_bypasser passkey to skip precondition checks on
272 /// mapping construction
273 /// @return check_bypasser value
274 ///
275 /// @note This exists as a workaround for a GCC bug where access checking for
276 /// private constructors of friend classes can be incorrectly performed in
277 /// the caller's instantiation context rather than the definition context.
278 static constexpr auto passkey() noexcept -> layout_detail::check_bypasser { return layout_detail::check_bypasser{}; }
279
280 /// @brief Access the strides of a @c mapping via the derived class rather than its private base
281 /// @param src the @c mapping to read strides from
282 /// @return @c src 's strides
283 ///
284 /// @note This exists as a workaround for a GCC bug (present on gcc8) where access checking for a
285 /// hidden friend's trailing return type incorrectly treats the mapping's private base class as
286 /// inaccessible when the friend is found via ADL through a separate SFINAE context
287 /// (e.g. @c is_invocable_v inside @c arene::base::invoke ). Routing the call through this
288 /// static member performs the access check on the derived class, which GCC handles correctly,
289 /// just like the @c passkey() workaround above.
290 static constexpr auto strides_of(mapping const& src) noexcept
292 return src.strides();
293 }
294
295 public:
296 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Hidden friends permitted by A11-3-1 Permit #2 v1.0.0"
297
298 /// @brief Compute the sub-mapping for a @c layout_left::mapping
299 /// @tparam CanonicalSliceSpecifiers types of the slice specifiers, one per dimension
300 /// @param src the source mapping to slice
301 /// @param slices the slice specifiers
302 ///
303 /// Uses @c slices to compute the sub-extents, sub-strides, and offset of the submdspan. The @c slices must be in
304 /// canonical form.
305 ///
306 /// @return A @c submdspan_mapping_result containing the sub-mapping and offset such that indexing the sub-mapping and
307 /// adding the offset recovers the corresponding index in the original mapping.
308 ///
309 /// @note Constraints <br>
310 /// * <c> sizeof...(CanonicalSliceSpecifiers) == extents_type::rank() </c>
311 /// * for each rank index @c k of @c src.extents(), @c CanonicalSliceSpecifiers...[k] is a valid submdspan slice
312 /// type for the @c k-th extent of @c extents_type
313 ///
314 /// @note Preconditions <br>
315 /// * for each rank index @c k of @c src.extents(), @c slices...[k] denotes a valid submdspan slice for the @c k-th
316 /// extent of @c src.extents()
317 ///
318 /// @note Remarks <br>
319 /// * the @c layout_left specialization of @c submdspan_mapping produces a @c layout_left::mapping if:
320 /// * for each k in the range <c> [0, SubExtents::rank() - 1) </c>, @c CanonicalSliceSpecifiers...[k] denotes @c
321 /// full_extent_t; and
322 /// * for k equal to <c> SubExtents::rank() - 1 </c>, @c CanonicalSliceSpecifiers...[k] is a unit-stride slice
323 /// type;
324 /// * Otherwise, it produces a @c layout_stride::mapping.
325 template <
331 nullptr>
356
357 // parasoft-end-suppress AUTOSAR-A11_3_1-a
358};
359// parasoft-end-suppress AUTOSAR-A2_10_1
360// parasoft-end-suppress AUTOSAR-A7_3_1-a
361// parasoft-end-suppress AUTOSAR-A10_2_1-b
362// parasoft-end-suppress AUTOSAR-A10_2_1-a
363
364/// @brief Specialization of @c is_sliceable_mapping_v indicating @c layout_left::mapping supports @c submdspan
365/// @tparam Extents Any specialization of @c arene::base::extents
366template <typename Extents>
367extern constexpr bool submdspan_detail::is_sliceable_mapping_v<layout_left::mapping<Extents>> = true;
368
369} // namespace base
370} // namespace arene
371
372// parasoft-end-suppress AUTOSAR-M2_10_1-a "Similar names permitted by M2-10-1 Permit #1"
373// parasoft-end-suppress AUTOSAR-A7_1_5-a-2
374
375#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_MDSPAN_LAYOUT_LEFT_HPP_
A mapping from a logical pack of indices into a single flat physical output index.
Definition layout_left.hpp:84
static constexpr auto is_always_exhaustive() noexcept -> bool
Return whether or not this mapping is always exhaustive, i.e. every element is reachable using some i...
Definition layout_left.hpp:234
constexpr mapping(extents_type const &exts) noexcept
Construct a left-strided mapping for the given extents.
Definition layout_left.hpp:108
constexpr mapping() noexcept
Construct a default left-strided mapping for the given extents.
Definition layout_left.hpp:99
static constexpr auto is_exhaustive() noexcept -> bool
Return whether or not this instance is exhaustive, i.e. every element is reachable using some indices...
Definition layout_left.hpp:240
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10