tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
extents.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2023 Tobias Hienzsch
3
4#ifndef TETL_MDSPAN_EXTENTS_HPP
5#define TETL_MDSPAN_EXTENTS_HPP
6
7#include <etl/_algorithm/transform.hpp>
8#include <etl/_array/array.hpp>
9#include <etl/_cstddef/size_t.hpp>
10#include <etl/_limits/numeric_limits.hpp>
11#include <etl/_mdspan/is_extents.hpp>
12#include <etl/_span/dynamic_extent.hpp>
13#include <etl/_span/span.hpp>
14#include <etl/_type_traits/is_convertible.hpp>
15#include <etl/_type_traits/is_nothrow_convertible.hpp>
16#include <etl/_type_traits/make_unsigned.hpp>
17#include <etl/_utility/cmp_not_equal.hpp>
18#include <etl/_utility/index_sequence.hpp>
19
20namespace etl {
21
22template <typename IndexType, etl::size_t... Extents>
23struct extents {
24 using index_type = IndexType;
25 using size_type = make_unsigned_t<IndexType>;
26 using rank_type = etl::size_t;
27
28private:
29 static constexpr auto _rank = sizeof...(Extents);
30 static constexpr auto _rank_dynamic = ((rank_type(Extents == dynamic_extent)) + ... + 0);
31 static constexpr auto _static_extents = array<etl::size_t, sizeof...(Extents)>{Extents...};
32
33 [[nodiscard]] static constexpr auto _dynamic_index(rank_type i) noexcept -> rank_type
34 {
35 return []<etl::size_t... Idxs>(etl::size_t idx, etl::index_sequence<Idxs...> /*is*/) {
36 // NOLINTNEXTLINE(bugprone-misplaced-widening-cast)
37 return static_cast<rank_type>((((Idxs < idx) ? (Extents == dynamic_extent ? 1 : 0) : 0) + ... + 0));
38 }(i, etl::make_index_sequence<rank()>{});
39 }
40
41 [[nodiscard]] static constexpr auto _dynamic_index_inv(rank_type i) noexcept -> rank_type
42 {
43 // TODO: this is horrible!
44 auto result = rank_type{};
45 for (rank_type r{0}; r < rank(); ++r) {
46 if (_dynamic_index(r) == i) {
47 result = i;
48 }
49 }
50 return result;
51 }
52
53public:
54 [[nodiscard]] static constexpr auto rank() noexcept -> rank_type
55 {
56 return sizeof...(Extents);
57 }
58
59 [[nodiscard]] static constexpr auto rank_dynamic() noexcept -> rank_type
60 {
61 return _rank_dynamic;
62 }
63
64 [[nodiscard]] static constexpr auto static_extent(rank_type i) noexcept -> etl::size_t
65 {
66 return _static_extents[i];
67 }
68
69 [[nodiscard]] constexpr auto extent(rank_type i) const noexcept -> index_type
70 {
71 if constexpr (rank_dynamic() == 0) {
72 return static_cast<index_type>(static_extent(i));
73 } else if constexpr (rank_dynamic() == rank()) {
74 return _extents[static_cast<etl::size_t>(i)];
75 } else {
76 if (auto const ext = static_extent(i); ext != dynamic_extent) {
77 return static_cast<index_type>(ext);
78 }
79 return _extents[static_cast<etl::size_t>(_dynamic_index(i))];
80 }
81 }
82
83 // [mdspan.extents.ctor], Constructors
84 constexpr extents() noexcept = default;
85
86 template <typename OtherIndexType, etl::size_t... OtherExtents>
87 requires(
88 sizeof...(OtherExtents) == rank()
89 and ((OtherExtents == dynamic_extent or Extents == dynamic_extent or OtherExtents == Extents) and ...)
90 )
91 explicit(
94 ) constexpr extents(extents<OtherIndexType, OtherExtents...> const& e) noexcept
95 {
96 if constexpr (rank_dynamic() > 0) {
97 for (rank_type i{0}; i < rank(); ++i) {
98 if (e.static_extent(i) == dynamic_extent) {
99 _extents[_dynamic_index(i)] = static_cast<IndexType>(e.extent(i));
100 }
101 }
102 }
103 }
104
105 template <typename... OtherIndexTypes>
106 requires(
107 (is_convertible_v<OtherIndexTypes, IndexType> and ...)
108 and (is_nothrow_constructible_v<IndexType, OtherIndexTypes> and ...)
109 and (sizeof...(OtherIndexTypes) == rank_dynamic() or sizeof...(OtherIndexTypes) == rank())
110 )
111 explicit constexpr extents(OtherIndexTypes... es) noexcept
112 : extents{array<IndexType, sizeof...(OtherIndexTypes)>{static_cast<IndexType>(es)...}}
113 {
114 }
115
116 template <typename OtherIndexType, etl::size_t N>
117 requires(
118 is_convertible_v<OtherIndexType const&, IndexType>
119 and is_nothrow_constructible_v<IndexType, OtherIndexType const&>
120 and (N == rank_dynamic() or N == rank())
121 )
122 explicit(N != rank_dynamic()) constexpr extents(span<OtherIndexType, N> ext) noexcept
123 {
124 if constexpr (rank_dynamic() != 0) {
125 transform(ext.begin(), ext.end(), _extents.begin(), [](auto e) { return static_cast<IndexType>(e); });
126 }
127 }
128
129 template <typename OtherIndexType, etl::size_t N>
130 requires(
131 is_convertible_v<OtherIndexType const&, IndexType>
132 and is_nothrow_constructible_v<IndexType, OtherIndexType const&>
133 and (N == rank_dynamic() or N == rank())
134 )
135 explicit(N != rank_dynamic()) constexpr extents(array<OtherIndexType, N> const& e) noexcept
136 : extents{span{e}}
137 {
138 }
139
140 template <typename OtherIndexType, etl::size_t... OtherExtents>
141 friend constexpr auto operator==(extents const& lhs, extents<OtherIndexType, OtherExtents...> const& rhs) noexcept
142 -> bool
143 {
144 if constexpr (rank() != extents<OtherIndexType, OtherExtents...>::rank()) {
145 return false;
146 } else {
147 for (auto i = rank_type(0); i < rank(); ++i) {
148 if (cmp_not_equal(lhs.extent(i), rhs.extent(i))) {
149 return false;
150 }
151 }
152 return true;
153 }
154 }
155
156 template <typename OtherIndexType>
157 [[nodiscard]] static constexpr auto index_cast(OtherIndexType&& i) noexcept -> IndexType
158 {
159 return static_cast<IndexType>(i);
160 }
161
162 [[nodiscard]] constexpr auto fwd_prod_of_extents(rank_type i) const noexcept -> size_t
163 {
164 if constexpr (rank() == 0) {
165 return 1;
166 } else {
167 auto result = size_t(1);
168 for (auto e = rank_type(0); e < i; ++e) {
169 result *= static_cast<size_t>(extent(e));
170 }
171 return result;
172 }
173 }
174
175 [[nodiscard]] constexpr auto rev_prod_of_extents(rank_type i) const noexcept -> size_t
176 {
177 auto result = size_t(1);
178 for (auto e = i + 1; e < rank(); ++e) {
179 result *= static_cast<size_t>(extent(e));
180 }
181 return result;
182 }
183
184private:
185 TETL_NO_UNIQUE_ADDRESS array<IndexType, rank_dynamic()> _extents{};
186};
187
188namespace detail {
189
190template <typename IndexType, typename Integrals>
191struct dextents_impl;
192
193template <typename IndexType, etl::size_t... Integrals>
194struct dextents_impl<IndexType, etl::index_sequence<Integrals...>> {
195 using type = extents<IndexType, ((void)Integrals, dynamic_extent)...>;
196};
197
198} // namespace detail
199
200template <typename... Integrals>
201 requires(etl::is_convertible_v<Integrals, etl::size_t> and ...)
202extents(Integrals...) -> extents<etl::size_t, etl::size_t((Integrals(), etl::dynamic_extent))...>;
203
204template <typename IndexType, etl::size_t Rank>
205using dextents = typename detail::dextents_impl<IndexType, etl::make_index_sequence<Rank>>::type;
206
207} // namespace etl
208
209#endif // TETL_MDSPAN_EXTENTS_HPP
constexpr auto dynamic_extent
etl::dynamic_extent is a constant of type etl::size_t that is used to differentiate etl::span of stat...
Definition dynamic_extent.hpp:15
Definition adjacent_find.hpp:9
extents(Integrals...) -> extents< etl::size_t, etl::size_t((Integrals(), etl::dynamic_extent))... >
A container that encapsulates fixed size arrays.
Definition array.hpp:49
Definition extents.hpp:23
static constexpr auto rank() noexcept -> rank_type
Definition extents.hpp:54
static constexpr auto static_extent(rank_type i) noexcept -> etl::size_t
Definition extents.hpp:64
static constexpr auto rank_dynamic() noexcept -> rank_type
Definition extents.hpp:59
OtherExtents const &e noexcept
Definition extents.hpp:95
constexpr extents() noexcept=default
constexpr auto extent(rank_type i) const noexcept -> index_type
Definition extents.hpp:69