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#include <stdexcept>
14#include <string>
15#include <type_traits>
16#if __has_include(<version>)
17 #include <version>
18#endif
19
21#include <dune/common/std/memory.hh>
22
23namespace Dune::Std {
24
27
28namespace Impl {
29
30template <std::size_t Extent>
31class SpanSize
32{
33public:
34 using size_type = std::size_t;
35
36public:
37 constexpr SpanSize () = default;
38
39 constexpr SpanSize ([[maybe_unused]] size_type size) noexcept
40 {
41 assert(Extent == Std::dynamic_extent || Extent == size);
42 }
43
44 template <class Iter>
45 constexpr SpanSize ([[maybe_unused]] Iter first, [[maybe_unused]] Iter last) noexcept
46 {
47 assert((std::distance(first,last) == Extent));
48 }
49
50 constexpr size_type size () const noexcept { return Extent; }
51};
52
53template <>
54class SpanSize<Std::dynamic_extent>
55{
56public:
57 using size_type = std::size_t;
58
59public:
60 constexpr SpanSize (size_type size = 0) noexcept
61 : size_(size)
62 {}
63
64 template <class Iter>
65 constexpr SpanSize (Iter first, Iter last) noexcept
66 : size_(std::distance(first,last))
67 {}
68
69 constexpr size_type size () const noexcept { return size_; }
70
71private:
72 size_type size_;
73};
74
75template <class T>
76struct TypeIdentity { using type = T; };
77
78template <class T>
79using TypeIdentity_t = typename TypeIdentity<T>::type;
80
81} // end namespace Impl
82
83
123template <class Element, std::size_t Extent = Std::dynamic_extent>
124class span
125 : public Impl::SpanSize<Extent>
126{
127 using base_type = Impl::SpanSize<Extent>; // base_type implements the member variable size()
128
129 static_assert(std::is_object_v<Element> && !std::is_abstract_v<Element>);
130
131public:
132 using element_type = Element;
133 using value_type = std::remove_cv_t<element_type>;
134 using size_type = std::size_t;
135 using difference_type = std::ptrdiff_t;
136 using pointer = element_type*;
137 using reference = element_type&;
138 using const_reference = const element_type&;
139 using iterator = pointer;
140 using reverse_iterator = std::reverse_iterator<iterator>;
141#if __cpp_lib_ranges_as_const >202311L
142 using const_iterator = std::const_iterator<iterator>;
143 using const_reverse_iterator = std::const_iterator<reverse_iterator>;
144#else
145 using const_iterator = const iterator;
146 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
147#endif
148
149
150 static constexpr size_type extent = Extent;
151
152public:
155
157 template <std::size_t e = extent,
158 std::enable_if_t<(e == dynamic_extent || e == 0), int> = 0>
159 constexpr span () noexcept
160 : base_type{}
161 , data_{}
162 {}
163
165 template <class Iter,
166 class U = std::remove_reference_t<decltype(*std::declval<Iter>())>,
167 std::enable_if_t<std::is_convertible_v<U(*)[], element_type(*)[]>, int> = 0>
168 #if __cpp_conditional_explicit >= 201806L
169 explicit(extent != Std::dynamic_extent)
170 #endif
171 constexpr span (Iter first, size_type size)
172 : base_type(size)
173 , data_(Std::to_address(first))
174 {}
175
177 template <class Iter,
178 class U = std::remove_reference_t<decltype(*std::declval<Iter>())>,
179 std::enable_if_t<std::is_convertible_v<U(*)[], element_type(*)[]>, int> = 0>
180 #if __cpp_conditional_explicit >= 201806L
181 explicit(extent != Std::dynamic_extent)
182 #endif
183 constexpr span (Iter first, Iter last)
184 : base_type(first,last)
185 , data_(Std::to_address(first))
186 {}
187
189 template <class Range,
190 decltype(std::begin(std::declval<Range>()), std::end(std::declval<Range>()), bool{}) = true,
191 std::enable_if_t<not std::is_array_v<Range>, int> = 0>
192 #if __cpp_conditional_explicit >= 201806L
193 explicit(extent != Std::dynamic_extent)
194 #endif
195 constexpr span (Range& range)
196 : span(std::begin(range), std::end(range))
197 {}
198
200 template <std::size_t N, std::size_t e = extent,
201 std::enable_if_t<(e == Std::dynamic_extent || e == N), int> = 0>
202 constexpr span (Impl::TypeIdentity_t<element_type> (&data)[N]) noexcept
203 : base_type(N)
204 , data_(data)
205 {}
206
208 template <class T, size_t N, std::size_t e = extent,
209 std::enable_if_t<(e == Std::dynamic_extent || e == N), int> = 0,
210 std::enable_if_t<std::is_convertible_v<T(*)[], element_type(*)[]>, int> = 0>
211 constexpr span (std::array<T, N>& arr) noexcept
212 : base_type(N)
213 , data_(arr.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<const T(*)[], element_type(*)[]>, int> = 0>
220 constexpr span (const std::array<T, N>& arr) noexcept
221 : base_type(N)
222 , data_(arr.data())
223 {}
224
226 template <class E = element_type,
227 std::enable_if_t<std::is_const_v<E>, int> = 0>
228 #if __cpp_conditional_explicit >= 201806L
229 explicit(extent != Std::dynamic_extent)
230 #endif
231 constexpr span (std::initializer_list<value_type> il)
232 : base_type(il.size())
233 , data_(il.begin())
234 {}
235
237 constexpr span (const span& other) noexcept = default;
238
240 template <class OtherElementType, std::size_t OtherExtent,
241 std::enable_if_t<(extent == Std::dynamic_extent || OtherExtent == Std::dynamic_extent || extent == OtherExtent), int> = 0,
242 std::enable_if_t<std::is_convertible_v<OtherElementType(*)[], element_type(*)[]>, int> = 0>
243 #if __cpp_conditional_explicit >= 201806L
244 explicit(extent != Std::dynamic_extent && OtherExtent == Std::dynamic_extent)
245 #endif
246 constexpr span (const span<OtherElementType, OtherExtent>& s) noexcept
247 : base_type(s.size())
248 , data_(s.data())
249 {}
250
252 constexpr span& operator= (const span& other) noexcept = default;
253
255
256
259
261 constexpr iterator begin () const noexcept { return data_; }
262
264 constexpr iterator end () const noexcept { return data_ + size(); }
265
267 constexpr const_iterator cbegin () const noexcept { return data_; }
268
270 constexpr const_iterator cend () const noexcept { return data_ + size(); }
271
273 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
274
276 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
277
279 constexpr const_reverse_iterator crbegin() const noexcept { return reverse_iterator{end()}; }
280
282 constexpr const_reverse_iterator crend() const noexcept { return reverse_iterator{begin()}; }
283
285
286
289
291 constexpr reference front () const
292 {
293 assert(not empty() && "front of empty span does not exist");
294 return data_[0];
295 }
296
298 constexpr reference back () const
299 {
300 assert(not empty() && "front of empty span does not exist");
301 return data_[size()-1];
302 }
303
305 constexpr reference at (size_type i) const
306 {
307 if (i >= size())
308 throw std::out_of_range("Index " + std::to_string(i) + " out of range.");
309 return data_[i];
310 }
311
313 constexpr reference operator[] (size_type i) const { return data_[i]; }
314
316 constexpr pointer data () const noexcept { return data_; }
317
319
320
323
325 template <std::size_t Count>
327 {
328 static_assert(Count <= Extent);
329 assert(Count <= size());
330 return span<element_type, Count>{data(), Count};
331 }
332
334 template <std::size_t Count>
336 {
337 static_assert(Count <= Extent);
338 assert(Count <= size());
339 return span<element_type, Count>{data()+ (size() - Count), Count};
340 }
341
342private:
343
344 static constexpr std::size_t subspan_extent (std::size_t O, std::size_t C) noexcept
345 {
346 return (C != Std::dynamic_extent) ? C :
347 (Extent != Std::dynamic_extent) ? Extent - O : Std::dynamic_extent;
348 }
349
350public:
351
353
357 template <std::size_t Offset, std::size_t Count = Std::dynamic_extent>
358 constexpr span<element_type, subspan_extent(Offset,Count)> subspan () const
359 {
360 static_assert(Offset <= Extent && (Count == Std::dynamic_extent || Count <= Extent - Offset));
361 assert(Offset <= size() && (Count == Std::dynamic_extent || Count <= size() - Offset));
362 return span<element_type, subspan_extent(Offset,Count)>{
363 data() + Offset, Count != Std::dynamic_extent ? Count : size() - Offset};
364 }
365
367 constexpr span<element_type, Std::dynamic_extent> first (size_type count) const
368 {
369 assert(count <= size());
371 }
372
374 constexpr span<element_type, Std::dynamic_extent> last (size_type count) const
375 {
376 assert(count <= size());
377 return span<element_type, Std::dynamic_extent>{data()+ (size() - count), count};
378 }
379
381
385 constexpr span<element_type, Std::dynamic_extent> subspan (size_type offset, size_type count = Std::dynamic_extent) const
386 {
387 assert(offset <= size() && (count == Std::dynamic_extent || count <= size() - offset));
389 data() + offset, count == Std::dynamic_extent ? size() - offset : count};
390 }
391
393
394
397
399 using base_type::size;
400
402 constexpr size_type size_bytes () const noexcept { return size() * sizeof(element_type); }
403
405 [[nodiscard]] constexpr bool empty () const noexcept { return size() == 0; }
406
408
409private:
410 pointer data_;
411};
412
413// deduction guide
414// @{
415
416template <class T, std::size_t N>
417span (T (&)[N])
418 -> span<T, N>;
419
420template <class ElementType, class I, std::size_t Extent,
421 std::enable_if_t<std::is_convertible_v<I,std::size_t>, int> = 0>
422span (ElementType*, std::integral_constant<I,Extent>)
423 -> span<ElementType, Extent>;
424
425template <class ElementType, class I,
426 std::enable_if_t<std::is_integral_v<I>, int> = 0,
427 std::enable_if_t<std::is_convertible_v<I,std::size_t>, int> = 0>
428span (ElementType*, I)
429 -> span<ElementType, Std::dynamic_extent>;
430
431template <class Iter,
432 class Element = std::remove_reference_t<decltype(*std::declval<Iter>())>>
433span (Iter,Iter)
434 -> span<Element, Std::dynamic_extent>;
435
436template <class Range,
437 class First = decltype(std::begin(std::declval<Range>())),
438 class Last = decltype(std::end(std::declval<Range>())),
439 class Element = std::remove_reference_t<decltype(*std::declval<First>())>>
440span (Range&)
441 -> span<Element, Std::dynamic_extent>;
442
443template <class T, size_t N>
444span (std::array<T, N>&) -> span<T, N>;
445
446template <class T, size_t N>
447span (const std::array<T, N>&) -> span<const T, N>;
448
449// @}
450
451} // end namespace Dune::Std
452
453#endif // DUNE_COMMON_STD_SPAN_HH
A contiguous sequence of elements with static or dynamic extent.
Definition: span.hh:126
constexpr reference front() const
Access the first element.
Definition: span.hh:291
constexpr span(const span &other) noexcept=default
Copy constructor.
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:261
constexpr const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:267
constexpr span(std::array< T, N > &arr) noexcept
Constructs a span that is a view over the array.
Definition: span.hh:211
constexpr iterator end() const noexcept
Returns an iterator to the end.
Definition: span.hh:264
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:385
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:305
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:367
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:358
constexpr const_reverse_iterator crend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:282
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:276
constexpr pointer data() const noexcept
Direct access to the underlying contiguous storage.
Definition: span.hh:316
constexpr size_type size_bytes() const noexcept
Returns the size of the sequence in bytes.
Definition: span.hh:402
constexpr const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:279
constexpr bool empty() const noexcept
Checks if the sequence is empty.
Definition: span.hh:405
constexpr span< element_type, Count > last() const
Obtains a subspan consisting of the last Count elements of the sequence.
Definition: span.hh:335
constexpr span(Range &range)
Constructs a span that is a view over the range [range.begin(), range.end())
Definition: span.hh:195
constexpr reverse_iterator rbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:273
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:374
constexpr const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: span.hh:270
constexpr span< element_type, Count > first() const
Obtains a subspan consisting of the first Count elements of the sequence.
Definition: span.hh:326
constexpr reference back() const
Access the last element.
Definition: span.hh:298
constexpr span(const std::array< T, N > &arr) noexcept
Constructs a span that is a view over the const array.
Definition: span.hh:220
constexpr reference operator[](size_type i) const
Access specified element.
Definition: span.hh:313
A few common exception classes.
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
Namespace for features backported from new C++ standards.
Definition: default_accessor.hh:10
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:26
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  |  generated with Hugo v0.111.3 (Dec 21, 23:30, 2024)