libstdc++: span Source File

libstdc++

span
Go to the documentation of this file.
1// Components for manipulating non-owning sequences of objects -*- C++ -*-
2
3// Copyright (C) 2019-2026 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file span
26 * This is a Standard C++ Library header.
27 */
28
29//
30// P0122 span library
31// Contributed by ThePhD
32//
33
34#ifndef _GLIBCXX_SPAN
35#define _GLIBCXX_SPAN 1
36
37#ifdef _GLIBCXX_SYSHDR
38#pragma GCC system_header
39#endif
40
41#define __glibcxx_want_span
42#define __glibcxx_want_span_initializer_list
43#define __glibcxx_want_hardened_span
44#include <bits/version.h>
45
46#ifdef __cpp_lib_span // C++ >= 20 && concepts
47#include <array>
48#include <cstddef>
49#include <bits/stl_iterator.h>
50#include <bits/ranges_base.h>
51
52namespace std _GLIBCXX_VISIBILITY(default)
53{
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
55
56 inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
57
58 template<typename _Type, size_t _Extent>
59 class span;
60
61 namespace __detail
62 {
63 template<typename _Tp>
64 inline constexpr bool __is_span = false;
65
66 template<typename _Tp, size_t _Num>
67 inline constexpr bool __is_span<span<_Tp, _Num>> = true;
68
69 template<typename _Tp>
70 inline constexpr bool __is_std_array = false;
71
72 template<typename _Tp, size_t _Num>
73 inline constexpr bool __is_std_array<std::array<_Tp, _Num>> = true;
74
75 template<size_t _Extent>
76 class __extent_storage
77 {
78 public:
79 // Used for runtime sizes that must satisfy the precondition.
80 constexpr
81 __extent_storage([[maybe_unused]] size_t __n) noexcept
82 { __glibcxx_assert(__n == _Extent); }
83
84 // Used for constant sizes that are already known to be correct.
85 consteval
86 __extent_storage(integral_constant<size_t, _Extent>) noexcept
87 { }
88
89 // "I've made a huge mistake" - George Oscar Bluth II
90 template<size_t _Gob>
91 __extent_storage(integral_constant<size_t, _Gob>) = delete;
92
93 [[__gnu__::__always_inline__]]
94 static constexpr size_t
95 _M_extent() noexcept
96 { return _Extent; }
97 };
98
99 template<>
100 class __extent_storage<dynamic_extent>
101 {
102 public:
103 [[__gnu__::__always_inline__]]
104 constexpr
105 __extent_storage(size_t __extent) noexcept
106 : _M_extent_value(__extent)
107 { }
108
109 [[__gnu__::__always_inline__]]
110 constexpr size_t
111 _M_extent() const noexcept
112 { return this->_M_extent_value; }
113
114 private:
115 size_t _M_extent_value;
116 };
117
118 template<typename _Type> struct __span_ptr { _Type* const _M_ptr; };
119
120 } // namespace __detail
121
122 template<typename _Type, size_t _Extent = dynamic_extent>
123 class span
124 {
125 template<size_t _Offset, size_t _Count>
126 static constexpr size_t
127 _S_subspan_extent()
128 {
129 if constexpr (_Count != dynamic_extent)
130 return _Count;
131 else if constexpr (extent != dynamic_extent)
132 return _Extent - _Offset;
133 else
134 return dynamic_extent;
135 }
136
137 // _GLIBCXX_RESOLVE_LIB_DEFECTS
138 // 3255. span's array constructor is too strict
139 template<typename _Tp, size_t _ArrayExtent>
140 requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
141 using __is_compatible_array = __is_array_convertible<_Type, _Tp>;
142
143 template<typename _Ref>
144 using __is_compatible_ref
145 = __is_array_convertible<_Type, remove_reference_t<_Ref>>;
146
147 // Nested type so that _Type is not an associated class of iterator.
148 struct __iter_tag;
149
150 template<size_t _Nm>
151 static inline constexpr integral_constant<size_t, _Nm> __v{};
152
153 public:
154 // member types
155 using element_type = _Type;
156 using value_type = remove_cv_t<_Type>;
157 using size_type = size_t;
158 using difference_type = ptrdiff_t;
159 using pointer = _Type*;
160 using const_pointer = const _Type*;
161 using reference = element_type&;
162 using const_reference = const element_type&;
163 using iterator = __gnu_cxx::__normal_iterator<pointer, __iter_tag>;
164 using reverse_iterator = std::reverse_iterator<iterator>;
165#if __cplusplus > 202002L
166 using const_iterator = std::const_iterator<iterator>;
167 using const_reverse_iterator = std::const_iterator<reverse_iterator>;
168#endif
169
170 // member constants
171 static constexpr size_t extent = _Extent;
172
173 // constructors, copy and assignment
174
175 constexpr
176 span() noexcept
177 requires (_Extent == dynamic_extent || _Extent == 0)
178 : _M_ptr(nullptr), _M_extent(__v<0>)
179 { }
180
181 template<contiguous_iterator _It>
182 requires __is_compatible_ref<iter_reference_t<_It>>::value
183 constexpr explicit(extent != dynamic_extent)
184 span(_It __first, size_type __count)
185 noexcept
186 : _M_ptr(std::to_address(__first)), _M_extent(__count)
187 { __glibcxx_requires_valid_range(__first, __first + __count); }
188
189 template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
190 requires __is_compatible_ref<iter_reference_t<_It>>::value
191 && (!is_convertible_v<_End, size_type>)
192 constexpr explicit(extent != dynamic_extent)
193 span(_It __first, _End __last)
194 noexcept(noexcept(__last - __first))
195 : _M_ptr(std::to_address(__first)),
196 _M_extent(static_cast<size_type>(__last - __first))
197 { __glibcxx_requires_valid_range(__first, __last); }
198
199 template<size_t _ArrayExtent>
200 requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
201 constexpr
202 span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
203 : _M_ptr(__arr), _M_extent(__v<_ArrayExtent>)
204 { }
205
206 template<typename _Tp, size_t _ArrayExtent>
207 requires __is_compatible_array<_Tp, _ArrayExtent>::value
208 constexpr
209 span(array<_Tp, _ArrayExtent>& __arr) noexcept
210 : _M_ptr(__arr.data()), _M_extent(__v<_ArrayExtent>)
211 { }
212
213 template<typename _Tp, size_t _ArrayExtent>
214 requires __is_compatible_array<const _Tp, _ArrayExtent>::value
215 constexpr
216 span(const array<_Tp, _ArrayExtent>& __arr) noexcept
217 : _M_ptr(__arr.data()), _M_extent(__v<_ArrayExtent>)
218 { }
219
220 template<typename _Range>
221 requires (!__detail::__is_span<remove_cvref_t<_Range>>)
222 && (!__detail::__is_std_array<remove_cvref_t<_Range>>)
223 && (!is_array_v<remove_cvref_t<_Range>>)
224 && ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
225 && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
226 && __is_compatible_ref<ranges::range_reference_t<_Range>>::value
227 constexpr explicit(extent != dynamic_extent)
228 span(_Range&& __range)
229 noexcept(noexcept(ranges::data(__range))
230 && noexcept(ranges::size(__range)))
231 : _M_ptr(ranges::data(__range)), _M_extent(ranges::size(__range))
232 { }
233
234 constexpr
235 span(const span&) noexcept = default;
236
237 template<typename _OType, size_t _OExtent>
238 requires (_Extent == dynamic_extent || _OExtent == dynamic_extent
239 || _Extent == _OExtent)
240 && (__is_array_convertible<_Type, _OType>::value)
241 constexpr
242 explicit(extent != dynamic_extent && _OExtent == dynamic_extent)
243 span(const span<_OType, _OExtent>& __s) noexcept
244 : _M_ptr(__s.data()), _M_extent(__s.size())
245 { }
246
247 constexpr span&
248 operator=(const span&) noexcept = default;
249
250 // observers
251
252 [[nodiscard]]
253 constexpr size_type
254 size() const noexcept
255 { return this->_M_extent._M_extent(); }
256
257 [[nodiscard]]
258 constexpr size_type
259 size_bytes() const noexcept
260 { return this->_M_extent._M_extent() * sizeof(element_type); }
261
262 [[nodiscard]]
263 constexpr bool
264 empty() const noexcept
265 { return size() == 0; }
266
267 // element access
268
269 [[nodiscard]]
270 constexpr reference
271 front() const noexcept
272 {
273 __glibcxx_assert(!empty());
274 return *this->_M_ptr;
275 }
276
277 [[nodiscard]]
278 constexpr reference
279 back() const noexcept
280 {
281 __glibcxx_assert(!empty());
282 return *(this->_M_ptr + (size() - 1));
283 }
284
285 [[nodiscard]]
286 constexpr reference
287 operator[](size_type __idx) const noexcept
288 {
289 __glibcxx_assert(__idx < size());
290 return *(this->_M_ptr + __idx);
291 }
292
293#if __cpp_lib_span >= 202311L // >= C++26
294 [[nodiscard]]
295 constexpr reference
296 at(size_type __idx) const
297 {
298 if (__idx >= size())
299 __throw_out_of_range_fmt(__N("span::at(%zu) out-of-range for span "
300 "of size %zu"), __idx, this->size());
301 return *(this->_M_ptr + __idx);
302 }
303#endif
304
305 [[nodiscard]]
306 constexpr pointer
307 data() const noexcept
308 { return this->_M_ptr; }
309
310 // iterator support
311
312 [[nodiscard]]
313 constexpr iterator
314 begin() const noexcept
315 { return iterator(this->_M_ptr); }
316
317 [[nodiscard]]
318 constexpr iterator
319 end() const noexcept
320 { return iterator(this->_M_ptr + this->size()); }
321
322 [[nodiscard]]
323 constexpr reverse_iterator
324 rbegin() const noexcept
325 { return reverse_iterator(this->end()); }
326
327 [[nodiscard]]
328 constexpr reverse_iterator
329 rend() const noexcept
330 { return reverse_iterator(this->begin()); }
331
332#if __cplusplus > 202002L
333 [[nodiscard]]
334 constexpr const_iterator
335 cbegin() const noexcept
336 { return begin(); }
337
338 [[nodiscard]]
339 constexpr const_iterator
340 cend() const noexcept
341 { return end(); }
342
343 [[nodiscard]]
344 constexpr const_reverse_iterator
345 crbegin() const noexcept
346 { return rbegin(); }
347
348 [[nodiscard]]
349 constexpr const_reverse_iterator
350 crend() const noexcept
351 { return rend(); }
352#endif
353
354 // subviews
355
356 template<size_t _Count>
357 [[nodiscard]]
358 constexpr span<element_type, _Count>
359 first() const noexcept
360 {
361 if constexpr (_Extent == dynamic_extent)
362 __glibcxx_assert(_Count <= size());
363 else
364 static_assert(_Count <= extent);
365 using _Sp = span<element_type, _Count>;
366 return _Sp(_SizedPtr{this->data()});
367 }
368
369 [[nodiscard]]
370 constexpr span<element_type, dynamic_extent>
371 first(size_type __count) const noexcept
372 {
373 __glibcxx_assert(__count <= size());
374 return span<element_type>(this->data(), __count);
375 }
376
377 template<size_t _Count>
378 [[nodiscard]]
379 constexpr span<element_type, _Count>
380 last() const noexcept
381 {
382 if constexpr (_Extent == dynamic_extent)
383 __glibcxx_assert(_Count <= size());
384 else
385 static_assert(_Count <= extent);
386 using _Sp = span<element_type, _Count>;
387 return _Sp(_SizedPtr{this->data() + (this->size() - _Count)});
388 }
389
390 [[nodiscard]]
391 constexpr span<element_type, dynamic_extent>
392 last(size_type __count) const noexcept
393 {
394 __glibcxx_assert(__count <= size());
395 return span<element_type>(this->data() + (this->size() - __count),
396 __count);
397 }
398
399 template<size_t _Offset, size_t _Count = dynamic_extent>
400 [[nodiscard]]
401 constexpr auto
402 subspan() const noexcept
403 -> span<element_type, _S_subspan_extent<_Offset, _Count>()>
404 {
405 if constexpr (_Extent == dynamic_extent)
406 {
407 __glibcxx_assert(_Offset <= size());
408 }
409 else
410 static_assert(_Offset <= extent);
411
412 using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>;
413
414 if constexpr (_Count == dynamic_extent)
415 return _Sp(this->data() + _Offset, this->size() - _Offset);
416 else
417 {
418 if constexpr (_Extent == dynamic_extent)
419 {
420 __glibcxx_assert(_Count <= size());
421 __glibcxx_assert(_Count <= (size() - _Offset));
422 }
423 else
424 {
425 static_assert(_Count <= extent);
426 static_assert(_Count <= (extent - _Offset));
427 }
428 return _Sp(_SizedPtr{this->data() + _Offset});
429 }
430 }
431
432 [[nodiscard]]
433 constexpr span<element_type, dynamic_extent>
434 subspan(size_type __offset, size_type __count = dynamic_extent) const
435 noexcept
436 {
437 __glibcxx_assert(__offset <= size());
438 if (__count == dynamic_extent)
439 __count = this->size() - __offset;
440 else
441 {
442 __glibcxx_assert(__count <= size());
443 __glibcxx_assert(__offset + __count <= size());
444 }
445 return span<element_type>(this->data() + __offset, __count);
446 }
447
448 private:
449 template<typename, size_t> friend class span;
450
451 // Tag type for pointer that has known extent.
452 using _SizedPtr = __detail::__span_ptr<_Type>;
453
454 // Private constructor with an implied extent.
455 [[__gnu__::__always_inline__]]
456 constexpr explicit
457 span(_SizedPtr __ptr) noexcept
458 requires (extent != dynamic_extent)
459 : _M_ptr(__ptr._M_ptr), _M_extent(__v<extent>)
460 { }
461
462 pointer _M_ptr;
463 [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
464 };
465
466 // deduction guides
467 namespace __detail
468 {
469 // _GLIBCXX_RESOLVE_LIB_DEFECTS
470 // 4351. integral-constant-like needs more remove_cvref_t
471 // 4486. integral-constant-like and constexpr-wrapper-like exposition-only
472 // concept duplication
473 template<typename _Tp>
474 concept __integral_constant_like =
475 is_integral_v<remove_cvref_t<decltype(_Tp::value)>>
476 && !is_same_v<bool, remove_cvref_t<decltype(_Tp::value)>>
477 && __constexpr_wrapper_like<_Tp>;
478
479 template<typename _Tp>
480 constexpr size_t __maybe_static_ext = dynamic_extent;
481
482 template<__integral_constant_like _Tp>
483 constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value};
484 }
485
486 template<typename _Type, size_t _ArrayExtent>
487 span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
488
489 template<typename _Type, size_t _ArrayExtent>
490 span(array<_Type, _ArrayExtent>&) -> span<_Type, _ArrayExtent>;
491
492 template<typename _Type, size_t _ArrayExtent>
493 span(const array<_Type, _ArrayExtent>&)
494 -> span<const _Type, _ArrayExtent>;
495
496 template<contiguous_iterator _Iter, typename _End>
497 span(_Iter, _End)
498 -> span<remove_reference_t<iter_reference_t<_Iter>>,
499 __detail::__maybe_static_ext<_End>>;
500
501 template<ranges::contiguous_range _Range>
502 span(_Range &&)
503 -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;
504
505 // _GLIBCXX_RESOLVE_LIB_DEFECTS
506 // 4243. as_bytes/as_writable_bytes is broken with span<volatile T>
507 template<typename _Type, size_t _Extent>
508 requires (!is_volatile_v<_Type>)
509 [[nodiscard]]
510 inline
511 span<const byte, _Extent == dynamic_extent
512 ? dynamic_extent : _Extent * sizeof(_Type)>
513 as_bytes(span<_Type, _Extent> __sp) noexcept
514 {
515 auto data = reinterpret_cast<const byte*>(__sp.data());
516 auto size = __sp.size_bytes();
517 constexpr auto extent = _Extent == dynamic_extent
518 ? dynamic_extent : _Extent * sizeof(_Type);
519 return span<const byte, extent>{data, size};
520 }
521
522 template<typename _Type, size_t _Extent>
523 requires (!is_const_v<_Type> && !is_volatile_v<_Type>)
524 inline
525 span<byte, _Extent == dynamic_extent
526 ? dynamic_extent : _Extent * sizeof(_Type)>
527 as_writable_bytes [[nodiscard]] (span<_Type, _Extent> __sp) noexcept
528 {
529 auto data = reinterpret_cast<byte*>(__sp.data());
530 auto size = __sp.size_bytes();
531 constexpr auto extent = _Extent == dynamic_extent
532 ? dynamic_extent : _Extent * sizeof(_Type);
533 return span<byte, extent>{data, size};
534 }
535
536 namespace ranges
537 {
538 // Opt-in to borrowed_range concept
539 template<typename _ElementType, size_t _Extent>
540 inline constexpr bool
541 enable_borrowed_range<span<_ElementType, _Extent>> = true;
542
543 // Opt-in to view concept
544 template<typename _ElementType, size_t _Extent>
545 inline constexpr bool
546 enable_view<span<_ElementType, _Extent>> = true;
547 }
548_GLIBCXX_END_NAMESPACE_VERSION
549} // namespace std
550#endif // __cpp_lib_span
551#endif // _GLIBCXX_SPAN
array
cstddef
ranges_base.h
std::ranges::enable_view
constexpr bool enable_view
[range.view] The ranges::enable_view boolean.
Definition ranges_base.h:602
version.h
std::to_address
constexpr _Tp * to_address(_Tp *__ptr) noexcept
Obtain address referenced by a pointer to an object.
Definition ptr_traits.h:234
std
ISO C++ entities toplevel namespace is std.
std::size
constexpr auto size(const _Container &__cont) noexcept(noexcept(__cont.size())) -> decltype(__cont.size())
Return the size of a container.
Definition range_access.h:294
std::data
constexpr auto data(_Container &__cont) noexcept(noexcept(__cont.data())) -> decltype(__cont.data())
Return the data pointer of a container.
Definition range_access.h:354
std::__detail
Implementation details not part of the namespace std interface.
std::array
A standard container for storing a fixed size sequence of elements.
Definition array:104
std::extent
extent
Definition type_traits:1623
stl_iterator.h