tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
span.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2020 Tobias Hienzsch
3
4#ifndef TETL_SPAN_SPAN_HPP
5#define TETL_SPAN_SPAN_HPP
6
7#include <etl/_config/all.hpp>
8
9#include <etl/_array/array.hpp>
10#include <etl/_array/c_array.hpp>
11#include <etl/_contracts/check.hpp>
12#include <etl/_cstddef/byte.hpp>
13#include <etl/_iterator/begin.hpp>
14#include <etl/_iterator/data.hpp>
15#include <etl/_iterator/end.hpp>
16#include <etl/_iterator/iter_reference_t.hpp>
17#include <etl/_iterator/next.hpp>
18#include <etl/_iterator/rbegin.hpp>
19#include <etl/_iterator/rend.hpp>
20#include <etl/_iterator/reverse_iterator.hpp>
21#include <etl/_iterator/size.hpp>
22#include <etl/_limits/numeric_limits.hpp>
23#include <etl/_ranges/borrowed_range.hpp>
24#include <etl/_ranges/enable_borrowed_range.hpp>
25#include <etl/_ranges/range_reference_t.hpp>
26#include <etl/_ranges/size.hpp>
27#include <etl/_ranges/sized_range.hpp>
28#include <etl/_span/dynamic_extent.hpp>
29#include <etl/_type_traits/conditional.hpp>
30#include <etl/_type_traits/declval.hpp>
31#include <etl/_type_traits/is_array.hpp>
32#include <etl/_type_traits/is_const.hpp>
33#include <etl/_type_traits/is_convertible.hpp>
34#include <etl/_type_traits/remove_cvref.hpp>
35#include <etl/_type_traits/remove_pointer.hpp>
36#include <etl/_type_traits/remove_reference.hpp>
37#include <etl/_type_traits/type_identity.hpp>
38
39namespace etl {
40
41/// A non-owning view over a contiguous sequence of objects.
42///
43/// The class template span describes an object that can refer to a
44/// contiguous sequence of objects with the first element of the sequence at
45/// position zero. A span can either have a static extent, in which case the
46/// number of elements in the sequence is known and encoded in the type, or a
47/// dynamic extent.
48///
49/// If a span has dynamic extent a typical implementation holds
50/// two members: a pointer to T and a size. A span with static extent may have
51/// only one member: a pointer to T.
52///
53/// \ingroup span
54/// \headerfile etl/span.hpp
55template <typename T, size_t Extent = etl::dynamic_extent>
56struct span;
57
58namespace detail {
59
60template <typename T>
61inline constexpr auto is_span = false;
62
63template <typename T, size_t Size>
64inline constexpr auto is_span<etl::span<T, Size>> = true;
65
66template <typename From, typename To>
67concept span_convertible_from = is_convertible_v<From (*)[], To (*)[]>;
68
69template <size_t Offset, size_t Count, size_t Extent>
70[[nodiscard]] consteval auto subspan_extent() -> size_t
71{
72 if (Count != dynamic_extent) {
73 return Count;
74 }
75 if (Extent != dynamic_extent) {
76 return Extent - Offset;
77 }
78 return dynamic_extent;
79}
80
81} // namespace detail
82
83template <typename T, size_t Extent>
84struct span {
85 using element_type = T;
86 using value_type = etl::remove_cv_t<T>;
87 using size_type = etl::size_t;
88 using difference_type = etl::ptrdiff_t;
89 using pointer = T*;
90 using const_pointer = T const*;
91 using reference = T&;
92 using const_reference = T const&;
93 using iterator = T*;
94 using reverse_iterator = etl::reverse_iterator<iterator>;
95
96 /// \brief The number of elements in the sequence, or etl::dynamic_extent
97 /// if dynamic.
98 static constexpr size_type extent = Extent;
99
100 /// \brief Constructs a span. Constructs an empty span whose
101 /// data() == nullptr and size() == 0.
102 ///
103 /// \details This overload only participates in overload resolution
104 /// if extent == 0 || extent == etl::dynamic_extent.
105 constexpr span() noexcept
106 requires(extent == 0 or extent == dynamic_extent)
107 = default;
108
109 /// \brief Constructs a span.
110 /// \details Constructs a span that is a view over the range [first, first + count);
111 template <typename /*contiguous_iterator*/ It>
112 requires detail::span_convertible_from<remove_reference_t<iter_reference_t<It>>, T>
113 explicit(extent != dynamic_extent) constexpr span(It first, size_type count)
114 : _storage{first, count}
115 {
116 }
117
118 /// Constructs a span. From a c style array.
119 template <size_t N>
120 requires(extent == dynamic_extent or extent == N)
121 constexpr span(c_array<type_identity_t<T>, N>& arr) noexcept
122 : _storage{&arr[0], N}
123 {
124 }
125
126 /// Constructs a span. From a array<Type,Size>.
127 template <detail::span_convertible_from<T> U, size_t N>
128 requires(extent == dynamic_extent or extent == N)
129 constexpr span(array<U, N>& arr) noexcept
130 : _storage{arr.data(), arr.size()}
131 {
132 }
133
134 /// Constructs a span. From a array<Type,Size> const.
135 template <detail::span_convertible_from<T> U, size_t N>
136 requires(extent == dynamic_extent or extent == N)
137 constexpr span(array<U, N> const& arr) noexcept
138 : _storage{arr.data(), arr.size()}
139 {
140 }
141
142 /// Constructs a span.
143 template <typename /*etl::ranges::contiguous_range*/ R>
144 requires(
145 ranges::sized_range<R>
146 and (ranges::borrowed_range<R> or is_const_v<T>)
147 and not is_array_v<remove_cvref_t<R>>
148 and not is_etl_array<R>
149 and not detail::is_span<R>
150 and detail::span_convertible_from<remove_reference_t<ranges::range_reference_t<R>>, T>
151 )
152 explicit(extent != dynamic_extent) constexpr span(R&& r)
153 : _storage{r.data(), ranges::size(r)}
154 {
155 }
156
157 template <detail::span_convertible_from<T> U, size_t N>
158 requires(extent == dynamic_extent or N == dynamic_extent or N == extent)
159 explicit(extent != dynamic_extent and N == dynamic_extent) constexpr span(span<U, N> const& source) noexcept
160 : _storage{source.data(), source.size()}
161 {
162 }
163
164 /// \brief Constructs a span.
165 constexpr span(span const& other) noexcept = default;
166
167 /// \brief Returns an iterator to the first element of the span. If the span
168 /// is empty, the returned iterator will be equal to end().
169 [[nodiscard]] constexpr auto begin() const noexcept -> iterator
170 {
171 return _storage.data();
172 }
173
174 /// \brief Returns an iterator to the element following the last element of
175 /// the span. This element acts as a placeholder; attempting to access it
176 /// results in undefined behavior
177 [[nodiscard]] constexpr auto end() const noexcept -> iterator
178 {
179 return begin() + size();
180 }
181
182 /// \brief Returns a reverse iterator to the first element of the reversed
183 /// span. It corresponds to the last element of the non-reversed span. If
184 /// the span is empty, the returned iterator is equal to rend().
185 [[nodiscard]] constexpr auto rbegin() const noexcept -> reverse_iterator
186 {
187 return reverse_iterator(end());
188 }
189
190 /// \brief Returns a reverse iterator to the element following the last
191 /// element of the reversed span. It corresponds to the element preceding
192 /// the first element of the non-reversed span. This element acts as a
193 /// placeholder, attempting to access it results in undefined behavior.
194 [[nodiscard]] constexpr auto rend() const noexcept -> reverse_iterator
195 {
196 return reverse_iterator(begin());
197 }
198
199 /// \brief Returns a reference to the first element in the span. Calling
200 /// front on an empty span results in undefined behavior.
201 [[nodiscard]] constexpr auto front() const -> reference
202 {
203 TETL_PRECONDITION(not empty());
204 return *begin();
205 }
206
207 /// \brief Returns a reference to the last element in the span. Calling
208 /// front on an empty span results in undefined behavior.
209 [[nodiscard]] constexpr auto back() const -> reference
210 {
211 TETL_PRECONDITION(not empty());
212 return *(end() - 1);
213 }
214
215 /// \brief Returns a reference to the idx-th element of the sequence. The
216 /// behavior is undefined if idx is out of range (i.e., if it is greater
217 /// than or equal to size()).
218 [[nodiscard]] constexpr auto operator[](size_type idx) const -> reference
219 {
220 TETL_PRECONDITION(idx < size());
221 return data()[idx];
222 }
223
224 /// \brief Returns a pointer to the beginning of the sequence.
225 [[nodiscard]] constexpr auto data() const noexcept -> pointer
226 {
227 return _storage.data();
228 }
229
230 /// \brief Returns the number of elements in the span.
231 [[nodiscard]] constexpr auto size() const noexcept -> size_type
232 {
233 return _storage.size();
234 }
235
236 /// \brief Returns the number of elements in the span.
237 [[nodiscard]] constexpr auto size_bytes() const noexcept -> size_type
238 {
239 return size() * sizeof(element_type);
240 }
241
242 /// \brief Checks if the span is empty.
243 [[nodiscard]] constexpr auto empty() const noexcept -> bool
244 {
245 return size() == 0;
246 }
247
248 /// \brief Obtains a span that is a view over the first Count elements of
249 /// this span. The program is ill-formed if Count > Extent.
250 template <size_t Count>
251 [[nodiscard]] constexpr auto first() const -> span<element_type, Count>
252 {
253 static_assert(Count <= Extent);
254 return span<element_type, Count>{data(), static_cast<size_type>(Count)};
255 }
256
257 /// \brief Obtains a span that is a view over the first Count elements of
258 /// this span. The behavior is undefined if Count > size().
259 [[nodiscard]] constexpr auto first(size_type count) const -> span<element_type, dynamic_extent>
260 {
261 TETL_PRECONDITION(count <= size());
262 return {data(), static_cast<size_type>(count)};
263 }
264
265 /// \brief Obtains a span that is a view over the last Count elements of
266 /// this span. The program is ill-formed if Count > Extent.
267 template <size_t Count>
268 [[nodiscard]] constexpr auto last() const -> span<element_type, Count>
269 {
270 static_assert(Count <= Extent);
271 return span<element_type, Count>{data() + (size() - Count), static_cast<size_type>(Count)};
272 }
273
274 /// \brief Obtains a span that is a view over the last Count elements of
275 /// this span. The behavior is undefined if Count > size().
276 [[nodiscard]] constexpr auto last(size_type count) const -> span<element_type, dynamic_extent>
277 {
278 TETL_PRECONDITION(count <= size());
279 return {data() + (size() - count), static_cast<size_type>(count)};
280 }
281
282 /// \brief Obtains a span that is a view over the Count elements of this
283 /// span starting at offset Offset. If Count is etl::dynamic_extent, the
284 /// number of elements in the subspan is size() - offset (i.e., it ends at
285 /// the end of *this.).
286 template <size_t Offset, size_t Count = dynamic_extent>
287 [[nodiscard]] constexpr auto subspan() const -> span<T, detail::subspan_extent<Offset, Count, Extent>()>
288 {
289 static_assert(Offset <= Extent);
290 static_assert(Count == dynamic_extent or Count <= Extent - Offset);
291
292 auto const ptr = data() + Offset;
293 auto const sz = static_cast<size_type>(Count == dynamic_extent ? size() - Offset : Count);
294 return span<T, detail::subspan_extent<Offset, Count, Extent>()>{ptr, sz};
295 }
296
297 /// \brief Obtains a span that is a view over the Count elements of this
298 /// span starting at offset Offset. If Count is etl::dynamic_extent, the
299 /// number of elements in the subspan is size() - offset (i.e., it ends at
300 /// the end of *this.).
301 [[nodiscard]] constexpr auto subspan(size_type offset, size_type count = dynamic_extent) const
302 -> span<T, dynamic_extent>
303 {
304 TETL_PRECONDITION(offset <= size());
305 TETL_PRECONDITION(count != dynamic_extent ? (count <= size() - offset) : true);
306 auto const sz = count == dynamic_extent ? size() - offset : count;
307 return {data() + offset, static_cast<size_type>(sz)};
308 }
309
310private:
311 struct static_storage {
312 constexpr static_storage() = default;
313 constexpr static_storage(T* ptr, size_type /*sz*/) noexcept
314 : _data{ptr}
315 {
316 }
317
318 [[nodiscard]] constexpr auto data() const noexcept
319 {
320 return _data;
321 }
322 [[nodiscard]] constexpr auto size() const noexcept
323 {
324 return Extent;
325 }
326
327 private:
328 T* _data{nullptr};
329 };
330
331 struct dynamic_storage {
332 constexpr dynamic_storage() = default;
333 constexpr dynamic_storage(T* ptr, size_type sz) noexcept
334 : _data{ptr}
335 , _size{sz}
336 {
337 }
338
339 [[nodiscard]] constexpr auto data() const noexcept
340 {
341 return _data;
342 }
343 [[nodiscard]] constexpr auto size() const noexcept
344 {
345 return _size;
346 }
347
348 private:
349 T* _data{nullptr};
350 etl::size_t _size{0};
351 };
352
353 using storage = conditional_t<Extent == dynamic_extent, dynamic_storage, static_storage>;
354 storage _storage;
355};
356
357// Deduction Guides. From raw array.
358template <typename Type, size_t Extent>
359span(c_array<Type, Extent>&) -> span<Type, Extent>;
360
361// Deduction Guides. From array<Type, Size>.
362template <typename Type, size_t Size>
363span(array<Type, Size>&) -> span<Type, Size>;
364
365// Deduction Guides. From array<Type const, Size>.
366template <typename Type, size_t Size>
367span(array<Type, Size> const&) -> span<Type const, Size>;
368
369// Deduction Guides. From a contiguous range
370template <ranges::range /*ranges::contiguous_range*/ R>
371span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
372
373namespace ranges {
374template <typename T, etl::size_t Extent>
375inline constexpr bool enable_borrowed_range<etl::span<T, Extent>> = true;
376} // namespace ranges
377
378namespace detail {
379template <typename T, etl::size_t N>
380inline constexpr etl::size_t span_as_bytes_size = N == etl::dynamic_extent ? etl::dynamic_extent : sizeof(T) * N;
381} // namespace detail
382
383/// Obtains a view to the object representation of the elements of the
384/// span s.
385///
386/// If N is dynamic_extent, the extent of the returned span S is also
387/// dynamic_extent; otherwise it is sizeof(T) * N.
388/// \relates span
389/// \ingroup span
390template <typename T, size_t N>
391[[nodiscard]] auto as_bytes(span<T, N> s) noexcept -> span<byte const, detail::span_as_bytes_size<T, N>>
392{
393 return {reinterpret_cast<byte const*>(s.data()), s.size_bytes()};
394}
395
396/// Obtains a view to the object representation of the elements of the
397/// span s.
398///
399/// If N is dynamic_extent, the extent of the returned span S is also
400/// dynamic_extent; otherwise it is sizeof(T) * N. Only participates in overload
401/// resolution if is_const_v<T> is false.
402/// \relates span
403/// \ingroup span
404template <typename T, size_t N>
405 requires(not is_const_v<T>)
406[[nodiscard]] auto as_writable_bytes(span<T, N> s) noexcept -> span<byte, detail::span_as_bytes_size<T, N>>
407{
408 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
409}
410
411} // namespace etl
412
413#endif // TETL_SPAN_SPAN_HPP
constexpr auto size
Definition size.hpp:65
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
auto as_bytes(span< T, N > s) noexcept -> span< byte const, detail::span_as_bytes_size< T, N > >
Obtains a view to the object representation of the elements of the span s.
Definition span.hpp:391
auto as_writable_bytes(span< T, N > s) noexcept -> span< byte, detail::span_as_bytes_size< T, N > >
Obtains a view to the object representation of the elements of the span s.
Definition span.hpp:406
Definition ranges_in_fun_result.hpp:12
Definition adjacent_find.hpp:9
span(array< Type, Size > const &) -> span< Type const, Size >
span(array< Type, Size > &) -> span< Type, Size >
span(c_array< Type, Extent > &) -> span< Type, Extent >
enum TETL_MAY_ALIAS byte
etl::byte is a distinct type that implements the concept of byte as specified in the C++ language def...
Definition byte.hpp:22
span(R &&) -> span< remove_reference_t< ranges::range_reference_t< R > > >
A container that encapsulates fixed size arrays.
Definition array.hpp:49
static constexpr size_type extent
The number of elements in the sequence, or etl::dynamic_extent if dynamic.
Definition span.hpp:98
constexpr auto subspan(size_type offset, size_type count=dynamic_extent) const -> span< T, dynamic_extent >
Obtains a span that is a view over the Count elements of this span starting at offset Offset....
Definition span.hpp:301
constexpr auto rbegin() const noexcept -> reverse_iterator
Returns a reverse iterator to the first element of the reversed span. It corresponds to the last elem...
Definition span.hpp:185
constexpr auto last() const -> span< element_type, Count >
Obtains a span that is a view over the last Count elements of this span. The program is ill-formed if...
Definition span.hpp:268
explicit(extent !=dynamic_extent) const expr span(It first
Constructs a span.
constexpr auto size_bytes() const noexcept -> size_type
Returns the number of elements in the span.
Definition span.hpp:237
constexpr auto rend() const noexcept -> reverse_iterator
Returns a reverse iterator to the element following the last element of the reversed span....
Definition span.hpp:194
size_type count
Definition span.hpp:114
constexpr auto subspan() const -> span< T, detail::subspan_extent< Offset, Count, Extent >()>
Obtains a span that is a view over the Count elements of this span starting at offset Offset....
Definition span.hpp:287
constexpr auto end() const noexcept -> iterator
Returns an iterator to the element following the last element of the span. This element acts as a pla...
Definition span.hpp:177
constexpr auto operator[](size_type idx) const -> reference
Returns a reference to the idx-th element of the sequence. The behavior is undefined if idx is out of...
Definition span.hpp:218
constexpr auto first() const -> span< element_type, Count >
Obtains a span that is a view over the first Count elements of this span. The program is ill-formed i...
Definition span.hpp:251
constexpr auto data() const noexcept -> pointer
Returns a pointer to the beginning of the sequence.
Definition span.hpp:225
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the first element of the span. If the span is empty, the returned iterator wil...
Definition span.hpp:169
constexpr auto empty() const noexcept -> bool
Checks if the span is empty.
Definition span.hpp:243
constexpr auto last(size_type count) const -> span< element_type, dynamic_extent >
Obtains a span that is a view over the last Count elements of this span. The behavior is undefined if...
Definition span.hpp:276
constexpr auto back() const -> reference
Returns a reference to the last element in the span. Calling front on an empty span results in undefi...
Definition span.hpp:209
constexpr auto first(size_type count) const -> span< element_type, dynamic_extent >
Obtains a span that is a view over the first Count elements of this span. The behavior is undefined i...
Definition span.hpp:259
constexpr auto front() const -> reference
Returns a reference to the first element in the span. Calling front on an empty span results in undef...
Definition span.hpp:201
constexpr auto size() const noexcept -> size_type
Returns the number of elements in the span.
Definition span.hpp:231