dune-common  2.11
span.hh
Go to the documentation of this file.
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 
25 
26 namespace Dune::Std {
27 
29 inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
30 
31 #if __cpp_lib_span >= 202002L
32 
33 using std::span;
34 
35 #else
36 
37 namespace Impl {
38 
39 template <std::size_t Extent>
40 class SpanSize
41 {
42 public:
43  using size_type = std::size_t;
44 
45 public:
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 
62 template <>
63 class SpanSize<Std::dynamic_extent>
64 {
65 public:
66  using size_type = std::size_t;
67 
68 public:
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 
80 private:
81  size_type size_;
82 };
83 
84 template <class T>
85 struct TypeIdentity { using type = T; };
86 
87 template <class T>
88 using TypeIdentity_t = typename TypeIdentity<T>::type;
89 
90 } // end namespace Impl
91 
92 
132 template <class Element, std::size_t Extent = Std::dynamic_extent>
133 class 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 
140 public:
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;
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 
161 public:
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>
335  constexpr span<element_type, Count> first () const
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>
344  constexpr span<element_type, Count> last () const
345  {
346  static_assert(Count <= Extent);
347  assert(Count <= size());
348  return span<element_type, Count>{data()+ (size() - Count), Count};
349  }
350 
351 private:
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 
359 public:
360 
362 
366  template <std::size_t Offset, std::size_t Count = Std::dynamic_extent>
368  {
369  static_assert(Offset <= Extent && (Count == Std::dynamic_extent || Count <= Extent - Offset));
370  assert(Offset <= size() && (Count == Std::dynamic_extent || Count <= size() - Offset));
372  data() + Offset, Count != Std::dynamic_extent ? Count : size() - Offset};
373  }
374 
377  {
378  assert(count <= size());
380  }
381 
384  {
385  assert(count <= size());
386  return span<element_type, Std::dynamic_extent>{data()+ (size() - count), count};
387  }
388 
390 
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 
418 private:
419  pointer data_;
420 };
421 
422 // deduction guide
423 // @{
424 
425 template <class T, std::size_t N>
426 span (T (&)[N])
427  -> span<T, N>;
428 
429 template <class ElementType, class I, std::size_t Extent,
430  std::enable_if_t<std::is_convertible_v<I,std::size_t>, int> = 0>
431 span (ElementType*, std::integral_constant<I,Extent>)
432  -> span<ElementType, Extent>;
433 
434 template <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>
437 span (ElementType*, I)
438  -> span<ElementType, Std::dynamic_extent>;
439 
440 template <class Iter,
441  class Element = std::remove_reference_t<decltype(*std::declval<Iter>())>>
442 span (Iter,Iter)
443  -> span<Element, Std::dynamic_extent>;
444 
445 template <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>())>>
449 span (Range&)
450  -> span<Element, Std::dynamic_extent>;
451 
452 template <class T, size_t N>
453 span (std::array<T, N>&) -> span<T, N>;
454 
455 template <class T, size_t N>
456 span (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
constexpr const_reverse_iterator crbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:288
constexpr span< element_type, Count > first() const
Obtains a subspan consisting of the first Count elements of the sequence.
Definition: span.hh:335
constexpr span() noexcept
Default construct an empty span.
Definition: span.hh:168
Namespace for features backported from new C++ standards.
Definition: algorithm.hh:19
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
pointer iterator
Definition: span.hh:148
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 reverse_iterator rbegin() const noexcept
Returns a reverse iterator starting at the end.
Definition: span.hh:282
constexpr size_type size_bytes() const noexcept
Returns the size of the sequence in bytes.
Definition: span.hh:411
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: span.hh:155
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
constexpr reference front() const
Access the first element.
Definition: span.hh:300
constexpr span(std::array< T, N > &arr) noexcept
Constructs a span that is a view over the array.
Definition: span.hh:220
constexpr reverse_iterator rend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:285
constexpr const_reverse_iterator crend() const noexcept
Returns a reverse iterator ending at the beginning.
Definition: span.hh:291
span(const std::array< T, N > &) -> span< const T, N >
I i
Definition: hybridmultiindex.hh:328
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
element_type & reference
Definition: span.hh:146
constexpr span(const std::array< T, N > &arr) noexcept
Constructs a span that is a view over the const array.
Definition: span.hh:229
A contiguous sequence of elements with static or dynamic extent.
Definition: span.hh:133
constexpr pointer data() const noexcept
Direct access to the underlying contiguous storage.
Definition: span.hh:325
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
constexpr span(Impl::TypeIdentity_t< element_type >(&data)[N]) noexcept
Constructs a span that is a view over the C-array.
Definition: span.hh:211
constexpr const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: span.hh:279
const iterator const_iterator
Definition: span.hh:154
constexpr span & operator=(const span &other) noexcept=default
Copy assignment operator.
constexpr reference back() const
Access the last element.
Definition: span.hh:307
std::reverse_iterator< iterator > reverse_iterator
Definition: span.hh:149
element_type * pointer
Definition: span.hh:145
std::size_t size_type
Definition: span.hh:143
std::remove_cv_t< element_type > value_type
Definition: span.hh:142
Element element_type
Definition: span.hh:141
constexpr bool empty() const noexcept
Checks if the sequence is empty.
Definition: span.hh:414
constexpr reference at(size_type i) const
Access specified element with bounds checking.
Definition: span.hh:314
A few common exception classes.
constexpr span< element_type, Count > last() const
Obtains a subspan consisting of the last Count elements of the sequence.
Definition: span.hh:344
constexpr reference operator[](size_type i) const
Access specified element.
Definition: span.hh:322
constexpr span(Range &range)
Constructs a span that is a view over the range [range.begin(), range.end())
Definition: span.hh:204
STL namespace.
std::ptrdiff_t difference_type
Definition: span.hh:144
constexpr const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:276
static constexpr size_type extent
Definition: span.hh:159
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
span(T(&)[N]) -> span< T, N >
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 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 iterator end() const noexcept
Returns an iterator to the end.
Definition: span.hh:273
const element_type & const_reference
Definition: span.hh:147
constexpr iterator begin() const noexcept
Returns an iterator to the beginning.
Definition: span.hh:270