Dune Core Modules (unstable)

span.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_SPAN_HH
6#define DUNE_COMMON_STD_SPAN_HH
7
8#include <cassert>
9#include <cstddef>
10#include <exception>
11#include <iterator>
12#include <limits>
13#if __has_include(<span>)
14#include <span>
15#endif
16#include <stdexcept>
17#include <string>
18#include <type_traits>
19#if __has_include(<version>)
20 #include <version>
21#endif
22
24#include <dune/common/std/memory.hh>
25
26namespace Dune::Std {
27
29inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
30
31#if __cpp_lib_span >= 202002L
32
33using std::span;
34
35#else
36
37namespace Impl {
38
39template <std::size_t Extent>
40class SpanSize
41{
42public:
43 using size_type = std::size_t;
44
45public:
46 constexpr SpanSize () = default;
47
48 constexpr SpanSize ([[maybe_unused]] size_type size) noexcept
49 {
50 assert(Extent == Std::dynamic_extent || Extent == size);
51 }
52
53 template <class Iter>
54 constexpr SpanSize ([[maybe_unused]] Iter first, [[maybe_unused]] Iter last) noexcept
55 {
56 assert((std::distance(first,last) == Extent));
57 }
58
59 constexpr size_type size () const noexcept { return Extent; }
60};
61
62template <>
63class SpanSize<Std::dynamic_extent>
64{
65public:
66 using size_type = std::size_t;
67
68public:
69 constexpr SpanSize (size_type size = 0) noexcept
70 : size_(size)
71 {}
72
73 template <class Iter>
74 constexpr SpanSize (Iter first, Iter last) noexcept
75 : size_(std::distance(first,last))
76 {}
77
78 constexpr size_type size () const noexcept { return size_; }
79
80private:
81 size_type size_;
82};
83
84template <class T>
85struct TypeIdentity { using type = T; };
86
87template <class T>
88using TypeIdentity_t = typename TypeIdentity<T>::type;
89
90} // end namespace Impl
91
92
132template <class Element, std::size_t Extent = Std::dynamic_extent>
133class span
134 : public Impl::SpanSize<Extent>
135{
136 using base_type = Impl::SpanSize<Extent>; // base_type implements the member variable size()
137
138 static_assert(std::is_object_v<Element> && !std::is_abstract_v<Element>);
139
140public:
141 using element_type = Element;
142 using value_type = std::remove_cv_t<element_type>;
143 using size_type = std::size_t;
144 using difference_type = std::ptrdiff_t;
145 using pointer = element_type*;
146 using reference = element_type&;
147 using const_reference = const element_type&;
148 using iterator = pointer;
149 using reverse_iterator = std::reverse_iterator<iterator>;
150#if __cpp_lib_ranges_as_const >202311L
151 using const_iterator = std::const_iterator<iterator>;
152 using const_reverse_iterator = std::const_iterator<reverse_iterator>;
153#else
154 using const_iterator = const iterator;
155 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
156#endif
157
158
159 static constexpr size_type extent = Extent;
160
161public:
164
166 template <std::size_t e = extent,
167 std::enable_if_t<(e == dynamic_extent || e == 0), int> = 0>
168 constexpr span () noexcept
169 : base_type{}
170 , data_{}
171 {}
172
174 template <class Iter,
175 class U = std::remove_reference_t<decltype(*std::declval<Iter>())>,
176 std::enable_if_t<std::is_convertible_v<U(*)[], element_type(*)[]>, int> = 0>
177 #if __cpp_conditional_explicit >= 201806L
178 explicit(extent != Std::dynamic_extent)
179 #endif
180 constexpr span (Iter first, size_type size)
181 : base_type(size)
182 , data_(Std::to_address(first))
183 {}
184
186 template <class Iter,
187 class U = std::remove_reference_t<decltype(*std::declval<Iter>())>,
188 std::enable_if_t<std::is_convertible_v<U(*)[], element_type(*)[]>, int> = 0>
189 #if __cpp_conditional_explicit >= 201806L
190 explicit(extent != Std::dynamic_extent)
191 #endif
192 constexpr span (Iter first, Iter last)
193 : base_type(first,last)
194 , data_(Std::to_address(first))
195 {}
196
198 template <class Range,
199 decltype(std::begin(std::declval<Range>()), std::end(std::declval<Range>()), bool{}) = true,
200 std::enable_if_t<not std::is_array_v<Range>, int> = 0>
201 #if __cpp_conditional_explicit >= 201806L
202 explicit(extent != Std::dynamic_extent)
203 #endif
204 constexpr span (Range& range)
205 : span(std::begin(range), std::end(range))
206 {}
207
209 template <std::size_t N, std::size_t e = extent,
210 std::enable_if_t<(e == Std::dynamic_extent || e == N), int> = 0>
211 constexpr span (Impl::TypeIdentity_t<element_type> (&data)[N]) noexcept
212 : base_type(N)
213 , data_(data)
214 {}
215
217 template <class T, size_t N, std::size_t e = extent,
218 std::enable_if_t<(e == Std::dynamic_extent || e == N), int> = 0,
219 std::enable_if_t<std::is_convertible_v<T(*)[], element_type(*)[]>, int> = 0>
220 constexpr span (std::array<T, N>& arr) noexcept
221 : base_type(N)
222 , data_(arr.data())
223 {}
224
226 template <class T, size_t N, std::size_t e = extent,
227 std::enable_if_t<(e == Std::dynamic_extent || e == N), int> = 0,
228 std::enable_if_t<std::is_convertible_v<const T(*)[], element_type(*)[]>, int> = 0>
229 constexpr span (const std::array<T, N>& arr) noexcept
230 : base_type(N)
231 , data_(arr.data())
232 {}
233
235 template <class E = element_type,
236 std::enable_if_t<std::is_const_v<E>, int> = 0>
237 #if __cpp_conditional_explicit >= 201806L
238 explicit(extent != Std::dynamic_extent)
239 #endif
240 constexpr span (std::initializer_list<value_type> il)
241 : base_type(il.size())
242 , data_(il.begin())
243 {}
244
246 constexpr span (const span& other) noexcept = default;
247
249 template <class OtherElementType, std::size_t OtherExtent,
250 std::enable_if_t<(extent == Std::dynamic_extent || OtherExtent == Std::dynamic_extent || extent == OtherExtent), int> = 0,
251 std::enable_if_t<std::is_convertible_v<OtherElementType(*)[], element_type(*)[]>, int> = 0>
252 #if __cpp_conditional_explicit >= 201806L
253 explicit(extent != Std::dynamic_extent && OtherExtent == Std::dynamic_extent)
254 #endif
255 constexpr span (const span<OtherElementType, OtherExtent>& s) noexcept
256 : base_type(s.size())
257 , data_(s.data())
258 {}
259
261 constexpr span& operator= (const span& other) noexcept = default;
262
264
265
268
270 constexpr iterator begin () const noexcept { return data_; }
271
273 constexpr iterator end () const noexcept { return data_ + size(); }
274
276 constexpr const_iterator cbegin () const noexcept { return data_; }
277
279 constexpr const_iterator cend () const noexcept { return data_ + size(); }
280
282 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
283
285 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
286
288 constexpr const_reverse_iterator crbegin() const noexcept { return reverse_iterator{end()}; }
289
291 constexpr const_reverse_iterator crend() const noexcept { return reverse_iterator{begin()}; }
292
294
295
298
300 constexpr reference front () const
301 {
302 assert(not empty() && "front of empty span does not exist");
303 return data_[0];
304 }
305
307 constexpr reference back () const
308 {
309 assert(not empty() && "front of empty span does not exist");
310 return data_[size()-1];
311 }
312
314 constexpr reference at (size_type i) const
315 {
316 if (i >= size())
317 throw std::out_of_range("Index " + std::to_string(i) + " out of range.");
318 return data_[i];
319 }
320
322 constexpr reference operator[] (size_type i) const { return data_[i]; }
323
325 constexpr pointer data () const noexcept { return data_; }
326
328
329
332
334 template <std::size_t Count>
336 {
337 static_assert(Count <= Extent);
338 assert(Count <= size());
339 return span<element_type, Count>{data(), Count};
340 }
341
343 template <std::size_t Count>
345 {
346 static_assert(Count <= Extent);
347 assert(Count <= size());
348 return span<element_type, Count>{data()+ (size() - Count), Count};
349 }
350
351private:
352
353 static constexpr std::size_t subspan_extent (std::size_t O, std::size_t C) noexcept
354 {
355 return (C != Std::dynamic_extent) ? C :
356 (Extent != Std::dynamic_extent) ? Extent - O : Std::dynamic_extent;
357 }
358
359public:
360
362
366 template <std::size_t Offset, std::size_t Count = Std::dynamic_extent>
367 constexpr span<element_type, subspan_extent(Offset,Count)> subspan () const
368 {
369 static_assert(Offset <= Extent && (Count == Std::dynamic_extent || Count <= Extent - Offset));
370 assert(Offset <= size() && (Count == Std::dynamic_extent || Count <= size() - Offset));
371 return span<element_type, subspan_extent(Offset,Count)>{
372 data() + Offset, Count != Std::dynamic_extent ? Count : size() - Offset};
373 }
374
376 constexpr span<element_type, Std::dynamic_extent> first (size_type count) const
377 {
378 assert(count <= size());
380 }
381
383 constexpr span<element_type, Std::dynamic_extent> last (size_type count) const
384 {
385 assert(count <= size());
386 return span<element_type, Std::dynamic_extent>{data()+ (size() - count), count};
387 }
388
390
394 constexpr span<element_type, Std::dynamic_extent> subspan (size_type offset, size_type count = Std::dynamic_extent) const
395 {
396 assert(offset <= size() && (count == Std::dynamic_extent || count <= size() - offset));
398 data() + offset, count == Std::dynamic_extent ? size() - offset : count};
399 }
400
402
403
406
408 using base_type::size;
409
411 constexpr size_type size_bytes () const noexcept { return size() * sizeof(element_type); }
412
414 [[nodiscard]] constexpr bool empty () const noexcept { return size() == 0; }
415
417
418private:
419 pointer data_;
420};
421
422// deduction guide
423// @{
424
425template <class T, std::size_t N>
426span (T (&)[N])
427 -> span<T, N>;
428
429template <class ElementType, class I, std::size_t Extent,
430 std::enable_if_t<std::is_convertible_v<I,std::size_t>, int> = 0>
431span (ElementType*, std::integral_constant<I,Extent>)
432 -> span<ElementType, Extent>;
433
434template <class ElementType, class I,
435 std::enable_if_t<std::is_integral_v<I>, int> = 0,
436 std::enable_if_t<std::is_convertible_v<I,std::size_t>, int> = 0>
437span (ElementType*, I)
438 -> span<ElementType, Std::dynamic_extent>;
439
440template <class Iter,
441 class Element = std::remove_reference_t<decltype(*std::declval<Iter>())>>
442span (Iter,Iter)
443 -> span<Element, Std::dynamic_extent>;
444
445template <class Range,
446 class First = decltype(std::begin(std::declval<Range>())),
447 class Last = decltype(std::end(std::declval<Range>())),
448 class Element = std::remove_reference_t<decltype(*std::declval<First>())>>
449span (Range&)
450 -> span<Element, Std::dynamic_extent>;
451
452template <class T, size_t N>
453span (std::array<T, N>&) -> span<T, N>;
454
455template <class T, size_t N>
456span (const std::array<T, N>&) -> span<const T, N>;
457
458// @}
459
460#endif // __cpp_lib_span
461
462} // end namespace Dune::Std
463
464#endif // DUNE_COMMON_STD_SPAN_HH
A contiguous sequence of elements with static or dynamic extent.
Definition: span.hh:135
constexpr reference front() const
Access the first element.
Definition: span.hh:300
constexpr span(const span &other) noexcept=default
Copy constructor.
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:270
constexpr const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:276
constexpr span(std::array< T, N > &arr) noexcept
Constructs a span that is a view over the array.
Definition: span.hh:220
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition: span.hh:273
constexpr span< element_type, Std::dynamic_extent > subspan(size_type offset, size_type count=Std::dynamic_extent) const
Obtains a subspan consisting of count elements of the sequence starting at offset.
Definition: span.hh:394
constexpr span & operator=(const span &other) noexcept=default
Copy assignment operator.
constexpr reference at(size_type i) const
Access specified element with bounds checking.
Definition: span.hh:314
constexpr span< element_type, Std::dynamic_extent > first(size_type count) const
Obtains a subspan consisting of the first count elements of the sequence.
Definition: span.hh:376
constexpr span< element_type, subspan_extent(Offset, Count)> subspan() const
Obtains a subspan consisting of Count elements of the sequence starting at Offset.
Definition: span.hh:367
constexpr const_reverse_iterator crend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:291
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:285
constexpr pointer data() const noexcept
Direct access to the underlying contiguous storage.
Definition: span.hh:325
constexpr size_type size_bytes() const noexcept
Returns the size of the sequence in bytes.
Definition: span.hh:411
constexpr const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:288
constexpr bool empty() const noexcept
Checks if the sequence is empty.
Definition: span.hh:414
constexpr span< element_type, Count > last() const
Obtains a subspan consisting of the last Count elements of the sequence.
Definition: span.hh:344
constexpr span(Range &range)
Constructs a span that is a view over the range [range.begin(), range.end())
Definition: span.hh:204
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:282
constexpr span< element_type, Std::dynamic_extent > last(size_type count) const
Obtains a subspan consisting of the last count elements of the sequence.
Definition: span.hh:383
constexpr const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: span.hh:279
constexpr span< element_type, Count > first() const
Obtains a subspan consisting of the first Count elements of the sequence.
Definition: span.hh:335
constexpr reference back() const
Access the last element.
Definition: span.hh:307
constexpr span(const std::array< T, N > &arr) noexcept
Constructs a span that is a view over the const array.
Definition: span.hh:229
constexpr reference operator[](size_type i) const
Access specified element.
Definition: span.hh:322
A few common exception classes.
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:288
Namespace for features backported from new C++ standards.
Definition: algorithm.hh:19
constexpr auto to_address(T &&p) noexcept
Obtain the address represented by p without forming a reference to the object pointed to by p.
Definition: memory.hh:47
constexpr std::size_t dynamic_extent
A constant of type std::size_t that is used to differentiate std::span of static and dynamic extent.
Definition: span.hh:29
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
STL namespace.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jul 19, 22:37, 2025)